132 lines
5.9 KiB
PHP
132 lines
5.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Service;
|
|
|
|
use App\BusProNet\Model\Insurance;
|
|
use App\BusProNet\Traits\SortByPriceTrait;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
|
|
/**
|
|
* Service for matching insurances to participants based on eligibility criteria.
|
|
*
|
|
* Evaluates insurance constraints including age limits, travel dates, booking windows,
|
|
* travel price ranges, and duration limits to determine which insurances are available
|
|
* for specific participants and booking scenarios.
|
|
*/
|
|
class InsuranceMatchingService
|
|
{
|
|
use SortByPriceTrait;
|
|
|
|
public function __construct(
|
|
private readonly BookingPriceCalculatorService $priceCalculatorService,
|
|
private readonly InsuranceTypeFilterService $insuranceTypeFilterService,
|
|
private readonly InsuranceEligibilityService $insuranceEligibilityService,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Filters insurances based on participant and booking criteria.
|
|
*
|
|
* @param array<Insurance> $insurances Available insurances to filter
|
|
* @param ParticipantDto $participant The participant to match insurances for
|
|
* @param BookingDto $booking The booking context for additional criteria
|
|
*
|
|
* @return array<Insurance> Filtered array of eligible insurances
|
|
*/
|
|
public function getEligibleInsurances(array $insurances, ParticipantDto $participant, BookingDto $booking): array
|
|
{
|
|
// Calculate travel price for this participant
|
|
$travelPrice = $this->calculateTravelPrice($booking, $participant->index);
|
|
|
|
// Delegate to InsuranceEligibilityService
|
|
return $this->insuranceEligibilityService->getEligibleInsurances(
|
|
$insurances,
|
|
$participant,
|
|
$booking,
|
|
$travelPrice
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Auto-reassigns an insurance to the same type with appropriate price tier.
|
|
*
|
|
* This method is used when a participant's individual price changes and their
|
|
* current insurance is no longer eligible. It finds the same insurance type
|
|
* (subType + familyInsurance) with the correct price tier.
|
|
*
|
|
* @param array<Insurance> $availableInsurances All available insurances
|
|
* @param Insurance $currentInsurance The currently selected insurance
|
|
* @param ParticipantDto $participant The participant to reassign for
|
|
* @param BookingDto $booking The booking context
|
|
*
|
|
* @return Insurance|null The reassigned insurance or null if no suitable match found
|
|
*/
|
|
public function reassignInsuranceForPriceChange(array $availableInsurances, Insurance $currentInsurance, ParticipantDto $participant, BookingDto $booking): ?Insurance
|
|
{
|
|
// Group insurances of the same type
|
|
$sameTypeInsurances = $this->insuranceTypeFilterService->filterByType($availableInsurances, $currentInsurance);
|
|
|
|
// Get eligible insurances for this participant
|
|
$eligibleInsurances = $this->getEligibleInsurances($sameTypeInsurances, $participant, $booking);
|
|
|
|
// Return the first eligible insurance (they should all be equivalent for the same type)
|
|
return !empty($eligibleInsurances) ? array_values($eligibleInsurances)[0] : null;
|
|
}
|
|
|
|
/**
|
|
* Batch-assigns insurances of the same type to all participants based on individual pricing.
|
|
*
|
|
* FUTURE FEATURE: This method will be used when implementing the "applicant assigns
|
|
* insurance to all participants" feature. The applicant's selection will be propagated
|
|
* to all participants with automatic price tier adjustment based on individual prices.
|
|
*
|
|
* This method takes the applicant's insurance selection and assigns the same insurance type
|
|
* (subType + familyInsurance) to all participants, but selects the appropriate price tier
|
|
* based on each participant's individual travel price.
|
|
*
|
|
* @param array<Insurance> $availableInsurances All available insurances
|
|
* @param Insurance $selectedInsurance The insurance selected by the applicant
|
|
* @param BookingDto $booking The booking with all participants
|
|
*
|
|
* @return array<int, Insurance|null> Array indexed by participant index with assigned insurances
|
|
*
|
|
* @internal Reserved for future feature implementation
|
|
*/
|
|
public function batchAssignInsuranceToParticipants(array $availableInsurances, Insurance $selectedInsurance, BookingDto $booking): array
|
|
{
|
|
$assignments = [];
|
|
|
|
// Group insurances of the same type
|
|
$sameTypeInsurances = $this->insuranceTypeFilterService->filterByType($availableInsurances, $selectedInsurance);
|
|
|
|
// Assign appropriate insurance to each participant
|
|
foreach ($booking->getParticipants() as $index => $participant) {
|
|
$eligibleInsurances = $this->getEligibleInsurances($sameTypeInsurances, $participant, $booking);
|
|
$assignments[$index] = !empty($eligibleInsurances) ? array_values($eligibleInsurances)[0] : null;
|
|
}
|
|
|
|
return $assignments;
|
|
}
|
|
|
|
/**
|
|
* Calculates the total travel price for a participant, excluding insurance prices.
|
|
*
|
|
* This method calculates the travel price used for insurance eligibility filtering.
|
|
* It excludes insurance prices to prevent circular dependency where insurance selection
|
|
* affects travel price which then affects insurance eligibility.
|
|
*
|
|
* @param BookingDto $booking The booking to calculate price for
|
|
* @param int $participantIndex The participant index to calculate for
|
|
*
|
|
* @return float The total travel price for the participant excluding insurance
|
|
*/
|
|
private function calculateTravelPrice(BookingDto $booking, int $participantIndex): float
|
|
{
|
|
// Use the price calculator to get the participant's individual price excluding insurance
|
|
return $this->priceCalculatorService->calculateIndividualParticipantPriceExcludingInsurance($booking, $participantIndex);
|
|
}
|
|
}
|