wip: improved refresh logic

This commit is contained in:
Björn Fromme
2026-03-16 11:59:10 +01:00
parent 36fe4c9e9a
commit 3063a7c05f
5 changed files with 95 additions and 3 deletions
@@ -46,6 +46,10 @@ class CreateStep2Controller extends AbstractController
// Ensure correct number of participants
$this->ensureCorrectNumberOfParticipants($bookingCreateDto);
$participantsCount = $this->getParticipantsCount($bookingCreateDto);
// Pre-select mandatory services for participants with birth dates
$this->bookingService->preselectMandatoryServices($bookingCreateDto);
$this->bookingService->saveBookingCreateDto($request, $bookingCreateDto);
$form = $this->createForm(BookingCreateStep2Type::class, $bookingCreateDto, [
@@ -94,6 +98,16 @@ class CreateStep2Controller extends AbstractController
]);
$form->handleRequest($request);
// Pre-select mandatory services after form processing but before pricing calculation
$this->bookingService->preselectMandatoryServices($bookingCreateDto);
// Recreate the form with the updated DTO that includes mandatory services
$form = $this->createForm(BookingCreateStep2Type::class, $bookingCreateDto, [
'attr' => ['novalidate' => 'novalidate'],
'validation_groups' => false,
]);
$this->bookingService->saveBookingCreateDto($request, $bookingCreateDto);
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto);
@@ -134,9 +134,8 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
$attributes = [];
// Pre-select and make readonly for mandatory services
// Make readonly for mandatory services (pre-selection handled by service layer)
if (true === $service->mandatory) {
$attributes['checked'] = true;
$attributes['readonly'] = true;
$attributes['class'] = 'text-pink';
$attributes['title'] = 'Diese Leistung ist nicht abwählbar';
@@ -286,6 +286,12 @@ class BookingPriceCalculatorService
}
$subType = $serviceData['subType'] ?? 'other';
// 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
}
$isDiscount = $serviceData['totalPrice'] < 0;
// Create separate buckets for positive costs and discounts
@@ -332,9 +338,10 @@ class BookingPriceCalculatorService
Constants::TOKEN_ADDITIONAL => 'Zusatzleistungen',
Constants::TOKEN_BOARD => 'Verpflegung',
'transportation' => 'Beförderung',
'rentals' => 'Leihmaterial', // Normalized rental subtype
];
// Handle rentals array
// Handle rentals array (keep for backward compatibility with non-normalized subtypes)
if (true === in_array($subType, Constants::TOKEN_RENTALS, true)) {
return 'Leihmaterial';
}
+54
View File
@@ -266,4 +266,58 @@ class BookingService
return $oldSnapshot !== $newSnapshot;
}
/**
* Pre-selects mandatory services for all participants in the booking DTO.
*
* This method ensures that mandatory services are selected before form rendering
* and pricing calculations, resolving timing issues where mandatory services
* were only selected during form rendering via choice_attr callbacks.
*
* @param BookingCreateDto $bookingDto The booking DTO to update with mandatory services
*/
public function preselectMandatoryServices(BookingCreateDto $bookingDto): void
{
$additionalServices = $bookingDto->travel->getAdditionalServicesBySubTypes(\App\BusProNet\Constants::TOKEN_ADDITIONAL);
$mandatoryServices = array_filter($additionalServices, fn ($service) => true === $service->mandatory);
// Pre-select mandatory services for each participant
foreach ($bookingDto->participants as $participant) {
if (null === $participant->dateOfBirth) {
continue; // Skip participants without age information
}
// Get age-appropriate mandatory services for this participant
$ageAppropriateServices = array_filter($mandatoryServices, function ($service) use ($bookingDto, $participant) {
// Use the age evaluator service to check if service is appropriate for participant age
if (null === $service->ageFrom && null === $service->ageTo) {
return true; // No age restrictions
}
$age = $participant->dateOfBirth->diff($bookingDto->travel->dateFrom)->y;
if (null !== $service->ageFrom && $age < $service->ageFrom) {
return false;
}
if (null !== $service->ageTo && $age > $service->ageTo) {
return false;
}
return true;
});
// Add mandatory services to current selections
$currentSelections = $participant->additionalServices ?? [];
$currentServiceIds = array_map(fn ($service) => $service->id, $currentSelections);
foreach ($ageAppropriateServices as $mandatoryService) {
if (false === in_array($mandatoryService->id, $currentServiceIds, true)) {
$currentSelections[] = $mandatoryService;
}
}
$participant->additionalServices = $currentSelections;
}
}
}
+18
View File
@@ -58,6 +58,24 @@
{{ form_row(participant.remarksRoom) }}
{% endif %}
</div>
{# Services hint - shown when date of birth is missing #}
{% set participantData = participant.vars.data %}
{% set hasDateOfBirth = participantData and participantData.dateOfBirth %}
{% if not hasDateOfBirth %}
<div class="mb-4 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<div class="flex items-center">
<svg class="w-5 h-5 text-blue-600 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path>
</svg>
<p class="text-sm text-blue-800">
Zusatzleistungen sind erst nach Angabe des Geburtsdatums buchbar
</p>
</div>
</div>
{% endif %}
<div class="grid grid-cols-2 gap-4">
{% if participant.skiPass is defined %}
{{ form_row(participant.skiPass, {