wip: hint eligibility of family insurance
addresses #869dr80qj
This commit is contained in:
1 parent
1fe6bcf5c9
commit
3177451a9c
3 files changed
+400
-1
No files matched your search
@@ -70,6 +70,21 @@ class BookingDto
|
|||||||
*/
|
*/
|
||||||
public ?string $originalFingerprint = null;
|
public ?string $originalFingerprint = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the applicant has already been notified that family insurance became
|
||||||
|
* available after they picked a non-family insurance while dependents were incomplete.
|
||||||
|
* Prevents re-showing the same hint on every subsequent participant card submission.
|
||||||
|
*/
|
||||||
|
public bool $familyInsuranceHintShown = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the applicant's current insurance choice was made while family insurance
|
||||||
|
* was not yet eligible (i.e. before all dependents' dates of birth were known).
|
||||||
|
* Set at selection time; used to distinguish "family insurance just became
|
||||||
|
* available" from "it was available all along and the applicant chose otherwise".
|
||||||
|
*/
|
||||||
|
public bool $applicantInsuranceChosenWhileFamilyIneligible = false;
|
||||||
|
|
||||||
public function __construct(public Travel $travel, public int $hotelId)
|
public function __construct(public Travel $travel, public int $hotelId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace App\Form\Service;
|
|||||||
|
|
||||||
use App\BusProNet\Model\Insurance;
|
use App\BusProNet\Model\Insurance;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
|
use App\Form\Model\ParticipantDto;
|
||||||
use App\Form\Service\Abstract\AbstractParticipantFieldHandler;
|
use App\Form\Service\Abstract\AbstractParticipantFieldHandler;
|
||||||
use App\Service\BookingPriceCalculator;
|
use App\Service\BookingPriceCalculator;
|
||||||
use App\Service\InsuranceManager;
|
use App\Service\InsuranceManager;
|
||||||
@@ -124,6 +125,19 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
* @param int $participantIndex The index of the participant being processed
|
* @param int $participantIndex The index of the participant being processed
|
||||||
*/
|
*/
|
||||||
public function processField(array $submittedData, BookingDto $bookingDto, int $participantIndex): void
|
public function processField(array $submittedData, BookingDto $bookingDto, int $participantIndex): void
|
||||||
|
{
|
||||||
|
$this->applyInsuranceSelection($submittedData, $bookingDto, $participantIndex);
|
||||||
|
|
||||||
|
// Runs after the selection above is fully resolved, so a submission that itself
|
||||||
|
// switches the applicant to family insurance doesn't trigger a stale "please
|
||||||
|
// recheck" notification about the choice it just made.
|
||||||
|
$this->notifyApplicantIfFamilyInsuranceNewlyAvailable($bookingDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
|
*/
|
||||||
|
private function applyInsuranceSelection(array $submittedData, BookingDto $bookingDto, int $participantIndex): void
|
||||||
{
|
{
|
||||||
$participant = $bookingDto->getParticipant($participantIndex);
|
$participant = $bookingDto->getParticipant($participantIndex);
|
||||||
if (null === $participant) {
|
if (null === $participant) {
|
||||||
@@ -152,6 +166,8 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
$noInsurance->price = 0.0;
|
$noInsurance->price = 0.0;
|
||||||
$participant->insurance = $noInsurance;
|
$participant->insurance = $noInsurance;
|
||||||
|
|
||||||
|
$this->recordFamilyIneligibilityAtSelectionTime($bookingDto, $participantIndex, $noInsurance);
|
||||||
|
|
||||||
return; // Skip all other processing for "no insurance"
|
return; // Skip all other processing for "no insurance"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,10 +204,15 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
// Insurance not found - clear selection
|
// Insurance not found - clear selection
|
||||||
$participant->insurance = null;
|
$participant->insurance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->recordFamilyIneligibilityAtSelectionTime($bookingDto, $participantIndex, $participant->insurance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle form resubmission with existing insurance (automatic reassignment check)
|
// Handle form resubmission with existing insurance (automatic reassignment check)
|
||||||
if (null !== $currentInsurance && null !== $selectedInsuranceId) {
|
// Only applies when the selection didn't just change above - otherwise this would
|
||||||
|
// re-validate the now-stale $currentInsurance and could overwrite the fresh selection
|
||||||
|
// the block above already made in this same request.
|
||||||
|
if (!$isNewSelection && null !== $currentInsurance && null !== $selectedInsuranceId) {
|
||||||
// Preserve "no insurance" selection during resubmission
|
// Preserve "no insurance" selection during resubmission
|
||||||
if ($currentInsurance->isNoInsurance()) {
|
if ($currentInsurance->isNoInsurance()) {
|
||||||
return;
|
return;
|
||||||
@@ -260,6 +281,95 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records whether the applicant's insurance choice was made while family insurance
|
||||||
|
* was NOT yet eligible, so the notification below can tell "just became available"
|
||||||
|
* apart from "was available all along and the applicant chose non-family anyway".
|
||||||
|
*
|
||||||
|
* Only called when the applicant (index 0) makes a genuine new selection - not on
|
||||||
|
* mere resubmission/price-tier reassignment of an already-standing choice.
|
||||||
|
*/
|
||||||
|
private function recordFamilyIneligibilityAtSelectionTime(BookingDto $bookingDto, int $participantIndex, ?Insurance $insurance): void
|
||||||
|
{
|
||||||
|
if (0 !== $participantIndex || null === $insurance || true === $insurance->familyInsurance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$applicant = $bookingDto->getParticipant(0);
|
||||||
|
if (null === $applicant) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bookingDto->applicantInsuranceChosenWhileFamilyIneligible = !$this->hasEligibleFamilyInsurance($bookingDto, $applicant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a family insurance is actually eligible right now - not just whether
|
||||||
|
* the participant composition qualifies as a family booking, but whether a selectable
|
||||||
|
* family insurance product actually matches the current total booking price.
|
||||||
|
*
|
||||||
|
* Used by both the selection-time recording above and the notification below, so they
|
||||||
|
* can never disagree on what "family insurance is eligible" means.
|
||||||
|
*/
|
||||||
|
private function hasEligibleFamilyInsurance(BookingDto $bookingDto, ParticipantDto $applicant): bool
|
||||||
|
{
|
||||||
|
if (!$bookingDto->isFamilyBooking()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$selectableInsurances = $this->insuranceService->getSelectableInsurances($bookingDto->travel);
|
||||||
|
$familyInsurances = array_values(array_filter($selectableInsurances, static fn (Insurance $i) => true === $i->familyInsurance));
|
||||||
|
|
||||||
|
if ([] === $familyInsurances) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalPrice = $this->priceCalculatorService->calculateTotalBookingPriceExcludingInsurance($bookingDto);
|
||||||
|
|
||||||
|
return [] !== $this->insuranceService->getEligibleInsurances($familyInsurances, $applicant, $bookingDto, $totalPrice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the applicant when family insurance becomes available after the fact.
|
||||||
|
*
|
||||||
|
* Participants are entered one card at a time, in any order, so the applicant is
|
||||||
|
* likely to pick a non-family insurance before any dependent's date of birth makes
|
||||||
|
* the booking eligible for family insurance. Once that happens, nothing prompts the
|
||||||
|
* applicant to revisit their earlier choice. This surfaces a one-time hint via the
|
||||||
|
* existing notification/toast pipeline (App\Form\Model\ParticipantDto::addNotification()),
|
||||||
|
* mirroring the cross-participant side effect already used by
|
||||||
|
* ParticipantAssignedRoomFieldHandler::resolveRoomCapacityConflict() for room conflicts.
|
||||||
|
*
|
||||||
|
* Requires `applicantInsuranceChosenWhileFamilyIneligible` to be true - i.e. the
|
||||||
|
* choice was actually made before family insurance was possible - not just that
|
||||||
|
* family insurance happens to be eligible now (it may have been all along).
|
||||||
|
*/
|
||||||
|
private function notifyApplicantIfFamilyInsuranceNewlyAvailable(BookingDto $bookingDto): void
|
||||||
|
{
|
||||||
|
if ($bookingDto->familyInsuranceHintShown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$bookingDto->applicantInsuranceChosenWhileFamilyIneligible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$applicant = $bookingDto->getParticipant(0);
|
||||||
|
if (null === $applicant || null === $applicant->insurance || true === $applicant->insurance->familyInsurance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->hasEligibleFamilyInsurance($bookingDto, $applicant)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$applicant->addNotification(
|
||||||
|
'info',
|
||||||
|
'Für eure Konstellation ist auch eine Familienversicherung verfügbar und kann über die anmeldende Person gebucht werden.'
|
||||||
|
);
|
||||||
|
$bookingDto->familyInsuranceHintShown = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds an insurance by ID from the available insurances array.
|
* Finds an insurance by ID from the available insurances array.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -198,6 +198,36 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase
|
|||||||
$this->assertNull($participant->insurance);
|
$this->assertNull($participant->insurance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldSwitchingToNewInsuranceIsNotOverwrittenByStaleResubmissionCheck(): void
|
||||||
|
{
|
||||||
|
// Regression: switching from one already-selected insurance to a different one must
|
||||||
|
// not be re-validated (and potentially overwritten) against the OLD, now-stale
|
||||||
|
// insurance by the "form resubmission" block afterward.
|
||||||
|
$oldInsurance = $this->createInsurance('1');
|
||||||
|
$newInsurance = $this->createInsurance('2');
|
||||||
|
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->insurance = $oldInsurance;
|
||||||
|
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->insurances = [$oldInsurance, $newInsurance];
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
// Only the NEW insurance is ever eligible - the old one would fail re-validation
|
||||||
|
// if the (buggy) resubmission block ran a second time after this new selection.
|
||||||
|
$this->insuranceService
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getEligibleInsurances')
|
||||||
|
->willReturn([$newInsurance]);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '2'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertSame($newInsurance, $participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
public function testProcessFieldWorksWithStringAndIntegerIds(): void
|
public function testProcessFieldWorksWithStringAndIntegerIds(): void
|
||||||
{
|
{
|
||||||
$insurance = $this->createInsurance(123); // Integer ID
|
$insurance = $this->createInsurance(123); // Integer ID
|
||||||
@@ -249,6 +279,250 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase
|
|||||||
$this->assertNull($participant->insurance);
|
$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');
|
||||||
|
$nonFamilyInsurance->familyInsurance = false;
|
||||||
|
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->dateFrom = new \DateTimeImmutable('2025-08-01');
|
||||||
|
$travel->dateTo = new \DateTimeImmutable('2025-08-08');
|
||||||
|
$travel->insurances = [$nonFamilyInsurance];
|
||||||
|
|
||||||
|
$applicant = new ParticipantDto();
|
||||||
|
$applicant->index = 0;
|
||||||
|
$applicant->dateOfBirth = new \DateTimeImmutable('1990-06-15');
|
||||||
|
|
||||||
|
// No dependents yet - not (and cannot be) a family booking at selection time
|
||||||
|
$bookingDto = new BookingDto($travel, 1);
|
||||||
|
$bookingDto->participants = [$applicant];
|
||||||
|
|
||||||
|
$this->insuranceService->method('getEligibleInsurances')->willReturn([$nonFamilyInsurance]);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '1'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertTrue(
|
||||||
|
$bookingDto->applicantInsuranceChosenWhileFamilyIneligible,
|
||||||
|
'Choosing non-family insurance while ineligible must be recorded so a later hint is justified'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldDoesNotRecordIneligibilityWhenApplicantSelectsInsuranceWhileAlreadyFamilyEligible(): void
|
||||||
|
{
|
||||||
|
$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');
|
||||||
|
|
||||||
|
$child = new ParticipantDto();
|
||||||
|
$child->index = 1;
|
||||||
|
$child->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||||
|
|
||||||
|
// Dependent's date of birth is already known, and a family insurance product is
|
||||||
|
// actually eligible at the current price - family insurance was genuinely
|
||||||
|
// available at the moment the applicant deliberately chose a non-family insurance.
|
||||||
|
$bookingDto = new BookingDto($travel, 1);
|
||||||
|
$bookingDto->participants = [$applicant, $child];
|
||||||
|
|
||||||
|
$this->priceCalculatorService->method('calculateTotalBookingPriceExcludingInsurance')->willReturn(500.0);
|
||||||
|
$this->insuranceService->method('getEligibleInsurances')->willReturnCallback(
|
||||||
|
fn (array $insurances) => $insurances
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '1'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$bookingDto->applicantInsuranceChosenWhileFamilyIneligible,
|
||||||
|
'Must not claim family insurance "just became available" when it was already eligible at selection time'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldRecordsIneligibilityWhenFamilyCompositionExistsButNoPriceTierMatches(): void
|
||||||
|
{
|
||||||
|
// Regression: family composition (adult + child) alone isn't enough - a family
|
||||||
|
// insurance product must actually match the current total price for it to count
|
||||||
|
// as "eligible". If it doesn't, the applicant's choice was genuinely made while
|
||||||
|
// family insurance was NOT selectable, even though isFamilyBooking() is already true.
|
||||||
|
$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');
|
||||||
|
|
||||||
|
$child = new ParticipantDto();
|
||||||
|
$child->index = 1;
|
||||||
|
$child->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||||
|
|
||||||
|
$bookingDto = new BookingDto($travel, 1);
|
||||||
|
$bookingDto->participants = [$applicant, $child];
|
||||||
|
|
||||||
|
$this->priceCalculatorService->method('calculateTotalBookingPriceExcludingInsurance')->willReturn(500.0);
|
||||||
|
$this->insuranceService->method('getEligibleInsurances')->willReturnCallback(
|
||||||
|
// No family insurance matches the current price tier, even though the
|
||||||
|
// participant composition already qualifies as a family booking.
|
||||||
|
fn (array $insurances) => array_values(array_filter($insurances, fn ($i) => false === $i->familyInsurance))
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '1'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertTrue(
|
||||||
|
$bookingDto->applicantInsuranceChosenWhileFamilyIneligible,
|
||||||
|
'Family composition alone must not count as eligible - no family insurance actually matched the price'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
public function testGetFieldStateModificationsReturnsEmptyArray(): void
|
||||||
{
|
{
|
||||||
$bookingDto = $this->createMockBookingDto();
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
|||||||
Reference in new issue
Block a user