feat: bulk insurance booking by applicant

This commit is contained in:
Björn Fromme
2025-10-01 17:52:21 +02:00
parent 372490ed5a
commit b4eaf695c7
10 changed files with 402 additions and 24 deletions
@@ -0,0 +1,142 @@
<?php
declare(strict_types=1);
namespace App\Form\Service;
use App\Form\Model\BookingCreateDto;
use App\Form\Model\BookingDtoInterface;
use App\Form\Service\Abstract\AbstractParticipantFieldHandler;
use App\Service\InsuranceMatchingService;
/**
* Handles bulk insurance booking for the applicant (first participant).
*
* When the applicant enables bulk insurance booking, their selected insurance type
* (subType + familyInsurance) is automatically assigned to all participants with
* automatic price tier adjustment based on each participant's individual travel price.
*
* This handler processes the bulkInsuranceBooking checkbox state and triggers
* insurance assignment to dependent participants when enabled.
*
* Dependencies: insurance (applicant must have insurance selected before enabling bulk)
*/
class ParticipantBulkInsuranceFieldHandler extends AbstractParticipantFieldHandler
{
public function __construct(
private readonly InsuranceMatchingService $insuranceMatchingService,
) {
}
public function getFieldName(): string
{
return 'bulkInsuranceBooking';
}
public function getDependencies(): array
{
// Depends on insurance field to ensure insurance is selected before bulk assignment
return ['insurance'];
}
/**
* Determines if this handler should process the field.
*
* Only process for the applicant (index 0). Dependent participants don't have
* the bulkInsuranceBooking checkbox - their insurance is controlled by the handler.
*
* @param array<string, mixed> $submittedData The submitted participant form data
* @param int $participantIndex The index of the participant being processed
*
* @return bool True if this is the applicant, false otherwise
*/
public function shouldProcess(array $submittedData, int $participantIndex): bool
{
return 0 === $participantIndex; // Only process for applicant
}
/**
* Processes the bulk insurance booking checkbox for the applicant.
*
* When bulk insurance is enabled and applicant has insurance selected,
* assigns the same insurance type to all participants based on their
* individual pricing and eligibility criteria.
*
* @param array<string, mixed> $submittedData The submitted participant form data
* @param BookingDtoInterface $bookingDto The booking DTO to update
* @param int $participantIndex The index of the participant (must be 0)
*/
public function processField(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): void
{
$participant = $this->getParticipant($bookingDto, $participantIndex);
if (null === $participant || !$bookingDto instanceof BookingCreateDto) {
return;
}
// Get checkbox value from submitted data
$bulkInsuranceBooking = $this->getFieldValue($submittedData, $this->getFieldName());
$isBulkEnabled = (bool) $bulkInsuranceBooking;
// Store checkbox state
$participant->bulkInsuranceBooking = $isBulkEnabled;
// If bulk insurance is enabled and applicant has insurance, assign to all participants
if (true === $isBulkEnabled && null !== $participant->insurance) {
$this->applyBulkInsuranceToAllParticipants($bookingDto, $participant->insurance);
}
// If bulk insurance is disabled, clear dependent participants' insurances
if (false === $isBulkEnabled) {
$this->clearDependentParticipantsInsurance($bookingDto);
}
}
/**
* Applies the applicant's insurance type to all participants with automatic price tier adjustment.
*
* Uses InsuranceMatchingService to find the appropriate price tier for each participant
* based on their individual travel price and eligibility criteria.
*
* @param BookingCreateDto $bookingDto The booking DTO with all participants
* @param object $applicantInsurance The insurance selected by the applicant
*/
private function applyBulkInsuranceToAllParticipants(BookingCreateDto $bookingDto, object $applicantInsurance): void
{
$availableInsurances = $bookingDto->travel->insurances ?? [];
// Get insurance assignments for all participants
$assignments = $this->insuranceMatchingService->batchAssignInsuranceToParticipants(
$availableInsurances,
$applicantInsurance,
$bookingDto
);
// Apply assignments to participants (skip applicant index 0, they keep their selection)
foreach ($assignments as $index => $insurance) {
if (0 === $index) {
continue; // Skip applicant
}
$participant = $bookingDto->getParticipant($index);
if (null !== $participant) {
$participant->insurance = $insurance;
}
}
}
/**
* Clears insurance selections for dependent participants when bulk booking is disabled.
*
* @param BookingCreateDto $bookingDto The booking DTO with all participants
*/
private function clearDependentParticipantsInsurance(BookingCreateDto $bookingDto): void
{
foreach ($bookingDto->getParticipants() as $index => $participant) {
if (0 === $index) {
continue; // Skip applicant
}
$participant->insurance = null;
}
}
}