Reverts split pricing calculation to use outbound-only pricing, matching BusPro's current behavior where pickup is only charged when outbound transportation is BUS. - Use pickup->price directly instead of calculateEffectivePrice() - PKW+BUS scenario now correctly charges €0 (matches BusPro loophole) - priceOutbound/priceInbound remain populated for future activation - Updated documentation with current behavior and future plan
5.1 KiB
Pickup Pricing - Implementation Documentation
Current BusPro Behavior (January 2026)
BusPro currently only charges pickup price when the outbound transportation is BUS, regardless of the inbound selection.
Pricing Matrix (Current)
| Outbound | Inbound | BusPro Charges | Notes |
|---|---|---|---|
| BUS | BUS | Pickup price once | Full price from outbound |
| BUS | PKW | Pickup price once | Full price from outbound |
| PKW | BUS | €0 | Known loophole in BusPro |
| PKW | PKW | €0 | No pickup available |
The "loophole" (PKW outbound + BUS inbound = no charge) exists on BusPro's side. Our portal must match this behavior to avoid price validation errors when submitting bookings.
XML Data Structure
Both travel sections contain pickup data with prices:
<!-- Outbound pickups -->
<zustiege>
<zustieg id="3" idbuspro="4" preis="5,90" .../>
</zustiege>
<!-- Inbound pickups -->
<zustiege_rueck>
<zustieg_rueck id="3" idbuspro="4" preis="5,90" .../>
</zustiege_rueck>
Currently, prices are duplicated in both sections. In the future, when BusPro supports split pricing, travels may be configured with different prices per direction (e.g., 2.95 each way instead of 5.90 outbound only).
Portal Implementation
Forward-Compatible Data Layer
The portal parses and stores both direction prices for future use:
-
Pickup Model (
src/BusProNet/Model/Pickup.php):price: The outbound price (used for pricing calculations)priceOutbound: Explicit outbound price (populated but not used yet)priceInbound: Explicit inbound price (populated but not used yet)calculateEffectivePrice(): Ready for future split pricing activation
-
TravelParser (
src/BusProNet/XmlParser/TravelParser.php):- Parses
zustiegesection and setspriceOutbound - Parses
zustiege_ruecksection and setspriceInbound - Merges inbound prices into outbound pickup objects by ID
- Parses
-
BookingDataProcessor (
src/BusProNet/DataProcessor/BookingDataProcessor.php):- Enriches participant pickups with all price properties from travel data
Current Pricing Logic
The pricing calculators use simple outbound-only logic to match BusPro:
// Only charge if outbound is BUS - matches current BusPro behavior
$hasOutboundBus = null !== $participant->transportationOutbound
&& 'BUS' === $participant->transportationOutbound->subType;
if ($hasOutboundBus && null !== $participant->pickup && null !== $participant->pickup->price) {
$serviceTotal += $participant->pickup->price;
}
This ensures portal prices always match BusPro responses, avoiding validation errors.
API Constraints
- Pickups can only be submitted via the
zustiege(outbound) XML section - There is no
zustiege_rueck(inbound) equivalent for submission - Booking responses return pickups in the outbound section only
- A future API update will support separate pickup/drop-off locations
Future Activation (When BusPro Supports Split Pricing)
When BusPro is updated to charge based on actual transportation selections, update the pricing calculators to use calculateEffectivePrice():
$hasOutboundBus = null !== $participant->transportationOutbound
&& 'BUS' === $participant->transportationOutbound->subType;
$hasInboundBus = null !== $participant->transportationInbound
&& 'BUS' === $participant->transportationInbound->subType;
if (null !== $participant->pickup) {
$pickupPrice = $participant->pickup->calculateEffectivePrice($hasOutboundBus, $hasInboundBus);
if (null !== $pickupPrice) {
$serviceTotal += $pickupPrice;
}
}
Important Caveat for Split Pricing Configuration
If travels are configured with split pricing (e.g., outbound=2.95, inbound=2.95) before BusPro supports it:
| Scenario | Portal Charges | BusPro Charges | Intended |
|---|---|---|---|
| BUS+BUS | 2.95 | 2.95 | 5.90 |
| BUS+PKW | 2.95 | 2.95 | 2.95 |
| PKW+BUS | 0.00 | 0.00 | 2.95 |
Recommendation: Keep full price on outbound (preis="5,90") until BusPro supports split pricing, then reconfigure to true split values.
Related Code Locations
src/BusProNet/Model/Pickup.php- Pickup model with split pricing properties and calculation methodssrc/BusProNet/XmlParser/TravelParser.php- Parses and merges pickup prices from XMLsrc/BusProNet/DataProcessor/BookingDataProcessor.php- Enriches pickups with travel datasrc/BusProNet/DataProcessor/BookingPayloadBuilder.php- Pickup submissionsrc/BusProNet/Model/Booking.php-getPickupForParticipant()methodsrc/Form/Service/EditFieldStateProvider.php- Pickup field visibilitysrc/Form/Service/CreateFieldStateProvider.php- Pickup field visibilitysrc/Service/ParticipantPricingCalculator.php- Pickup pricing logic (individual)src/Service/ServicePricingCalculator.php- Pickup pricing aggregation (summary)
Test Scenarios
- BUS + BUS: Charges
pickup->price(outbound) - BUS + PKW: Charges
pickup->price(outbound) - PKW + BUS: Charges €0 (matches BusPro loophole)
- PKW + PKW: No pickup available
Last updated: 2026-01-21