wip: insurance booking

This commit is contained in:
Björn Fromme
2026-03-16 11:59:10 +01:00
parent 4ba81b8f03
commit 29bdf794f3
11 changed files with 131 additions and 475 deletions
+6 -17
View File
@@ -359,7 +359,7 @@ class BookingPriceCalculatorService
if ($parkingTotal > 0) {
$transportationItems['transportation_parking'] = [
'serviceId' => 'transportation_parking',
'label' => 'Parkplatz',
'label' => Constants::SERVICE_LABELS[Constants::TOKEN_PARKING],
'unitPrice' => null,
'participantCount' => $parkingParticipants,
'totalPrice' => $parkingTotal,
@@ -444,23 +444,12 @@ class BookingPriceCalculatorService
*/
private function getGroupNameForSubtype(string $subType): string
{
$groupMapping = [
Constants::TOKEN_COURSES => 'Kurse',
Constants::TOKEN_SKI_PASS => 'Skipässe',
Constants::TOKEN_ADDITIONAL => 'Zusatzleistungen',
Constants::TOKEN_BOARD => 'Verpflegung',
Constants::TOKEN_RENTAL_INSURANCE => 'Leihmaterial-Versicherung',
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)
if (true === in_array($subType, Constants::TOKEN_RENTALS, true)) {
return 'Leihmaterial';
return Constants::SERVICE_LABELS[Constants::GROUP_RENTALS];
}
return $groupMapping[$subType] ?? 'Sonstige Leistungen';
return Constants::SERVICE_LABELS[$subType] ?? 'Sonstige Leistungen';
}
/**
@@ -525,8 +514,8 @@ class BookingPriceCalculatorService
/**
* Calculates the total service cost for a single participant.
*
* @param ParticipantDto $participant The participant to calculate services for
* @param bool $includeInsurance Whether to include insurance pricing (default: true)
* @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
*/
@@ -612,7 +601,7 @@ class BookingPriceCalculatorService
*
* @param array $serviceAggregation The service aggregation array to update
* @param Insurance $insurance The insurance to add
* @param int $quantity The quantity of the insurance
* @param int $quantity The quantity of the insurance
*/
private function addInsuranceToServiceAggregation(array &$serviceAggregation, Insurance $insurance, int $quantity): void
{
+11 -3
View File
@@ -8,8 +8,6 @@ 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;
/**
@@ -23,9 +21,9 @@ class InsuranceMatchingService
{
public function __construct(
private readonly BookingPriceCalculatorService $priceCalculatorService,
private readonly InsuranceTypeResolver $insuranceTypeResolver
) {
}
/**
* Filters insurances based on participant and booking criteria.
*
@@ -78,6 +76,10 @@ class InsuranceMatchingService
/**
* 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.
@@ -87,6 +89,8 @@ class InsuranceMatchingService
* @param BookingCreateDto $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, BookingCreateDto $booking): array
{
@@ -106,9 +110,13 @@ class InsuranceMatchingService
/**
* Creates eligibility criteria from participant and booking data.
*
* This method performs early validation before creating the criteria object
* to avoid unnecessary object instantiation when criteria cannot be satisfied.
*/
private function createEligibilityCriteria(ParticipantDto $participant, BookingCreateDto $booking): ?InsuranceEligibilityCriteria
{
// Early return if travel dates are missing - cannot evaluate any criteria
$travelStartDate = $booking->travel->dateFrom;
$travelEndDate = $booking->travel->dateTo;
-135
View File
@@ -1,135 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Service;
use App\BusProNet\Model\Insurance;
/**
* Resolves insurance types for both individual insurances and packages.
*
* This service provides consistent type resolution by mapping insurance subtypes
* to standardized type constants. For packages, it analyzes contained insurances
* to determine the dominant (non-deductible) type and applies family variants
* based on the familyInsurance flag.
*/
class InsuranceTypeResolver
{
public const TRAVEL_CANCELLATION = 'TRAVEL_CANCELLATION';
public const TRAVEL_CANCELLATION_FAMILY = 'TRAVEL_CANCELLATION_FAMILY';
public const TRAVEL_PROTECTION = 'TRAVEL_PROTECTION';
public const TRAVEL_PROTECTION_FAMILY = 'TRAVEL_PROTECTION_FAMILY';
public const DEDUCTIBLE = 'DEDUCTIBLE';
/**
* Resolves the standardized type for an insurance or package.
*
* @param Insurance $insurance The insurance to resolve the type for
*
* @return string|null The resolved type constant or null if unresolvable
*/
public function resolveType(Insurance $insurance): ?string
{
if (!$insurance->package) {
return $this->mapSubtypeToType($insurance->subType, $insurance->familyInsurance);
}
return $this->resolvePackageType($insurance);
}
/**
* Resolves the type for an insurance package by analyzing contained insurances.
*
* @param Insurance $package The package to analyze
*
* @return string|null The resolved type or null if no primary type found
*/
private function resolvePackageType(Insurance $package): ?string
{
// Get primary (non-deductible) insurance type from contained insurances
$primaryType = null;
foreach ($package->containedInsurances as $contained) {
$baseType = $this->mapSubtypeToBaseType($contained->subType);
if ($baseType && self::DEDUCTIBLE !== $baseType) {
$primaryType = $baseType;
break;
}
}
// Apply family suffix using package's familyInsurance flag
return $primaryType ? $primaryType.($package->familyInsurance ? '_FAMILY' : '') : null;
}
/**
* Maps a subtype to a full type including family variant.
*
* @param string|null $subtype The subtype to map
* @param bool $isFamily Whether this is a family insurance
*
* @return string|null The mapped type or null if unmappable
*/
private function mapSubtypeToType(?string $subtype, bool $isFamily): ?string
{
$baseType = $this->mapSubtypeToBaseType($subtype);
return $baseType ? $baseType.($isFamily ? '_FAMILY' : '') : null;
}
/**
* Maps a subtype to its base type constant.
*
* @param string|null $subtype The subtype to map
*
* @return string|null The base type constant or null if unmappable
*/
private function mapSubtypeToBaseType(?string $subtype): ?string
{
return match ($subtype) {
'RRV' => self::TRAVEL_CANCELLATION,
'PAK' => self::TRAVEL_PROTECTION,
'OHN' => self::DEDUCTIBLE,
default => null,
};
}
/**
* Gets all available insurance type constants.
*
* @return array<string> Array of all type constants
*/
public function getAllTypes(): array
{
return [
self::TRAVEL_CANCELLATION,
self::TRAVEL_CANCELLATION_FAMILY,
self::TRAVEL_PROTECTION,
self::TRAVEL_PROTECTION_FAMILY,
self::DEDUCTIBLE,
];
}
/**
* Checks if a type is a family variant.
*
* @param string $type The type to check
*
* @return bool True if the type is a family variant
*/
public function isFamilyType(string $type): bool
{
return str_ends_with($type, '_FAMILY');
}
/**
* Gets the base type from a family type.
*
* @param string $type The type to get the base for
*
* @return string The base type (without _FAMILY suffix)
*/
public function getBaseType(string $type): string
{
return str_replace('_FAMILY', '', $type);
}
}