feat: indicate family insurance eligibility

This commit is contained in:
Björn Fromme
2026-08-05 15:11:58 +02:00
parent 0b642dcfe4
commit 2cfa87f44b
12 changed files with 327 additions and 234 deletions
@@ -10,6 +10,7 @@ use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Form\Service\ParticipantInsuranceFieldHandler;
use App\Service\BookingPriceCalculator;
use App\Service\FamilyInsuranceAvailabilityChecker;
use App\Service\InsuranceManager;
use PHPUnit\Framework\TestCase;
@@ -34,7 +35,13 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase
$this->priceCalculatorService->method('resolveInsuranceTravelPrice')
->willReturn(500.0);
$this->handler = new ParticipantInsuranceFieldHandler($this->insuranceService, $this->priceCalculatorService);
// Real checker over the mocked collaborators - the selection-time recording below is
// only meaningful against the actual "is a family insurance available" definition
$this->handler = new ParticipantInsuranceFieldHandler(
$this->insuranceService,
$this->priceCalculatorService,
new FamilyInsuranceAvailabilityChecker($this->insuranceService, $this->priceCalculatorService),
);
}
public function testGetFieldName(): void
@@ -279,21 +286,6 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase
$this->assertNull($participant->insurance);
}
public function testProcessFieldNotifiesApplicantWhenFamilyInsuranceNewlyAvailable(): void
{
$bookingDto = $this->createFamilyBookingDtoWithNonFamilyApplicantInsurance();
$applicant = $bookingDto->getParticipant(0);
$this->priceCalculatorService->method('calculateTotalBookingPriceExcludingInsurance')->willReturn(500.0);
$this->insuranceService->method('getEligibleInsurances')->willReturn([$this->createInsurance('2', 'Reise-Rücktritt Familie')]);
// Dependent's own card is submitted (e.g. just their date of birth) - no insurance selection
$this->handler->processField([], $bookingDto, 1);
$this->assertNotEmpty($applicant->notifications, 'Applicant should be notified that family insurance is now available');
$this->assertTrue($bookingDto->familyInsuranceHintShown);
}
public function testProcessFieldRecordsIneligibilityWhenApplicantSelectsInsuranceBeforeFamilyEligible(): void
{
$nonFamilyInsurance = $this->createInsurance('1');
@@ -405,124 +397,6 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase
);
}
public function testProcessFieldDoesNotNotifyWhenApplicantSwitchesToFamilyInsuranceInSameSubmission(): void
{
$familyInsurance = $this->createInsurance('2');
$familyInsurance->familyInsurance = true;
$nonFamilyInsurance = $this->createInsurance('1');
$nonFamilyInsurance->familyInsurance = false;
$travel = new Travel();
$travel->dateFrom = new \DateTimeImmutable('2025-08-01');
$travel->dateTo = new \DateTimeImmutable('2025-08-08');
$travel->insurances = [$nonFamilyInsurance, $familyInsurance];
$applicant = new ParticipantDto();
$applicant->index = 0;
$applicant->dateOfBirth = new \DateTimeImmutable('1990-06-15');
$applicant->insurance = $nonFamilyInsurance;
$child = new ParticipantDto();
$child->index = 1;
$child->dateOfBirth = new \DateTimeImmutable('2015-01-01');
$bookingDto = new BookingDto($travel, 1);
$bookingDto->participants = [$applicant, $child];
$bookingDto->applicantInsuranceChosenWhileFamilyIneligible = true;
$this->insuranceService->method('getEligibleInsurances')->willReturn([$familyInsurance]);
// Applicant's own submission switches them to family insurance in this same request
$this->handler->processField(['insurance' => '2'], $bookingDto, 0);
$this->assertSame($familyInsurance, $applicant->insurance);
$this->assertEmpty($applicant->notifications, 'Must not show a stale "please recheck" hint for a choice this submission already made');
}
public function testProcessFieldDoesNotNotifyWhenHintAlreadyShown(): void
{
$bookingDto = $this->createFamilyBookingDtoWithNonFamilyApplicantInsurance();
$bookingDto->familyInsuranceHintShown = true;
$applicant = $bookingDto->getParticipant(0);
$this->priceCalculatorService->method('calculateTotalBookingPriceExcludingInsurance')->willReturn(500.0);
$this->insuranceService->method('getEligibleInsurances')->willReturn([$this->createInsurance('2')]);
$this->handler->processField([], $bookingDto, 1);
$this->assertEmpty($applicant->notifications, 'Hint must not repeat once already shown');
}
public function testProcessFieldDoesNotNotifyWhenApplicantHasNoInsurance(): void
{
$bookingDto = $this->createFamilyBookingDtoWithNonFamilyApplicantInsurance();
$applicant = $bookingDto->getParticipant(0);
$applicant->insurance = null;
$this->handler->processField([], $bookingDto, 1);
$this->assertEmpty($applicant->notifications, 'Nothing to alert about when applicant has not chosen insurance yet');
$this->assertFalse($bookingDto->familyInsuranceHintShown);
}
public function testProcessFieldDoesNotNotifyWhenApplicantAlreadyHasFamilyInsurance(): void
{
$bookingDto = $this->createFamilyBookingDtoWithNonFamilyApplicantInsurance();
$applicant = $bookingDto->getParticipant(0);
$familyInsurance = $this->createInsurance('2');
$familyInsurance->familyInsurance = true;
$applicant->insurance = $familyInsurance;
$this->handler->processField([], $bookingDto, 1);
$this->assertEmpty($applicant->notifications, 'Nothing to alert about when applicant already has family insurance');
$this->assertFalse($bookingDto->familyInsuranceHintShown);
}
public function testProcessFieldDoesNotNotifyWhenNoEligibleFamilyInsuranceExists(): void
{
$bookingDto = $this->createFamilyBookingDtoWithNonFamilyApplicantInsurance();
$applicant = $bookingDto->getParticipant(0);
$this->priceCalculatorService->method('calculateTotalBookingPriceExcludingInsurance')->willReturn(500.0);
$this->insuranceService->method('getEligibleInsurances')->willReturn([]); // No eligible family insurance
$this->handler->processField([], $bookingDto, 1);
$this->assertEmpty($applicant->notifications, 'Nothing to alert about when no family insurance is actually eligible');
$this->assertFalse($bookingDto->familyInsuranceHintShown);
}
private function createFamilyBookingDtoWithNonFamilyApplicantInsurance(): BookingDto
{
$nonFamilyInsurance = $this->createInsurance('1');
$nonFamilyInsurance->familyInsurance = false;
$familyInsurance = $this->createInsurance('2');
$familyInsurance->familyInsurance = true;
$travel = new Travel();
$travel->dateFrom = new \DateTimeImmutable('2025-08-01');
$travel->dateTo = new \DateTimeImmutable('2025-08-08');
$travel->insurances = [$nonFamilyInsurance, $familyInsurance];
$applicant = new ParticipantDto();
$applicant->index = 0;
$applicant->dateOfBirth = new \DateTimeImmutable('1990-06-15');
$applicant->insurance = $nonFamilyInsurance;
$child = new ParticipantDto();
$child->index = 1;
$child->dateOfBirth = new \DateTimeImmutable('2015-01-01');
$bookingDto = new BookingDto($travel, 1);
$bookingDto->participants = [$applicant, $child];
$bookingDto->applicantInsuranceChosenWhileFamilyIneligible = true;
return $bookingDto;
}
public function testGetFieldStateModificationsReturnsEmptyArray(): void
{
$bookingDto = $this->createMockBookingDto();