wip: insurance booking

This commit is contained in:
Björn Fromme
2026-03-16 11:59:10 +01:00
parent 8af7f0e797
commit 4ba81b8f03
19 changed files with 807 additions and 128 deletions
+88 -7
View File
@@ -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;
}
}