wip: bulk insurance booking fix

This commit is contained in:
Björn Fromme
2026-03-16 11:59:11 +01:00
parent a8cf67728b
commit a3d7ee63d3
6 changed files with 1132 additions and 263 deletions
+71 -5
View File
@@ -22,6 +22,8 @@ class BookingPriceCalculatorService
{
public function __construct(
private readonly ParticipantEligibilityService $participantEligibilityService,
private readonly InsuranceTypeFilterService $insuranceTypeFilterService,
private readonly InsuranceEligibilityService $insuranceEligibilityService,
) {
}
@@ -173,7 +175,7 @@ class BookingPriceCalculatorService
continue;
}
$this->aggregateParticipantServices($participant, $serviceAggregation);
$this->aggregateParticipantServices($participant, $serviceAggregation, $bookingDto);
}
// Add transportation services as separate line items (Zustieg, Rabatt, Parkplatz)
@@ -518,8 +520,11 @@ class BookingPriceCalculatorService
/**
* Aggregates service selections from a single participant into the service aggregation array.
*/
private function aggregateParticipantServices(ParticipantDto $participant, array &$serviceAggregation): void
{
private function aggregateParticipantServices(
ParticipantDto $participant,
array &$serviceAggregation,
BookingDto $bookingDto,
): void {
// Handle single service selections (skiPass, rentalInsurance)
if (null !== $participant->skiPass && null !== $participant->skiPass->price) {
$this->addToServiceAggregation($serviceAggregation, $participant->skiPass, 1);
@@ -529,8 +534,11 @@ class BookingPriceCalculatorService
$this->addToServiceAggregation($serviceAggregation, $participant->rentalInsurance, 1);
}
if (null !== $participant->insurance && null !== $participant->insurance->price) {
$this->addInsuranceToServiceAggregation($serviceAggregation, $participant->insurance, 1);
// Resolve insurance: use price-tier-adjusted insurance for bulk assignment
$insuranceToAggregate = $this->resolveInsuranceForAggregation($participant, $bookingDto);
if (null !== $insuranceToAggregate && null !== $insuranceToAggregate->price) {
$this->addInsuranceToServiceAggregation($serviceAggregation, $insuranceToAggregate, 1);
}
// Handle multiple service selections
@@ -732,4 +740,62 @@ class BookingPriceCalculatorService
// Bulk insurance is active - use applicant's insurance for dependent participants
return $applicant->insurance;
}
/**
* Resolves the insurance to use for aggregation, handling bulk insurance with price tiers.
*
* When bulk insurance is active, dependent participants get price-tier-adjusted insurance
* based on their individual travel price, matching the logic used in API submission.
*
* @param ParticipantDto $participant The participant to resolve insurance for
* @param BookingDto $bookingDto The booking context
*
* @return Insurance|null The insurance to aggregate (null if none)
*/
private function resolveInsuranceForAggregation(ParticipantDto $participant, BookingDto $bookingDto): ?Insurance
{
// If participant already has insurance assigned, use it
if (null !== $participant->insurance) {
return $participant->insurance;
}
// Check if bulk insurance is active
$applicant = $bookingDto->getParticipant(0);
if (null === $applicant || false === $applicant->bulkInsuranceBooking || null === $applicant->insurance) {
return null; // No bulk insurance active
}
// Applicant always uses their own insurance
if (0 === $participant->index) {
return $participant->insurance;
}
// For dependent participants: calculate price-tier-adjusted insurance
// This mirrors the logic in BookingDataProcessor::applyBulkInsuranceIfActive()
$availableInsurances = $bookingDto->travel->insurances;
// Exclude complementary insurances
$availableInsurances = array_filter($availableInsurances, fn ($insurance) => false === $insurance->complementary);
$availableInsurances = array_values($availableInsurances);
// Get insurances of the same type as applicant's selection
$sameTypeInsurances = $this->insuranceTypeFilterService->filterByType(
$availableInsurances,
$applicant->insurance
);
// Calculate participant's travel price (excluding insurance)
$travelPrice = $this->calculateIndividualParticipantPriceExcludingInsurance($bookingDto, $participant->index);
// Get eligible insurances for THIS participant (price tier adjusted)
$eligibleInsurances = $this->insuranceEligibilityService->getEligibleInsurances(
$sameTypeInsurances,
$participant,
$bookingDto,
$travelPrice
);
// Return first eligible insurance (sorted by price)
return !empty($eligibleInsurances) ? array_values($eligibleInsurances)[0] : null;
}
}