wip: implement transportation, pickups and parking

This commit is contained in:
Björn Fromme
2025-09-02 19:32:02 +02:00
parent 605b6ca64c
commit 21054f0c45
15 changed files with 1497 additions and 190 deletions
@@ -227,7 +227,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
$this->fieldOptionProviders['pickupOutbound'] = fn (BookingDtoInterface $bookingDto, int $participantIndex, array $options = []) => [
'label' => 'Zustieg Hinfahrt',
'choices' => $bookingDto->travel->pickupsTo,
'choice_label' => fn (Pickup $pickup) => $this->formatPickupLabel($pickup),
'choice_label' => fn (?Pickup $pickup) => $this->formatPickupLabelWithPrice($pickup),
'choice_value' => 'id',
'expanded' => false, // Dropdown for pickups
'multiple' => false,
@@ -237,24 +237,20 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// Inbound Pickup (conditional - only shown when inbound transportation is bus)
$this->fieldOptionProviders['pickupInbound'] = fn (BookingDtoInterface $bookingDto, int $participantIndex, array $options = []) => [
'label' => 'Zustieg Rückfahrt',
'label' => 'Ausstieg Rückfahrt',
'choices' => $bookingDto->travel->pickupsFro,
'choice_label' => fn (Pickup $pickup) => $this->formatPickupLabel($pickup),
'choice_label' => fn (?Pickup $pickup) => $this->formatPickupLabelWithPrice($pickup),
'choice_value' => 'id',
'expanded' => false,
'multiple' => false,
'required' => true,
'placeholder' => 'Zustieg auswählen',
'placeholder' => 'Ausstieg auswählen',
];
// Parking (conditional - only shown when at least one transportation direction is PKW)
// Parking (conditional - only shown when outbound transportation is PKW)
// Simple checkbox since there's only ever one parking type
$this->fieldOptionProviders['parking'] = fn (BookingDtoInterface $bookingDto, int $participantIndex, array $options = []) => [
'label' => 'Parkplatz',
'choices' => $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING, true),
'choice_label' => fn (?Service $service) => $this->formatServiceLabelWithPrice($service),
'choice_value' => 'id',
'expanded' => true,
'multiple' => false,
'label' => $this->getParkingCheckboxLabel($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING, true)),
'required' => false,
];
@@ -287,6 +283,11 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
return $service->label;
}
if ($service->price < 0) {
// Negative prices are discounts
return sprintf('%s (-%s€ Rabatt)', $service->label, number_format(abs($service->price), 2, ',', '.'));
}
return sprintf('%s (€%s)', $service->label, number_format($service->price, 2, ',', '.'));
}
@@ -307,16 +308,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
{
$label = $service->label;
// Add transportation type indicator
$typeIndicator = match ($service->subType) {
'BUS' => '🚌',
'PKW' => '🚗',
default => '',
};
if ($typeIndicator) {
$label = $typeIndicator.' '.$label;
}
// Transportation type indicators removed for cleaner labels
// Add pricing with discount indication
if (null !== $service->price) {
@@ -357,6 +349,47 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
return $label;
}
private function formatPickupLabelWithPrice(?Pickup $pickup): string
{
if (null === $pickup) {
return '';
}
$label = $this->formatPickupLabel($pickup);
if (null === $pickup->price || 0.0 === $pickup->price) {
return $label;
}
if ($pickup->price < 0) {
// Negative prices are discounts
return sprintf('%s (-%s€ Rabatt)', $label, number_format(abs($pickup->price), 2, ',', '.'));
}
return sprintf('%s (€%s)', $label, number_format($pickup->price, 2, ',', '.'));
}
/**
* Gets the parking checkbox label with pricing information.
*
* Creates a checkbox label for the single parking service including pricing.
* Since there's only ever one parking type, we take the first available service.
*
* @param array $parkingServices Array of available parking services
*
* @return string The formatted checkbox label with pricing
*/
private function getParkingCheckboxLabel(array $parkingServices): string
{
if (empty($parkingServices)) {
return 'Parkplatz';
}
$parkingService = reset($parkingServices); // Get the first (and only) parking service
return $this->formatServiceLabelWithPrice($parkingService);
}
/**
* Filters services based on participant's age constraints.
*