wip: insurance booking phases 1 and 2

This commit is contained in:
Björn Fromme
2025-09-26 16:34:32 +02:00
parent bd7b70e465
commit 0ceabe465b
8 changed files with 1109 additions and 4 deletions
+3
View File
@@ -25,6 +25,9 @@ class Insurance
#[Groups(['api:single', 'api:list'])]
public ?string $label = null;
#[Groups(['api:single', 'api:list'])]
public ?string $subType = null;
#[Groups(['api:single', 'api:list'])]
public ?float $price = null;
@@ -74,6 +74,7 @@ class InsuranceParser extends AbstractParser
$insurance->id = $isPackage ? $idValue : (int) $idValue;
$insurance->code = $node->attr('code');
$insurance->label = $node->attr('bezeichnung');
$insurance->subType = $node->attr('unterart');
$insurance->price = $node->attr('preis') ?
$this->stringToFloat($node->attr('preis')) : null;
$insurance->familyInsurance = $this->stringToBool($node->attr('familienversicherung'));
+6 -4
View File
@@ -108,21 +108,23 @@ class ParticipantDto
}
/**
* Calculates the participant's current age in complete years.
* Calculates the participant's age in complete years.
*
* Uses the same logic as existing age evaluators in the system
* for consistency across age-related calculations.
*
* @param \DateTimeImmutable|null $referenceDate The date to calculate age at (defaults to current date)
*
* @return int|null The calculated age in complete years, or null if no birth date
*/
public function getAge(): ?int
public function getAge(?\DateTimeImmutable $referenceDate = null): ?int
{
if (null === $this->dateOfBirth) {
return null;
}
$today = new \DateTimeImmutable();
$referenceDate = $referenceDate ?? new \DateTimeImmutable();
return $this->dateOfBirth->diff($today)->y;
return $this->dateOfBirth->diff($referenceDate)->y;
}
}
+135
View File
@@ -0,0 +1,135 @@
<?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);
}
}