wip: insurance booking
This commit is contained in:
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Form\Service;
|
||||
|
||||
use App\BusProNet\Model\Insurance;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\Form\Model\BookingDtoInterface;
|
||||
@@ -345,6 +346,11 @@ class ParticipantFieldHandlerRegistry
|
||||
return $value->id;
|
||||
}
|
||||
|
||||
// Handle Insurance objects -> convert to ID
|
||||
if ($value instanceof Insurance) {
|
||||
return $value->id;
|
||||
}
|
||||
|
||||
// Handle DateTimeInterface -> convert to string format
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return $value->format('Y-m-d');
|
||||
|
||||
@@ -13,7 +13,6 @@ use App\Form\Model\BookingCreateDto;
|
||||
use App\Form\Model\BookingDtoInterface;
|
||||
use App\Form\Service\Abstract\AbstractFieldOptionsProvider;
|
||||
use App\Form\Service\Factory\ParticipantRoomChoiceLoaderFactory;
|
||||
use App\Form\Service\ServiceAgeEvaluator;
|
||||
use App\Service\InsuranceMatchingService;
|
||||
use App\Service\ServiceAvailabilityCalculator;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
@@ -591,7 +590,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
private function getParkingCheckboxLabel(array $parkingServices): string
|
||||
{
|
||||
if (empty($parkingServices)) {
|
||||
return 'Parkplatz';
|
||||
return Constants::SERVICE_LABELS[Constants::TOKEN_PARKING];
|
||||
}
|
||||
|
||||
$parkingService = reset($parkingServices); // Get the first (and only) parking service
|
||||
@@ -681,7 +680,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
private function getRentalInsuranceCheckboxLabel(array $rentalInsuranceServices): string
|
||||
{
|
||||
if (empty($rentalInsuranceServices)) {
|
||||
return 'Leihmaterial-Versicherung';
|
||||
return Constants::SERVICE_LABELS[Constants::TOKEN_RENTAL_INSURANCE];
|
||||
}
|
||||
$rentalInsuranceService = reset($rentalInsuranceServices); // Get the first (and only) rental insurance service
|
||||
|
||||
@@ -751,15 +750,9 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
$label .= sprintf(' (€%s)', number_format($insurance->price, 2, ',', '.'));
|
||||
}
|
||||
|
||||
// Add type information if available
|
||||
if (null !== $insurance->subType) {
|
||||
$typeLabel = match ($insurance->subType) {
|
||||
'RRV' => 'Reiserücktrittsversicherung',
|
||||
'PAK' => 'Reiseschutz',
|
||||
'OHN' => 'Selbstbehalt',
|
||||
default => $insurance->subType,
|
||||
};
|
||||
$label .= sprintf(' (%s)', $typeLabel);
|
||||
// Add type information if available using centralized mapping
|
||||
if (null !== $insurance->subType && isset(Constants::INSURANCE_LABELS[$insurance->subType])) {
|
||||
$label .= sprintf(' (%s)', Constants::INSURANCE_LABELS[$insurance->subType]);
|
||||
}
|
||||
|
||||
return $label;
|
||||
|
||||
@@ -35,7 +35,7 @@ use App\Service\InsuranceMatchingService;
|
||||
class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
||||
{
|
||||
public function __construct(
|
||||
private readonly InsuranceMatchingService $insuranceMatchingService
|
||||
private readonly InsuranceMatchingService $insuranceMatchingService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -52,13 +52,27 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
||||
/**
|
||||
* Returns the field dependencies for proper processing order.
|
||||
*
|
||||
* This handler depends on dateOfBirth for age evaluation and insurance eligibility.
|
||||
* This handler must run AFTER all fields that affect travel price, since insurance
|
||||
* reassignment logic depends on accurate price calculations. It also depends on
|
||||
* dateOfBirth for age evaluation and insurance eligibility.
|
||||
*
|
||||
* @return string[] Array containing 'dateOfBirth' dependency
|
||||
* @return string[] Array of field dependencies
|
||||
*/
|
||||
public function getDependencies(): array
|
||||
{
|
||||
return ['dateOfBirth'];
|
||||
return [
|
||||
'dateOfBirth', // Required for age-based eligibility
|
||||
'skiPass', // Affects travel price
|
||||
'rentals', // Affects travel price
|
||||
'courses', // Affects travel price
|
||||
'additionalServices', // Affects travel price
|
||||
'board', // Affects travel price
|
||||
'transportationOutbound', // Affects travel price
|
||||
'transportationInbound', // Affects travel price
|
||||
'pickupOutbound', // Affects travel price
|
||||
'pickupInbound', // Affects travel price
|
||||
'parking', // Affects travel price
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,8 +96,12 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
||||
* Processes the insurance field for a specific participant.
|
||||
*
|
||||
* This method handles both explicit insurance selection from form data and automatic
|
||||
* reassignment when the participant's travel price changes. It maintains the same
|
||||
* insurance type but adjusts to the appropriate price tier when needed.
|
||||
* reassignment when the participant's travel price changes. It distinguishes between:
|
||||
* 1. New selection: User explicitly changed their insurance choice
|
||||
* 2. Resubmission: Form resubmitted with existing insurance (e.g., after adding rentals)
|
||||
*
|
||||
* For resubmissions, it checks if the current insurance is still eligible with updated
|
||||
* participant data and automatically reassigns to the correct price tier if needed.
|
||||
*
|
||||
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||
* @param BookingDtoInterface $bookingDto The booking DTO to update (create or edit)
|
||||
@@ -100,59 +118,63 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
||||
$currentInsurance = $participant->insurance;
|
||||
$availableInsurances = $bookingDto->travel->insurances ?? [];
|
||||
|
||||
// Handle explicit insurance selection from form
|
||||
if (null !== $selectedInsuranceId) {
|
||||
// Determine if this is a new user selection or just form resubmission
|
||||
$isNewSelection = null !== $selectedInsuranceId
|
||||
&& (null === $currentInsurance || !$this->isSameInsurance($selectedInsuranceId, $currentInsurance));
|
||||
|
||||
// Handle explicit new insurance selection from user
|
||||
if ($isNewSelection) {
|
||||
$selectedInsurance = $this->findInsuranceById($availableInsurances, $selectedInsuranceId);
|
||||
|
||||
// Check if the selected insurance is still eligible for this participant
|
||||
if (null !== $selectedInsurance) {
|
||||
$eligibleInsurances = $this->insuranceMatchingService->getEligibleInsurances($availableInsurances, $participant, $bookingDto);
|
||||
$isSelectedInsuranceEligible = $this->isInsuranceInList($selectedInsurance, $eligibleInsurances);
|
||||
|
||||
if ($isSelectedInsuranceEligible) {
|
||||
// Insurance is still eligible - use it directly
|
||||
// New selection is eligible - use it
|
||||
$participant->insurance = $selectedInsurance;
|
||||
return;
|
||||
} else {
|
||||
// Insurance is no longer eligible - try to reassign to same type with new price tier
|
||||
// New selection is not eligible - try to find alternative in same type
|
||||
$reassignedInsurance = $this->insuranceMatchingService->reassignInsuranceForPriceChange(
|
||||
$availableInsurances,
|
||||
$selectedInsurance,
|
||||
$participant,
|
||||
$bookingDto
|
||||
);
|
||||
|
||||
$participant->insurance = $reassignedInsurance;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Insurance not found - clear selection
|
||||
$participant->insurance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle automatic reassignment if participant had an insurance but it's no longer eligible
|
||||
if (null !== $currentInsurance) {
|
||||
// Check if current insurance is still eligible
|
||||
// Handle form resubmission with existing insurance (automatic reassignment check)
|
||||
if (null !== $currentInsurance && null !== $selectedInsuranceId) {
|
||||
// Check if current insurance is still eligible with updated participant data
|
||||
$eligibleInsurances = $this->insuranceMatchingService->getEligibleInsurances($availableInsurances, $participant, $bookingDto);
|
||||
$isCurrentInsuranceStillEligible = $this->isInsuranceInList($currentInsurance, $eligibleInsurances);
|
||||
|
||||
if (!$isCurrentInsuranceStillEligible) {
|
||||
// Try to reassign to same insurance type with appropriate price tier
|
||||
// Current insurance no longer eligible - try to reassign to same type with new price tier
|
||||
$reassignedInsurance = $this->insuranceMatchingService->reassignInsuranceForPriceChange(
|
||||
$availableInsurances,
|
||||
$currentInsurance,
|
||||
$participant,
|
||||
$bookingDto
|
||||
);
|
||||
|
||||
$participant->insurance = $reassignedInsurance; // null if no suitable match found
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// No insurance selected or reassignment needed - keep current state (may be null)
|
||||
// Handle explicit deselection (user removed insurance)
|
||||
if (null === $selectedInsuranceId) {
|
||||
$participant->insurance = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,4 +243,19 @@ class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the submitted insurance ID matches the current insurance.
|
||||
*
|
||||
* This is used to distinguish between a new user selection and a form resubmission
|
||||
* with the existing insurance selection (e.g., when user adds rentals that change travel price).
|
||||
*
|
||||
* @param string|int $selectedInsuranceId The insurance ID from form submission
|
||||
* @param Insurance $currentInsurance The currently assigned insurance from DTO
|
||||
*
|
||||
* @return bool True if they represent the same insurance
|
||||
*/
|
||||
private function isSameInsurance(string|int $selectedInsuranceId, Insurance $currentInsurance): bool
|
||||
{
|
||||
return (string) $currentInsurance->id === (string) $selectedInsuranceId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user