wip: insurance booking
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Service;
|
||||
|
||||
use App\BusProNet\Constants;
|
||||
use App\BusProNet\Model\Insurance;
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\Form\Model\BookingCreateDto;
|
||||
@@ -238,6 +239,45 @@ class BookingPriceCalculatorService
|
||||
return $participantPrices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the total price for an individual participant excluding insurance.
|
||||
*
|
||||
* This method is used for insurance eligibility filtering to avoid circular dependency
|
||||
* where insurance selection affects travel price which affects insurance eligibility.
|
||||
*
|
||||
* @param BookingDtoInterface $bookingDto The booking data containing all participants
|
||||
* @param int $participantIndex The index of the participant to calculate for
|
||||
*
|
||||
* @return float The total price for the specified participant excluding insurance
|
||||
*/
|
||||
public function calculateIndividualParticipantPriceExcludingInsurance(BookingDtoInterface $bookingDto, int $participantIndex): float
|
||||
{
|
||||
if (false === $bookingDto instanceof BookingCreateDto) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$participant = $bookingDto->getParticipant($participantIndex);
|
||||
if (null === $participant) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$totalPrice = 0.0;
|
||||
|
||||
// Add room price if participant is assigned to a room
|
||||
if (null !== $participant->assignedRoomId) {
|
||||
$room = $this->getRoomById($bookingDto, $participant->assignedRoomId);
|
||||
if (null !== $room && null !== $room->price) {
|
||||
// Each participant pays the full room price
|
||||
$totalPrice += $room->price;
|
||||
}
|
||||
}
|
||||
|
||||
// Add service prices for this participant (excluding insurance)
|
||||
$totalPrice += $this->calculateParticipantServiceTotal($participant, false);
|
||||
|
||||
return $totalPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates all transportation-related services and pricing into separate line items.
|
||||
*
|
||||
@@ -311,7 +351,7 @@ class BookingPriceCalculatorService
|
||||
'unitPrice' => null,
|
||||
'participantCount' => $pickupParticipants,
|
||||
'totalPrice' => $pickupTotal,
|
||||
'subType' => 'transportation',
|
||||
'subType' => Constants::GROUP_TRANSPORTATION,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -323,7 +363,7 @@ class BookingPriceCalculatorService
|
||||
'unitPrice' => null,
|
||||
'participantCount' => $parkingParticipants,
|
||||
'totalPrice' => $parkingTotal,
|
||||
'subType' => 'transportation',
|
||||
'subType' => Constants::GROUP_TRANSPORTATION,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -356,7 +396,12 @@ class BookingPriceCalculatorService
|
||||
|
||||
// Normalize rental subtypes to avoid duplicate sections
|
||||
if (true === in_array($subType, Constants::TOKEN_RENTALS, true)) {
|
||||
$subType = 'rentals'; // Normalize all rental subtypes to a single key
|
||||
$subType = Constants::GROUP_RENTALS; // Normalize all rental subtypes to a single key
|
||||
}
|
||||
|
||||
// Normalize insurance subtypes to avoid duplicate sections
|
||||
if (true === in_array($subType, Constants::TOKEN_INSURANCES, true)) {
|
||||
$subType = Constants::GROUP_INSURANCE; // Normalize all insurance subtypes to a single key
|
||||
}
|
||||
|
||||
$isDiscount = $serviceData['totalPrice'] < 0;
|
||||
@@ -405,8 +450,9 @@ class BookingPriceCalculatorService
|
||||
Constants::TOKEN_ADDITIONAL => 'Zusatzleistungen',
|
||||
Constants::TOKEN_BOARD => 'Verpflegung',
|
||||
Constants::TOKEN_RENTAL_INSURANCE => 'Leihmaterial-Versicherung',
|
||||
'transportation' => 'Beförderung',
|
||||
'rentals' => 'Leihmaterial', // Normalized rental subtype
|
||||
Constants::GROUP_TRANSPORTATION => 'Beförderung',
|
||||
Constants::GROUP_RENTALS => 'Leihmaterial', // Normalized rental subtype
|
||||
Constants::GROUP_INSURANCE => 'Reiseversicherungen', // Normalized insurance subtype
|
||||
];
|
||||
|
||||
// Handle rentals array (keep for backward compatibility with non-normalized subtypes)
|
||||
@@ -431,6 +477,10 @@ class BookingPriceCalculatorService
|
||||
$this->addToServiceAggregation($serviceAggregation, $participant->rentalInsurance, 1);
|
||||
}
|
||||
|
||||
if (null !== $participant->insurance && null !== $participant->insurance->price) {
|
||||
$this->addInsuranceToServiceAggregation($serviceAggregation, $participant->insurance, 1);
|
||||
}
|
||||
|
||||
// Handle multiple service selections
|
||||
$multipleServiceArrays = [
|
||||
'courses' => $participant->courses,
|
||||
@@ -475,11 +525,12 @@ class BookingPriceCalculatorService
|
||||
/**
|
||||
* Calculates the total service cost for a single participant.
|
||||
*
|
||||
* @param ParticipantDto $participant The participant to calculate services for
|
||||
* @param ParticipantDto $participant The participant to calculate services for
|
||||
* @param bool $includeInsurance Whether to include insurance pricing (default: true)
|
||||
*
|
||||
* @return float The total service cost for this participant
|
||||
*/
|
||||
private function calculateParticipantServiceTotal(ParticipantDto $participant): float
|
||||
private function calculateParticipantServiceTotal(ParticipantDto $participant, bool $includeInsurance = true): float
|
||||
{
|
||||
$serviceTotal = 0.0;
|
||||
|
||||
@@ -492,6 +543,10 @@ class BookingPriceCalculatorService
|
||||
$serviceTotal += $participant->rentalInsurance->price;
|
||||
}
|
||||
|
||||
if ($includeInsurance && null !== $participant->insurance && null !== $participant->insurance->price) {
|
||||
$serviceTotal += $participant->insurance->price;
|
||||
}
|
||||
|
||||
// Transportation services
|
||||
if (null !== $participant->transportationOutbound && null !== $participant->transportationOutbound->price) {
|
||||
$serviceTotal += $participant->transportationOutbound->price;
|
||||
@@ -551,4 +606,30 @@ class BookingPriceCalculatorService
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an insurance to the service aggregation array.
|
||||
*
|
||||
* @param array $serviceAggregation The service aggregation array to update
|
||||
* @param Insurance $insurance The insurance to add
|
||||
* @param int $quantity The quantity of the insurance
|
||||
*/
|
||||
private function addInsuranceToServiceAggregation(array &$serviceAggregation, Insurance $insurance, int $quantity): void
|
||||
{
|
||||
$serviceKey = $insurance->id.'_'.$insurance->label;
|
||||
|
||||
if (false === isset($serviceAggregation[$serviceKey])) {
|
||||
$serviceAggregation[$serviceKey] = [
|
||||
'serviceId' => $insurance->id,
|
||||
'label' => $insurance->label,
|
||||
'unitPrice' => $insurance->price,
|
||||
'participantCount' => 0,
|
||||
'totalPrice' => 0.0,
|
||||
'subType' => $insurance->getSubType(),
|
||||
];
|
||||
}
|
||||
|
||||
$serviceAggregation[$serviceKey]['participantCount'] += $quantity;
|
||||
$serviceAggregation[$serviceKey]['totalPrice'] += $insurance->price * $quantity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ namespace App\Service;
|
||||
use App\BusProNet\Model\Insurance;
|
||||
use App\Form\Model\BookingCreateDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use App\Model\InsuranceEligibilityCriteria;
|
||||
use App\Service\BookingPriceCalculatorService;
|
||||
use App\Service\InsuranceTypeResolver;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
@@ -18,6 +21,11 @@ use Carbon\Carbon;
|
||||
*/
|
||||
class InsuranceMatchingService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly BookingPriceCalculatorService $priceCalculatorService,
|
||||
private readonly InsuranceTypeResolver $insuranceTypeResolver
|
||||
) {
|
||||
}
|
||||
/**
|
||||
* Filters insurances based on participant and booking criteria.
|
||||
*
|
||||
@@ -29,67 +37,151 @@ class InsuranceMatchingService
|
||||
*/
|
||||
public function getEligibleInsurances(array $insurances, ParticipantDto $participant, BookingCreateDto $booking): array
|
||||
{
|
||||
$travelStartDate = $booking->travel->dateFrom;
|
||||
$travelEndDate = $booking->travel->dateTo;
|
||||
$criteria = $this->createEligibilityCriteria($participant, $booking);
|
||||
|
||||
// Cannot match insurances without travel dates
|
||||
if (null === $travelStartDate || null === $travelEndDate) {
|
||||
return [];
|
||||
if (null === $criteria) {
|
||||
return []; // Cannot match insurances without travel dates
|
||||
}
|
||||
|
||||
$bookingDate = Carbon::now()->toDateTimeImmutable();
|
||||
$travelPrice = $this->calculateTravelPrice($booking);
|
||||
$travelDurationDays = $this->calculateTravelDurationDays($travelStartDate, $travelEndDate);
|
||||
|
||||
return array_filter($insurances, function (Insurance $insurance) use ($participant, $travelStartDate, $travelEndDate, $bookingDate, $travelPrice, $travelDurationDays) {
|
||||
return $this->isInsuranceEligible($insurance, $participant, $travelStartDate, $travelEndDate, $bookingDate, $travelPrice, $travelDurationDays);
|
||||
});
|
||||
return array_filter(
|
||||
$insurances,
|
||||
fn (Insurance $insurance) => $this->isInsuranceEligible($insurance, $criteria)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific insurance is eligible for a participant.
|
||||
* Auto-reassigns an insurance to the same type with appropriate price tier.
|
||||
*
|
||||
* @param Insurance $insurance The insurance to check
|
||||
* @param ParticipantDto $participant The participant
|
||||
* @param \DateTimeImmutable $travelStartDate Travel start date
|
||||
* @param \DateTimeImmutable $travelEndDate Travel end date
|
||||
* @param \DateTimeImmutable $bookingDate Booking date
|
||||
* @param float $travelPrice Total travel price
|
||||
* @param int $travelDurationDays Travel duration in days
|
||||
* 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.
|
||||
*
|
||||
* @return bool True if insurance is eligible
|
||||
* @param array<Insurance> $availableInsurances All available insurances
|
||||
* @param Insurance $currentInsurance The currently selected insurance
|
||||
* @param ParticipantDto $participant The participant to reassign for
|
||||
* @param BookingCreateDto $booking The booking context
|
||||
*
|
||||
* @return Insurance|null The reassigned insurance or null if no suitable match found
|
||||
*/
|
||||
private function isInsuranceEligible(
|
||||
Insurance $insurance,
|
||||
ParticipantDto $participant,
|
||||
\DateTimeImmutable $travelStartDate,
|
||||
\DateTimeImmutable $travelEndDate,
|
||||
\DateTimeImmutable $bookingDate,
|
||||
float $travelPrice,
|
||||
int $travelDurationDays,
|
||||
): bool {
|
||||
public function reassignInsuranceForPriceChange(array $availableInsurances, Insurance $currentInsurance, ParticipantDto $participant, BookingCreateDto $booking): ?Insurance
|
||||
{
|
||||
// Group insurances of the same type (subType + familyInsurance)
|
||||
$sameTypeInsurances = $this->filterInsurancesByType($availableInsurances, $currentInsurance->subType, $currentInsurance->familyInsurance);
|
||||
|
||||
// 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.
|
||||
*
|
||||
* 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 BookingCreateDto $booking The booking with all participants
|
||||
*
|
||||
* @return array<int, Insurance|null> Array indexed by participant index with assigned insurances
|
||||
*/
|
||||
public function batchAssignInsuranceToParticipants(array $availableInsurances, Insurance $selectedInsurance, BookingCreateDto $booking): array
|
||||
{
|
||||
$assignments = [];
|
||||
|
||||
// Group insurances of the same type (subType + familyInsurance)
|
||||
$sameTypeInsurances = $this->filterInsurancesByType($availableInsurances, $selectedInsurance->subType, $selectedInsurance->familyInsurance);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates eligibility criteria from participant and booking data.
|
||||
*/
|
||||
private function createEligibilityCriteria(ParticipantDto $participant, BookingCreateDto $booking): ?InsuranceEligibilityCriteria
|
||||
{
|
||||
$travelStartDate = $booking->travel->dateFrom;
|
||||
$travelEndDate = $booking->travel->dateTo;
|
||||
|
||||
if (null === $travelStartDate || null === $travelEndDate) {
|
||||
return null; // Cannot create criteria without travel dates
|
||||
}
|
||||
|
||||
return new InsuranceEligibilityCriteria(
|
||||
participant: $participant,
|
||||
travelStartDate: $travelStartDate,
|
||||
travelEndDate: $travelEndDate,
|
||||
bookingDate: Carbon::now()->toDateTimeImmutable(),
|
||||
travelPrice: $this->calculateTravelPrice($booking, $participant->index),
|
||||
travelDurationDays: $this->calculateTravelDurationDays($travelStartDate, $travelEndDate),
|
||||
booking: $booking,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific insurance is eligible for given criteria.
|
||||
*/
|
||||
private function isInsuranceEligible(Insurance $insurance, InsuranceEligibilityCriteria $criteria): bool
|
||||
{
|
||||
// Family insurance constraints
|
||||
if (false === $this->checkFamilyInsuranceConstraints($insurance, $criteria->booking)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Age constraints
|
||||
if (!$this->checkAgeConstraints($insurance, $participant, $travelStartDate)) {
|
||||
if (false === $this->checkAgeConstraints($insurance, $criteria->participant, $criteria->travelStartDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Travel date constraints
|
||||
if (!$this->checkTravelDateConstraints($insurance, $travelStartDate, $travelEndDate)) {
|
||||
if (false === $this->checkTravelDateConstraints($insurance, $criteria->travelStartDate, $criteria->travelEndDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Booking date constraints
|
||||
if (!$this->checkBookingDateConstraints($insurance, $bookingDate)) {
|
||||
if (false === $this->checkBookingDateConstraints($insurance, $criteria->bookingDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Travel price constraints
|
||||
if (!$this->checkTravelPriceConstraints($insurance, $travelPrice)) {
|
||||
if (false === $this->checkTravelPriceConstraints($insurance, $criteria->travelPrice)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Travel duration constraints
|
||||
if (!$this->checkTravelDurationConstraints($insurance, $travelDurationDays)) {
|
||||
if (false === $this->checkTravelDurationConstraints($insurance, $criteria->travelDurationDays)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if family insurance constraints are met.
|
||||
*
|
||||
* Family insurances should only be available for family bookings,
|
||||
* and individual insurances should only be available for non-family bookings.
|
||||
*/
|
||||
private function checkFamilyInsuranceConstraints(Insurance $insurance, BookingCreateDto $booking): bool
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
@@ -103,8 +195,9 @@ class InsuranceMatchingService
|
||||
{
|
||||
$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 false; // Cannot determine age eligibility without birth date
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check minimum age
|
||||
@@ -197,17 +290,21 @@ class InsuranceMatchingService
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the total travel price from booking data.
|
||||
* Calculates the total travel price for a participant, excluding insurance prices.
|
||||
*
|
||||
* @param BookingCreateDto $booking The booking to calculate price for
|
||||
* 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.
|
||||
*
|
||||
* @return float The total travel price
|
||||
* @param BookingCreateDto $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(BookingCreateDto $booking): float
|
||||
private function calculateTravelPrice(BookingCreateDto $booking, int $participantIndex): float
|
||||
{
|
||||
// For now, return 0.0 as placeholder - this will be enhanced
|
||||
// when we integrate with the existing pricing calculation system
|
||||
return 0.0;
|
||||
// Use the price calculator to get the participant's individual price excluding insurance
|
||||
return $this->priceCalculatorService->calculateIndividualParticipantPriceExcludingInsurance($booking, $participantIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,4 +319,24 @@ class InsuranceMatchingService
|
||||
{
|
||||
return $startDate->diff($endDate)->days;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters insurances by type (subType and familyInsurance combination).
|
||||
*
|
||||
* This method groups insurances of the same type together for reassignment or batch assignment.
|
||||
* Insurance type is defined as the combination of subType (RRV, PAK, OHN) and familyInsurance flag.
|
||||
*
|
||||
* @param array<Insurance> $insurances All available insurances to filter
|
||||
* @param string|null $subType The insurance subType to match (e.g., 'RRV', 'PAK')
|
||||
* @param bool $familyInsurance Whether to match family or individual insurances
|
||||
*
|
||||
* @return array<Insurance> Filtered insurances of the same type
|
||||
*/
|
||||
private function filterInsurancesByType(array $insurances, ?string $subType, bool $familyInsurance): array
|
||||
{
|
||||
return array_filter(
|
||||
$insurances,
|
||||
fn (Insurance $insurance) => $insurance->subType === $subType && $insurance->familyInsurance === $familyInsurance
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\XmlLoader\HotelLoader;
|
||||
use App\BusProNet\XmlLoader\InsuranceLoader;
|
||||
use App\BusProNet\XmlLoader\PickupLoader;
|
||||
use App\BusProNet\XmlLoader\TravelLoader;
|
||||
use App\Exception\HotelNotFoundException;
|
||||
@@ -36,6 +37,7 @@ class TravelDataService
|
||||
private readonly TravelLoader $travelLoader,
|
||||
private readonly HotelLoader $hotelLoader,
|
||||
private readonly PickupLoader $pickupLoader,
|
||||
private readonly InsuranceLoader $insuranceLoader,
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly LoggerInterface $logger,
|
||||
@@ -102,6 +104,11 @@ class TravelDataService
|
||||
public function getTravelDataFromXml(int $dateId, ?int $hotelId = null): ?Travel
|
||||
{
|
||||
try {
|
||||
$this->logger->debug('Loading travel data from XML', [
|
||||
'dateId' => $dateId,
|
||||
'hotelId' => $hotelId,
|
||||
]);
|
||||
|
||||
$travel = $this->travelLoader->loadById($dateId, $hotelId);
|
||||
|
||||
$this->enrichTravelData($travel);
|
||||
@@ -151,6 +158,11 @@ class TravelDataService
|
||||
public function getTravelDataFromApi(int $dateId, ?int $hotelId = null): ?Travel
|
||||
{
|
||||
try {
|
||||
$this->logger->debug('Loading travel data from API', [
|
||||
'dateId' => $dateId,
|
||||
'hotelId' => $hotelId,
|
||||
]);
|
||||
|
||||
// Map dateId to productId for API call
|
||||
$productId = $this->mapDateIdToProductId($dateId);
|
||||
if (null === $productId) {
|
||||
@@ -581,8 +593,13 @@ class TravelDataService
|
||||
private function enrichTravelData(Travel $travel): void
|
||||
{
|
||||
try {
|
||||
$this->logger->debug('Enriching travel data', [
|
||||
'travelId' => $travel->id,
|
||||
]);
|
||||
|
||||
$this->pickupLoader->patchPickupsDetails($travel);
|
||||
$this->hotelLoader->patchHotelDetails($travel);
|
||||
$this->patchInsuranceData($travel);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->warning('Failed to enrich travel data', [
|
||||
'travelId' => $travel->id,
|
||||
@@ -590,4 +607,34 @@ class TravelDataService
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds insurance data to travel object.
|
||||
*
|
||||
* Loads all available insurances and adds them to the travel object.
|
||||
* This ensures insurance options are available for booking.
|
||||
*
|
||||
* @param Travel $travel The travel object to enrich with insurance data
|
||||
*/
|
||||
private function patchInsuranceData(Travel $travel): void
|
||||
{
|
||||
try {
|
||||
$this->logger->debug('Loading insurance data', [
|
||||
'travelId' => $travel->id,
|
||||
]);
|
||||
|
||||
$insurances = $this->insuranceLoader->loadAll();
|
||||
$travel->insurances = array_values($insurances);
|
||||
|
||||
$this->logger->debug('Insurance data added to travel', [
|
||||
'travelId' => $travel->id,
|
||||
'insuranceCount' => count($insurances),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->warning('Failed to load insurance data', [
|
||||
'travelId' => $travel->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user