diff --git a/src/Form/Service/ParticipantTransportationDiscountReplacementFieldHandler.php b/src/Form/Service/ParticipantTransportationDiscountReplacementFieldHandler.php index b9fc1e9..049b82b 100644 --- a/src/Form/Service/ParticipantTransportationDiscountReplacementFieldHandler.php +++ b/src/Form/Service/ParticipantTransportationDiscountReplacementFieldHandler.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Form\Service; +use App\BusProNet\Constants; use App\BusProNet\Utility\DirectionMapper; use App\Form\Model\BookingDto; use App\Form\Service\Abstract\AbstractParticipantFieldHandler; @@ -119,6 +120,12 @@ class ParticipantTransportationDiscountReplacementFieldHandler extends AbstractP // 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 diff --git a/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php b/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php index 7139718..064ba46 100644 --- a/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php @@ -312,6 +312,117 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->expectNotToPerformAssertions(); } + public function testProcessFieldSkipsDiscountRestorationForBabyParticipant(): void + { + // Setup services + $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); + $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); + $pkwInbound = $this->createPkwService(201, 'Selbstorganisiert', 0.0, DirectionMapper::INBOUND_TRAVEL); + + // Setup baby participant (age 1) with regular PKW outbound and PKW inbound + $participant = new ParticipantDto(); + $participant->dateOfBirth = new \DateTimeImmutable('-1 year'); + $participant->transportationOutbound = $regularPkw; + $participant->transportationInbound = $pkwInbound; + + // Setup booking with travel services - travel starts today + $travel = $this->createTravelWithServices([$discountedPkw, $regularPkw, $pkwInbound]); + $travel->dateFrom = new \DateTimeImmutable('today'); + $bookingDto = new BookingDto($travel, 1); + $bookingDto->participants = [$participant]; + + // Availability calculator should NOT be called for babies + $this->serviceAvailabilityCalculator + ->expects($this->never()) + ->method('isServiceUnavailable'); + + $submittedData = []; + + // Process + $this->handler->processField($submittedData, $bookingDto, 0); + + // Assert outbound remains regular PKW (no discount restoration for babies) + $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); + + // Assert no notification was generated + $this->assertEmpty($participant->notifications); + } + + public function testProcessFieldSkipsDiscountRestorationForTwoYearOldParticipant(): void + { + // Setup services + $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); + $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); + $pkwInbound = $this->createPkwService(201, 'Selbstorganisiert', 0.0, DirectionMapper::INBOUND_TRAVEL); + + // Setup participant at BABY_MAX_AGE (2 years) with regular PKW + $participant = new ParticipantDto(); + $participant->dateOfBirth = new \DateTimeImmutable('-2 years'); + $participant->transportationOutbound = $regularPkw; + $participant->transportationInbound = $pkwInbound; + + // Setup booking with travel services - travel starts today + $travel = $this->createTravelWithServices([$discountedPkw, $regularPkw, $pkwInbound]); + $travel->dateFrom = new \DateTimeImmutable('today'); + $bookingDto = new BookingDto($travel, 1); + $bookingDto->participants = [$participant]; + + // Availability calculator should NOT be called for babies + $this->serviceAvailabilityCalculator + ->expects($this->never()) + ->method('isServiceUnavailable'); + + $submittedData = []; + + // Process + $this->handler->processField($submittedData, $bookingDto, 0); + + // Assert outbound remains regular PKW + $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); + + // Assert no notification was generated + $this->assertEmpty($participant->notifications); + } + + public function testProcessFieldRestoresDiscountForThreeYearOldParticipant(): void + { + // Setup services + $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); + $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); + $pkwInbound = $this->createPkwService(201, 'Selbstorganisiert', 0.0, DirectionMapper::INBOUND_TRAVEL); + + // Setup participant clearly above BABY_MAX_AGE (3+ years) with regular PKW + // Use specific dates to ensure age calculation is unambiguous + $participant = new ParticipantDto(); + $participant->dateOfBirth = new \DateTimeImmutable('2020-01-01'); + $participant->transportationOutbound = $regularPkw; + $participant->transportationInbound = $pkwInbound; + + // Setup booking with travel services - travel starts well after 3rd birthday + $travel = $this->createTravelWithServices([$discountedPkw, $regularPkw, $pkwInbound]); + $travel->dateFrom = new \DateTimeImmutable('2024-06-01'); + $bookingDto = new BookingDto($travel, 1); + $bookingDto->participants = [$participant]; + + // Mock availability: discounted PKW is available + $this->serviceAvailabilityCalculator + ->expects($this->once()) + ->method('isServiceUnavailable') + ->with($discountedPkw->id, $bookingDto, 0) + ->willReturn(false); + + $submittedData = []; + + // Process + $this->handler->processField($submittedData, $bookingDto, 0); + + // Assert outbound was replaced with discounted PKW (3-year-old is eligible) + $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); + + // Assert notification was generated + $this->assertCount(1, $participant->notifications); + } + private function createPkwService(int $id, string $label, float $price, string $direction = DirectionMapper::OUTBOUND_TRAVEL): Service { $service = new Service();