wip: insurance booking in edit flow
This commit is contained in:
@@ -42,6 +42,7 @@ class Booking
|
||||
public array $pickupsOutbound = [];
|
||||
public array $pickupsInbound = [];
|
||||
public array $surcharges = [];
|
||||
public array $insurances = [];
|
||||
public ?int $invoiceNumber = null;
|
||||
public ?float $totalPrice = null;
|
||||
public ?string $travelInfoUrl = null;
|
||||
@@ -150,6 +151,24 @@ class Booking
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the insurance assigned to a specific participant.
|
||||
*
|
||||
* @param int $participantIndex The participant index (0-based)
|
||||
*
|
||||
* @return Insurance|null The assigned insurance or null if none assigned
|
||||
*/
|
||||
public function getInsuranceForParticipant(int $participantIndex): ?Insurance
|
||||
{
|
||||
foreach ($this->insurances as $insurance) {
|
||||
if (in_array($participantIndex, $insurance->mapping ?? [], true)) {
|
||||
return $insurance;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves ski pass for a specific participant.
|
||||
*
|
||||
|
||||
@@ -95,6 +95,16 @@ class Insurance
|
||||
#[Groups(['api:single', 'api:list'])]
|
||||
public array $containedInsuranceIds = [];
|
||||
|
||||
/**
|
||||
* @var array<int> Participant indices assigned to this insurance (booking data only)
|
||||
*/
|
||||
public array $mapping = [];
|
||||
|
||||
/**
|
||||
* @var array<int, float> Individual prices per participant index (booking data only)
|
||||
*/
|
||||
public array $individualPrice = [];
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->id;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Insurance;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
/**
|
||||
* Parses insurance data from booking XML responses.
|
||||
*
|
||||
* This parser handles the simplified insurance structure found in booking data,
|
||||
* which includes participant mappings and individual pricing.
|
||||
*/
|
||||
class BookingInsurancesParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): array
|
||||
{
|
||||
$insurances = [];
|
||||
|
||||
$result->each(function (Crawler $node) use (&$insurances) {
|
||||
$insurance = new Insurance();
|
||||
$insurance->id = (int) $node->attr('idversicherung');
|
||||
$insurance->label = $node->attr('bezeichnung');
|
||||
$insurance->price = $this->stringToFloat($node->attr('gesamtpreis'));
|
||||
|
||||
// Parse participant mapping (zuordnung attribute)
|
||||
$mapping = $this->stringToArray($node->attr('zuordnung'));
|
||||
$insurance->mapping = array_map(function ($index) {
|
||||
return (int) $index - 1;
|
||||
}, $mapping);
|
||||
|
||||
// Parse individual prices per participant
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat($price);
|
||||
},
|
||||
$this->stringToArray($node->attr('einzelpreis', ''), '/')
|
||||
);
|
||||
$insurance->individualPrice = array_combine($insurance->mapping, $individualPrices);
|
||||
|
||||
$insurances[$insurance->id] = $insurance;
|
||||
});
|
||||
|
||||
return $insurances;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ class BookingParser extends AbstractParser
|
||||
private readonly RoomsParser $roomsParser;
|
||||
private readonly PickupsParser $pickupsParser;
|
||||
private readonly SurchargesParser $surchargesParser;
|
||||
private readonly BookingInsurancesParser $insurancesParser;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -23,6 +24,7 @@ class BookingParser extends AbstractParser
|
||||
$this->roomsParser = new RoomsParser();
|
||||
$this->pickupsParser = new PickupsParser();
|
||||
$this->surchargesParser = new SurchargesParser();
|
||||
$this->insurancesParser = new BookingInsurancesParser();
|
||||
}
|
||||
|
||||
public function parse(Crawler $node): Booking
|
||||
@@ -101,6 +103,11 @@ class BookingParser extends AbstractParser
|
||||
$booking->surcharges = $this->surchargesParser->parse($surchargesData);
|
||||
}
|
||||
|
||||
$insurancesData = $node->filterXPath('//versicherungen/versicherung');
|
||||
if (0 < $insurancesData->count()) {
|
||||
$booking->insurances = $this->insurancesParser->parse($insurancesData);
|
||||
}
|
||||
|
||||
return $booking;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,10 @@ class BookingEditDto implements BookingDtoInterface
|
||||
$pickup = $booking->getPickupForParticipant($index);
|
||||
$participantData->pickup = $pickup;
|
||||
|
||||
// Insurance - get insurance for participant
|
||||
$insurance = $booking->getInsuranceForParticipant($index);
|
||||
$participantData->insurance = $insurance;
|
||||
|
||||
// Room assignment - extract from booking room mappings
|
||||
$room = $booking->getRoomForParticipant($index);
|
||||
$participantData->assignedRoomId = $room?->id;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form\Service\Condition;
|
||||
|
||||
use App\Form\Model\BookingDtoInterface;
|
||||
use App\Form\Model\BookingEditDto;
|
||||
use App\Form\Service\Contract\FieldConditionInterface;
|
||||
|
||||
/**
|
||||
* Condition that determines if insurance fields are editable based on booking and travel dates.
|
||||
*
|
||||
* Implements time-based mutability constraints for insurance booking in the edit flow:
|
||||
* - Standard case: Insurance editable up to 30 days before travel date
|
||||
* - Late booking case: If booking made < 30 days before travel, insurance editable up to 3 days after booking date
|
||||
*/
|
||||
class InsuranceMutabilityCondition implements FieldConditionInterface
|
||||
{
|
||||
private const DAYS_BEFORE_TRAVEL_THRESHOLD = 30;
|
||||
private const DAYS_AFTER_BOOKING_THRESHOLD = 3;
|
||||
|
||||
/**
|
||||
* Evaluates whether the insurance field should be readonly.
|
||||
*
|
||||
* Returns true if the field should be readonly (locked), false if editable.
|
||||
*
|
||||
* Logic:
|
||||
* 1. Always editable in create flow
|
||||
* 2. In edit flow, check standard case: editable if >= 30 days before travel
|
||||
* 3. In edit flow, check late booking case: editable if within 3 days of booking date
|
||||
* 4. Otherwise: readonly
|
||||
*
|
||||
* @param BookingDtoInterface $bookingDto The current booking data
|
||||
* @param int $participantIndex The participant index (unused for insurance mutability)
|
||||
* @param array<string, mixed> $formData Current form data (unused for insurance mutability)
|
||||
*
|
||||
* @return bool True if field should be readonly, false if editable
|
||||
*/
|
||||
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||
{
|
||||
// Only apply mutability constraints to edit flow
|
||||
if (!$bookingDto instanceof BookingEditDto) {
|
||||
return false; // Always editable in create flow
|
||||
}
|
||||
|
||||
$now = \Carbon\Carbon::now()->toDateTimeImmutable();
|
||||
$travelDate = $bookingDto->travel->dateFrom;
|
||||
$bookingDate = $bookingDto->booking->bookingDate;
|
||||
|
||||
// Calculate days until travel
|
||||
$daysUntilTravel = $now->diff($travelDate)->days;
|
||||
$isBeforeTravel = $now < $travelDate;
|
||||
|
||||
// Standard case: Editable if >= 30 days before travel
|
||||
if ($isBeforeTravel && $daysUntilTravel >= self::DAYS_BEFORE_TRAVEL_THRESHOLD) {
|
||||
return false; // Editable
|
||||
}
|
||||
|
||||
// Late booking case: Check if booking was made < 30 days before travel
|
||||
$daysFromBookingToTravel = $bookingDate->diff($travelDate)->days;
|
||||
$wasLateBooking = $daysFromBookingToTravel < self::DAYS_BEFORE_TRAVEL_THRESHOLD;
|
||||
|
||||
if ($wasLateBooking) {
|
||||
// Editable if within 3 days of booking date
|
||||
$daysSinceBooking = $bookingDate->diff($now)->days;
|
||||
|
||||
return $daysSinceBooking > self::DAYS_AFTER_BOOKING_THRESHOLD; // True = readonly (past threshold)
|
||||
}
|
||||
|
||||
// Default: Not editable (readonly)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field names that trigger re-evaluation of this condition.
|
||||
*
|
||||
* Insurance mutability is based on dates, not other form fields,
|
||||
* so no field dependencies are needed.
|
||||
*
|
||||
* @return string[] Empty array - no field dependencies
|
||||
*/
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable description of this condition.
|
||||
*
|
||||
* @return string Description of the insurance mutability logic
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return sprintf(
|
||||
'Insurance is not editable (>= %d days before travel or > %d days after late booking)',
|
||||
self::DAYS_BEFORE_TRAVEL_THRESHOLD,
|
||||
self::DAYS_AFTER_BOOKING_THRESHOLD
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user