wip: bulk insurance booking fix
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
<?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;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Service for evaluating insurance eligibility without circular dependencies.
|
||||
*
|
||||
* This service contains the core eligibility logic that can be used by both
|
||||
* InsuranceMatchingService and BookingPriceCalculatorService.
|
||||
*/
|
||||
class InsuranceEligibilityService
|
||||
{
|
||||
use SortByPriceTrait;
|
||||
|
||||
/**
|
||||
* Filters insurances based on eligibility criteria.
|
||||
*
|
||||
* @param array<Insurance> $insurances Available insurances to filter
|
||||
* @param ParticipantDto $participant The participant to match insurances for
|
||||
* @param BookingDto $booking The booking context
|
||||
* @param float $travelPrice The participant's travel price (excluding insurance)
|
||||
*
|
||||
* @return array<Insurance> Filtered array of eligible insurances, sorted by price
|
||||
*/
|
||||
public function getEligibleInsurances(
|
||||
array $insurances,
|
||||
ParticipantDto $participant,
|
||||
BookingDto $booking,
|
||||
float $travelPrice,
|
||||
): array {
|
||||
$travelStartDate = $booking->travel->dateFrom;
|
||||
$travelEndDate = $booking->travel->dateTo;
|
||||
|
||||
if (null === $travelStartDate || null === $travelEndDate) {
|
||||
return []; // Cannot evaluate without travel dates
|
||||
}
|
||||
|
||||
$bookingDate = Carbon::now()->toDateTimeImmutable();
|
||||
$travelDurationDays = $travelStartDate->diff($travelEndDate)->days;
|
||||
|
||||
$eligibleInsurances = array_filter(
|
||||
$insurances,
|
||||
fn (Insurance $insurance) => $this->isInsuranceEligible(
|
||||
$insurance,
|
||||
$participant,
|
||||
$booking,
|
||||
$travelStartDate,
|
||||
$travelEndDate,
|
||||
$bookingDate,
|
||||
$travelPrice,
|
||||
$travelDurationDays
|
||||
)
|
||||
);
|
||||
|
||||
return $this->sortByPrice($eligibleInsurances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific insurance is eligible for given criteria.
|
||||
*/
|
||||
private function isInsuranceEligible(
|
||||
Insurance $insurance,
|
||||
ParticipantDto $participant,
|
||||
BookingDto $booking,
|
||||
\DateTimeImmutable $travelStartDate,
|
||||
\DateTimeImmutable $travelEndDate,
|
||||
\DateTimeImmutable $bookingDate,
|
||||
float $travelPrice,
|
||||
int $travelDurationDays,
|
||||
): bool {
|
||||
// Family insurance constraints
|
||||
if (false === $this->checkFamilyInsuranceConstraints($insurance, $booking)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Age constraints
|
||||
if (false === $this->checkAgeConstraints($insurance, $participant, $travelStartDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Travel date constraints
|
||||
if (false === $this->checkTravelDateConstraints($insurance, $travelStartDate, $travelEndDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Booking date constraints
|
||||
if (false === $this->checkBookingDateConstraints($insurance, $bookingDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Travel price constraints
|
||||
if (false === $this->checkTravelPriceConstraints($insurance, $travelPrice)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Travel duration constraints
|
||||
if (false === $this->checkTravelDurationConstraints($insurance, $travelDurationDays)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkFamilyInsuranceConstraints(Insurance $insurance, BookingDto $booking): bool
|
||||
{
|
||||
// Family booking detection only available in create mode
|
||||
if (BookingDto::MODE_EDIT === $booking->getMode()) {
|
||||
return true; // Skip family constraints for edit mode
|
||||
}
|
||||
|
||||
$isFamilyBooking = $booking->isFamilyBooking();
|
||||
|
||||
// If it's a family insurance, it should only be available for family bookings
|
||||
if (true === $insurance->familyInsurance && false === $isFamilyBooking) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it's not a family insurance, it should only be available for non-family bookings
|
||||
if (false === $insurance->familyInsurance && true === $isFamilyBooking) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkAgeConstraints(Insurance $insurance, ParticipantDto $participant, \DateTimeImmutable $travelStartDate): bool
|
||||
{
|
||||
$participantAge = $participant->getAge($travelStartDate);
|
||||
|
||||
// If no birth date is provided, skip age constraints (field will be hidden via field state conditions)
|
||||
if (null === $participantAge) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check minimum age
|
||||
if (null !== $insurance->ageFrom && $participantAge < $insurance->ageFrom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check maximum age
|
||||
if (null !== $insurance->ageTo && $participantAge > $insurance->ageTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkTravelDateConstraints(Insurance $insurance, \DateTimeImmutable $travelStartDate, \DateTimeImmutable $travelEndDate): bool
|
||||
{
|
||||
// Check travel start date
|
||||
if (null !== $insurance->travelDateFrom && $travelStartDate < $insurance->travelDateFrom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null !== $insurance->travelDateTo && $travelStartDate > $insurance->travelDateTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check travel end date
|
||||
if (null !== $insurance->travelDateTo && $travelEndDate > $insurance->travelDateTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkBookingDateConstraints(Insurance $insurance, \DateTimeImmutable $bookingDate): bool
|
||||
{
|
||||
// Check booking window start
|
||||
if (null !== $insurance->bookingDateFrom && $bookingDate < $insurance->bookingDateFrom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check booking window end
|
||||
if (null !== $insurance->bookingDateTo && $bookingDate > $insurance->bookingDateTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkTravelPriceConstraints(Insurance $insurance, float $travelPrice): bool
|
||||
{
|
||||
// Check minimum price
|
||||
if (null !== $insurance->travelPriceFrom && $travelPrice < $insurance->travelPriceFrom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check maximum price
|
||||
if (null !== $insurance->travelPriceTo && $travelPrice > $insurance->travelPriceTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkTravelDurationConstraints(Insurance $insurance, int $travelDurationDays): bool
|
||||
{
|
||||
// Check minimum duration
|
||||
if (null !== $insurance->travelDurationFrom && $travelDurationDays < $insurance->travelDurationFrom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check maximum duration
|
||||
if (null !== $insurance->travelDurationTo && $travelDurationDays > $insurance->travelDurationTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user