fix: always adopt outbound pickup price for inbound when set
This commit is contained in:
1 parent
29f295abf6
commit
0c6126010f
5 files changed
+203
-20
No files matched your search
@@ -87,8 +87,8 @@ class TravelParser extends AbstractParser
|
||||
$travel->pickups = $this->getPickups($node->filterXPath('.//zustiege/zustieg'), $dateFrom, true);
|
||||
$travel->dropOffs = $this->getPickups($node->filterXPath('.//zustiege_rueck/zustieg_rueck'), $dateTo, false);
|
||||
|
||||
// Merge drop-off prices into pickups for split pricing support
|
||||
$this->mergeDropOffPricesIntoPickups($travel->pickups, $travel->dropOffs);
|
||||
// A boarding point costs the same in both directions
|
||||
$this->levelBoardingPointPrices($travel->pickups, $travel->dropOffs);
|
||||
|
||||
$travel->guide = $this->getGuide($node);
|
||||
|
||||
@@ -453,22 +453,38 @@ class TravelParser extends AbstractParser
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges drop-off prices into pickups for split pricing support.
|
||||
* Levels the price of a boarding point across both travel directions.
|
||||
*
|
||||
* For each pickup, finds the matching drop-off by ID and copies
|
||||
* the inbound price to the pickup's priceInbound property. This enables
|
||||
* split pricing calculations where costs are distributed between outbound
|
||||
* and inbound transportation.
|
||||
* A boarding point is either free or costs the same in both directions:
|
||||
* `ZustiegPreis` is keyed by (point, tariff scheme) and holds no per-leg price, so
|
||||
* BusPro bills an `Abfahrtsortzuschlag` per leg at one and the same rate. An
|
||||
* asymmetric pair is therefore always an export defect — on some products a
|
||||
* `<zustieg_rueck>` carries no `preis` although the engine still charges the return
|
||||
* leg — and the stated price is the one that applies to both legs.
|
||||
*
|
||||
* Where both directions state a price they agree in practice; the outbound one wins
|
||||
* to keep the outcome deterministic. Points without a counterpart are left as they are.
|
||||
*
|
||||
* @param array<int, Pickup> $pickups Pickups indexed by ID (modified in place)
|
||||
* @param array<int, Pickup> $dropOffs Drop-offs indexed by ID
|
||||
* @param array<int, Pickup> $dropOffs Drop-offs indexed by ID (modified in place)
|
||||
*/
|
||||
private function mergeDropOffPricesIntoPickups(array &$pickups, array $dropOffs): void
|
||||
private function levelBoardingPointPrices(array &$pickups, array $dropOffs): void
|
||||
{
|
||||
foreach ($pickups as $pickupId => $pickup) {
|
||||
if (isset($dropOffs[$pickupId])) {
|
||||
$pickup->priceInbound = $dropOffs[$pickupId]->priceInbound;
|
||||
foreach ($dropOffs as $pickupId => $dropOff) {
|
||||
if (false === isset($pickups[$pickupId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pickup = $pickups[$pickupId];
|
||||
$price = $pickup->price ?? $dropOff->price;
|
||||
|
||||
$pickup->price = $price;
|
||||
$pickup->priceOutbound = $price;
|
||||
$pickup->priceInbound = $price;
|
||||
|
||||
$dropOff->price = $price;
|
||||
$dropOff->priceOutbound = $price;
|
||||
$dropOff->priceInbound = $price;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\BusProNet\Constants;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\Insurance;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\BusProNet\Utility\DirectionMapper;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
|
||||
@@ -161,7 +162,9 @@ class BookingPricingAssembler
|
||||
}
|
||||
|
||||
$hasOutboundBus = null !== $participant->transportationOutbound
|
||||
&& 'BUS' === $participant->transportationOutbound->subType;
|
||||
&& DirectionMapper::isBus($participant->transportationOutbound->subType);
|
||||
$hasInboundBus = null !== $participant->transportationInbound
|
||||
&& DirectionMapper::isBus($participant->transportationInbound->subType);
|
||||
|
||||
if ($hasOutboundBus && null !== $participant->pickup && null !== $participant->pickup->price) {
|
||||
if ($participant->pickup->price < 0) {
|
||||
@@ -171,7 +174,7 @@ class BookingPricingAssembler
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $participant->dropOff && null !== $participant->dropOff->price) {
|
||||
if ($hasInboundBus && null !== $participant->dropOff && null !== $participant->dropOff->price) {
|
||||
if ($participant->dropOff->price < 0) {
|
||||
$participantTransportationDiscountCost += $participant->dropOff->price;
|
||||
} else {
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\BusProNet\Utility\DirectionMapper;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
|
||||
@@ -193,18 +194,17 @@ class ParticipantPricingCalculator
|
||||
}
|
||||
}
|
||||
|
||||
// Pickup pricing - only charged when outbound transportation is BUS
|
||||
// This matches current BusPro behavior where pickup price is only applied for outbound bus
|
||||
// Note: priceOutbound/priceInbound are populated for future split pricing support when BusPro is updated
|
||||
// Boarding surcharges are charged per leg, at the same rate in both directions
|
||||
$hasOutboundBus = null !== $participant->transportationOutbound
|
||||
&& 'BUS' === $participant->transportationOutbound->subType;
|
||||
&& DirectionMapper::isBus($participant->transportationOutbound->subType);
|
||||
$hasInboundBus = null !== $participant->transportationInbound
|
||||
&& DirectionMapper::isBus($participant->transportationInbound->subType);
|
||||
|
||||
if ($hasOutboundBus && null !== $participant->pickup && null !== $participant->pickup->price) {
|
||||
$serviceTotal += $participant->pickup->price;
|
||||
}
|
||||
|
||||
// Drop-off pricing (charged when inbound transportation is BUS and a drop-off is selected)
|
||||
if (null !== $participant->dropOff && null !== $participant->dropOff->price) {
|
||||
if ($hasInboundBus && null !== $participant->dropOff && null !== $participant->dropOff->price) {
|
||||
$serviceTotal += $participant->dropOff->price;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user