getParticipant($participantIndex); if (null === $participant) { return; } // Need both transportation fields to process if (null === $participant->transportationOutbound) { return; } // Step 2: Detect inbound transportation type $inboundIsBus = null !== $participant->transportationInbound && DirectionMapper::SUBTYPE_BUS_API === $participant->transportationInbound->subType; // Step 3: Get all outbound PKW services $allOutboundServices = $bookingDto->travel->getTransportationServicesByDirection( DirectionMapper::OUTBOUND_TRAVEL ); // Find discounted and regular PKW services $discountedPkw = null; $regularPkw = null; foreach ($allOutboundServices as $service) { if (false === DirectionMapper::isCar($service->subType)) { continue; // Skip non-PKW services } if (null !== $service->price && $service->price < 0) { $discountedPkw = $service; } elseif (null === $service->price || $service->price >= 0) { $regularPkw = $service; } } // Edge case: no regular PKW found (impossible in production, but handle gracefully) if (null === $regularPkw) { return; } // Step 4a: Handle inbound BUS scenario (force regular PKW) if (true === $inboundIsBus) { // Check if outbound is currently DISCOUNTED PKW $outboundIsDiscountedPkw = DirectionMapper::isCar($participant->transportationOutbound->subType) && null !== $participant->transportationOutbound->price && $participant->transportationOutbound->price < 0; if ($outboundIsDiscountedPkw) { // Store original for notification $originalLabel = $participant->transportationOutbound->label; // Replace with regular PKW $participant->transportationOutbound = $regularPkw; // Notify user about replacement $participant->addNotification( 'warning', sprintf( 'Hinfahrt automatisch angepasst: Rabattierte Anreise nicht möglich bei Busrückfahrt. Geändert von "%s" zu "%s".', $originalLabel, $regularPkw->label ) ); $this->syncBookingTransportationService($bookingDto, $participantIndex, $discountedPkw, $regularPkw); } return; // Done processing for BUS inbound scenario } // Step 4b: Handle non-BUS inbound scenario (restore discount if available) // Inbound is NOT BUS - try to restore discounted PKW if available // Baby participants never get discounted transportation $age = $participant->getAge($bookingDto->travel->dateFrom); if (null !== $age && $age <= Constants::BABY_MAX_AGE) { return; } // Check if outbound is currently REGULAR PKW $outboundIsRegularPkw = DirectionMapper::isCar($participant->transportationOutbound->subType) && (null === $participant->transportationOutbound->price || $participant->transportationOutbound->price >= 0); if (false === $outboundIsRegularPkw || null === $discountedPkw) { return; // Not eligible for discount restoration } // Check per-booking availability of discounted PKW $discountedIsAvailable = false === $this->serviceAvailabilityCalculator->isServiceUnavailable( $discountedPkw->id, $bookingDto, $participantIndex ); if ($discountedIsAvailable) { // Store original for notification $originalLabel = $participant->transportationOutbound->label; // Restore discounted PKW $participant->transportationOutbound = $discountedPkw; // Notify user about restoration $participant->addNotification( 'success', sprintf( 'Hinfahrt automatisch angepasst: Rabattierte Anreise wieder verfügbar. Geändert von "%s" zu "%s".', $originalLabel, $discountedPkw->label ) ); $this->syncBookingTransportationService($bookingDto, $participantIndex, $regularPkw, $discountedPkw); } } /** * Keeps $bookingDto->booking->transportationServices consistent with a participant's * updated outbound transportation selection. Only runs in edit mode. * * Clones the new service before inserting it to avoid mutating the shared travel-data * object when resetServiceMappings() clears mappings at submit time. */ private function syncBookingTransportationService( BookingDto $bookingDto, int $participantIndex, Service $oldService, Service $newService, ): void { if (null === $bookingDto->booking) { return; } $services = &$bookingDto->booking->transportationServices; if (isset($services[$oldService->id])) { $services[$oldService->id]->mapping = array_values( array_filter( $services[$oldService->id]->mapping, fn (int $idx): bool => $idx !== $participantIndex, ) ); } if (false === isset($services[$newService->id])) { $services[$newService->id] = clone $newService; $services[$newService->id]->mapping = []; } if (false === in_array($participantIndex, $services[$newService->id]->mapping, true)) { $services[$newService->id]->mapping[] = $participantIndex; } } }