feat: extended pricing breakdown on confirmation page
This commit is contained in:
@@ -8,7 +8,11 @@
|
|||||||
1. **Step 1**: Room selection and dates (`Create\Step1Controller`)
|
1. **Step 1**: Room selection and dates (`Create\Step1Controller`)
|
||||||
2. **Step 2**: Participant details with card-based UI (`Create\Step2Controller`)
|
2. **Step 2**: Participant details with card-based UI (`Create\Step2Controller`)
|
||||||
3. **Step 3**: Payment method selection (`Create\Step3Controller`)
|
3. **Step 3**: Payment method selection (`Create\Step3Controller`)
|
||||||
4. **Step 4**: Final confirmation and submission to BPN API (`Create\Step4Controller`)
|
4. **Step 4**: Final confirmation with comprehensive pricing breakdown and submission to BPN API (`Create\Step4Controller`)
|
||||||
|
- Displays complete pricing breakdown by category (rooms, services grouped by type)
|
||||||
|
- Shows per-participant total pricing in card headers
|
||||||
|
- Displays individual service prices inline with each booked service
|
||||||
|
- Three-level pricing transparency: aggregate, participant, and service-level
|
||||||
5. **Edit Flow**: Similar card-based UI for existing bookings (`Edit\IndexController`)
|
5. **Edit Flow**: Similar card-based UI for existing bookings (`Edit\IndexController`)
|
||||||
|
|
||||||
### Card-Based UI Pattern (Production)
|
### Card-Based UI Pattern (Production)
|
||||||
@@ -46,7 +50,12 @@
|
|||||||
|
|
||||||
### Service Layer (`src/Service/`)
|
### Service Layer (`src/Service/`)
|
||||||
- `BookingService` - Core booking workflow
|
- `BookingService` - Core booking workflow
|
||||||
- `BookingPriceCalculatorService` - Real-time pricing
|
- `BookingPriceCalculatorService` - Comprehensive pricing calculations
|
||||||
|
- `getPricingBreakdown()` - Complete pricing breakdown with rooms and services grouped by type
|
||||||
|
- `calculateAllParticipantIndividualPrices()` - Per-participant total pricing
|
||||||
|
- `calculateIndividualParticipantPrice()` - Single participant total (room + all services)
|
||||||
|
- `calculateServicePricing()` - Service aggregation with grouping by subtype
|
||||||
|
- Powers sidebar summary and Step 4 confirmation pricing display
|
||||||
- `BookingFingerprintService` - Dirty state detection for edit mode
|
- `BookingFingerprintService` - Dirty state detection for edit mode
|
||||||
- `TravelDataService` - API integration and caching
|
- `TravelDataService` - API integration and caching
|
||||||
- `ParticipantCardDataService` - Card display data
|
- `ParticipantCardDataService` - Card display data
|
||||||
@@ -285,7 +294,12 @@ Edit mode session requires proper cleanup to prevent dirty state persistence:
|
|||||||
- `Step1Controller.php` - Room selection and dates
|
- `Step1Controller.php` - Room selection and dates
|
||||||
- `Step2Controller.php` - Participant details with card-based UI
|
- `Step2Controller.php` - Participant details with card-based UI
|
||||||
- `Step3Controller.php` - Payment method selection
|
- `Step3Controller.php` - Payment method selection
|
||||||
- `Step4Controller.php` - Final confirmation and API submission
|
- `Step4Controller.php` - Final confirmation with comprehensive pricing display and API submission
|
||||||
|
- Integrates `BookingPriceCalculatorService` for complete pricing breakdown
|
||||||
|
- Calculates per-participant individual prices via `calculateAllParticipantIndividualPrices()`
|
||||||
|
- Template displays three-level pricing: aggregate breakdown, per-participant totals, and inline service prices
|
||||||
|
- All service prices shown in blue (text-blue-700) with German formatting
|
||||||
|
- Zero prices hidden per project standards
|
||||||
- `SuccessController.php` - Success page after booking completion
|
- `SuccessController.php` - Success page after booking completion
|
||||||
|
|
||||||
**Edit Namespace** (`src/Controller/Booking/Edit/`):
|
**Edit Namespace** (`src/Controller/Booking/Edit/`):
|
||||||
@@ -312,7 +326,12 @@ Edit mode session requires proper cleanup to prevent dirty state persistence:
|
|||||||
- `templates/booking/create/step_1.html.twig` - Room selection
|
- `templates/booking/create/step_1.html.twig` - Room selection
|
||||||
- `templates/booking/create/step_2.html.twig` - Participant cards
|
- `templates/booking/create/step_2.html.twig` - Participant cards
|
||||||
- `templates/booking/create/step_3.html.twig` - Payment method
|
- `templates/booking/create/step_3.html.twig` - Payment method
|
||||||
- `templates/booking/create/step_4.html.twig` - Confirmation
|
- `templates/booking/create/step_4.html.twig` - Final confirmation with comprehensive pricing display
|
||||||
|
- **Aggregate pricing breakdown**: Rooms and services grouped by type with totals
|
||||||
|
- **Per-participant cards**: Individual total price in header, all personal details and service selections
|
||||||
|
- **Inline service pricing**: Each service shows price in blue (€X,XX format) next to label
|
||||||
|
- **Payment summary**: Selected payment method and bank details (if debit)
|
||||||
|
- **Confirmation checkbox**: Final acceptance before API submission
|
||||||
- `templates/booking/create/success.html.twig` - Success page
|
- `templates/booking/create/success.html.twig` - Success page
|
||||||
- `templates/booking/create/error.html.twig` - Error page
|
- `templates/booking/create/error.html.twig` - Error page
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
|||||||
use App\Form\BookingCreateStep4Type;
|
use App\Form\BookingCreateStep4Type;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
|
use App\Service\BookingPriceCalculatorService;
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
@@ -30,6 +31,7 @@ class Step4Controller extends AbstractController
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly BookingService $bookingService,
|
private readonly BookingService $bookingService,
|
||||||
|
private readonly BookingPriceCalculatorService $priceCalculator,
|
||||||
private readonly ApiClient $apiClient,
|
private readonly ApiClient $apiClient,
|
||||||
private readonly LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
@@ -118,6 +120,7 @@ class Step4Controller extends AbstractController
|
|||||||
'bookingCreateDto' => $bookingCreateDto,
|
'bookingCreateDto' => $bookingCreateDto,
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
...$this->getSummaryVariables($bookingCreateDto),
|
...$this->getSummaryVariables($bookingCreateDto),
|
||||||
|
'participantPrices' => $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingCreateDto),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,18 +25,74 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Rooms Summary #}
|
{# Detailed Pricing Breakdown #}
|
||||||
<div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200">
|
<div class="mb-8 p-6 bg-blue-50 rounded-lg border border-blue-200">
|
||||||
<h3 class="text-xl font-semibold mb-4">Zimmer / Unterkünfte</h3>
|
<h3 class="text-xl font-semibold mb-6 text-blue-900">Preisübersicht</h3>
|
||||||
|
|
||||||
|
{# Rooms Section #}
|
||||||
{% if pricingData.rooms is not empty %}
|
{% if pricingData.rooms is not empty %}
|
||||||
<ul class="space-y-2">
|
<div class="mb-6 pb-6 border-b border-blue-200">
|
||||||
{% for roomPricing in pricingData.rooms %}
|
<h4 class="font-semibold text-lg mb-3 text-blue-800">Unterkunft</h4>
|
||||||
<li class="flex justify-between">
|
<div class="space-y-2">
|
||||||
<span>{{ roomPricing.quantity }}x {{ roomPricing.label }}</span>
|
{% for roomPricing in pricingData.rooms %}
|
||||||
<span class="font-semibold">{{ roomPricing.totalPrice|number_format(2, ',', '.') }} €</span>
|
<div class="flex justify-between items-start">
|
||||||
</li>
|
<div class="text-sm text-gray-700">
|
||||||
|
<span class="font-medium">{{ roomPricing.quantity }}x {{ roomPricing.label }}</span>
|
||||||
|
{% if assignmentCounts is defined and assignmentCounts[roomPricing.roomId] is defined %}
|
||||||
|
<span class="block text-xs text-gray-600">{{ assignmentCounts[roomPricing.roomId] }} Person(en) belegt</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<div class="text-gray-900 font-semibold">
|
||||||
|
€{{ roomPricing.totalPrice|number_format(2, ',', '.') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-600">
|
||||||
|
€{{ roomPricing.unitPrice|number_format(2, ',', '.') }} pro Person
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Services Section #}
|
||||||
|
{% if pricingData.services is not empty %}
|
||||||
|
<div class="mb-6 pb-6 border-b border-blue-200">
|
||||||
|
<h4 class="font-semibold text-lg mb-3 text-blue-800">Leistungen</h4>
|
||||||
|
{% for serviceGroup in pricingData.services %}
|
||||||
|
<div class="mb-4 last:mb-0">
|
||||||
|
<h5 class="font-medium text-sm text-gray-700 mb-2 uppercase tracking-wide">{{ serviceGroup.groupName }}</h5>
|
||||||
|
<div class="space-y-1.5 ml-4">
|
||||||
|
{% for servicePricing in serviceGroup.services %}
|
||||||
|
<div class="flex justify-between items-center text-sm">
|
||||||
|
<span class="text-gray-700">
|
||||||
|
{{ servicePricing.participantCount }}x {{ servicePricing.label }}
|
||||||
|
{% if servicePricing.unitPrice is not null %}
|
||||||
|
<span class="text-xs text-gray-500">(€{{ servicePricing.unitPrice|number_format(2, ',', '.') }} pro Person)</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<span class="font-medium text-gray-900">
|
||||||
|
€{{ servicePricing.totalPrice|number_format(2, ',', '.') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Grand Total #}
|
||||||
|
{% if pricingData.grandTotal is defined and pricingData.grandTotal > 0 %}
|
||||||
|
<div class="pt-4">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="font-bold text-xl text-blue-900">Gesamtpreis:</span>
|
||||||
|
<span class="font-bold text-2xl text-blue-900">
|
||||||
|
€{{ pricingData.grandTotal|number_format(2, ',', '.') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -45,10 +101,18 @@
|
|||||||
<h3 class="text-xl font-semibold mb-4">Teilnehmer ({{ participantsCount }})</h3>
|
<h3 class="text-xl font-semibold mb-4">Teilnehmer ({{ participantsCount }})</h3>
|
||||||
{% for participant in bookingCreateDto.participants %}
|
{% for participant in bookingCreateDto.participants %}
|
||||||
<div class="mb-6 pb-6 {% if not loop.last %}border-b border-gray-300{% endif %}">
|
<div class="mb-6 pb-6 {% if not loop.last %}border-b border-gray-300{% endif %}">
|
||||||
<h4 class="font-semibold text-lg mb-3">
|
<div class="flex justify-between items-start mb-3">
|
||||||
{{ participant.firstName }} {{ participant.lastName }}
|
<h4 class="font-semibold text-lg">
|
||||||
{% if loop.first %}<span class="text-sm text-gray-600">(Anmelder)</span>{% endif %}
|
{{ participant.firstName }} {{ participant.lastName }}
|
||||||
</h4>
|
{% if loop.first %}<span class="text-sm text-gray-600">(Anmelder)</span>{% endif %}
|
||||||
|
</h4>
|
||||||
|
{% if participantPrices is defined and participantPrices[loop.index0] is defined %}
|
||||||
|
<div class="text-right">
|
||||||
|
<div class="text-xs text-gray-600 uppercase tracking-wide">Preis</div>
|
||||||
|
<div class="font-bold text-lg text-blue-700">€{{ participantPrices[loop.index0]|number_format(2, ',', '.') }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<dl class="grid grid-cols-2 gap-4 text-sm">
|
<dl class="grid grid-cols-2 gap-4 text-sm">
|
||||||
{# Personal Data #}
|
{# Personal Data #}
|
||||||
@@ -102,7 +166,12 @@
|
|||||||
{% if assignedRoom %}
|
{% if assignedRoom %}
|
||||||
<div>
|
<div>
|
||||||
<dt class="text-gray-600 font-semibold">Zimmer</dt>
|
<dt class="text-gray-600 font-semibold">Zimmer</dt>
|
||||||
<dd>{{ assignedRoom.label }}</dd>
|
<dd>
|
||||||
|
{{ assignedRoom.label }}
|
||||||
|
{% if assignedRoom.price is not null and assignedRoom.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ assignedRoom.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -118,13 +187,23 @@
|
|||||||
{% if participant.transportationOutbound %}
|
{% if participant.transportationOutbound %}
|
||||||
<div>
|
<div>
|
||||||
<dt class="text-gray-600 font-semibold">Anreise</dt>
|
<dt class="text-gray-600 font-semibold">Anreise</dt>
|
||||||
<dd>{{ participant.transportationOutbound.label }}</dd>
|
<dd>
|
||||||
|
{{ participant.transportationOutbound.label }}
|
||||||
|
{% if participant.transportationOutbound.price is not null and participant.transportationOutbound.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.transportationOutbound.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if participant.transportationInbound %}
|
{% if participant.transportationInbound %}
|
||||||
<div>
|
<div>
|
||||||
<dt class="text-gray-600 font-semibold">Abreise</dt>
|
<dt class="text-gray-600 font-semibold">Abreise</dt>
|
||||||
<dd>{{ participant.transportationInbound.label }}</dd>
|
<dd>
|
||||||
|
{{ participant.transportationInbound.label }}
|
||||||
|
{% if participant.transportationInbound.price is not null and participant.transportationInbound.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.transportationInbound.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -132,7 +211,12 @@
|
|||||||
{% if participant.pickup %}
|
{% if participant.pickup %}
|
||||||
<div>
|
<div>
|
||||||
<dt class="text-gray-600 font-semibold">Zu- und Ausstieg</dt>
|
<dt class="text-gray-600 font-semibold">Zu- und Ausstieg</dt>
|
||||||
<dd>{{ participant.pickup.label }}</dd>
|
<dd>
|
||||||
|
{{ participant.pickup.label }}
|
||||||
|
{% if participant.pickup.price is not null and participant.pickup.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.pickup.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -140,7 +224,12 @@
|
|||||||
{% if participant.parking %}
|
{% if participant.parking %}
|
||||||
<div>
|
<div>
|
||||||
<dt class="text-gray-600 font-semibold">Parkplatz</dt>
|
<dt class="text-gray-600 font-semibold">Parkplatz</dt>
|
||||||
<dd>Ja</dd>
|
<dd>
|
||||||
|
Ja
|
||||||
|
{% if participant.parkingService is not null and participant.parkingService.price is not null and participant.parkingService.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.parkingService.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if participant.licensePlate %}
|
{% if participant.licensePlate %}
|
||||||
@@ -157,7 +246,12 @@
|
|||||||
<dd>
|
<dd>
|
||||||
<ul class="list-disc list-inside">
|
<ul class="list-disc list-inside">
|
||||||
{% for boardItem in participant.board %}
|
{% for boardItem in participant.board %}
|
||||||
<li>{{ boardItem.label }}</li>
|
<li>
|
||||||
|
{{ boardItem.label }}
|
||||||
|
{% if boardItem.price is not null and boardItem.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ boardItem.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -168,7 +262,12 @@
|
|||||||
{% if participant.skiPass %}
|
{% if participant.skiPass %}
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<dt class="text-gray-600 font-semibold">Skipass</dt>
|
<dt class="text-gray-600 font-semibold">Skipass</dt>
|
||||||
<dd>{{ participant.skiPass.label }}</dd>
|
<dd>
|
||||||
|
{{ participant.skiPass.label }}
|
||||||
|
{% if participant.skiPass.price is not null and participant.skiPass.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.skiPass.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -179,7 +278,12 @@
|
|||||||
<dd>
|
<dd>
|
||||||
<ul class="list-disc list-inside">
|
<ul class="list-disc list-inside">
|
||||||
{% for rental in participant.rentals %}
|
{% for rental in participant.rentals %}
|
||||||
<li>{{ rental.label }}</li>
|
<li>
|
||||||
|
{{ rental.label }}
|
||||||
|
{% if rental.price is not null and rental.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ rental.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -190,7 +294,12 @@
|
|||||||
{% if participant.rentalInsuranceSelected and participant.rentalInsurance %}
|
{% if participant.rentalInsuranceSelected and participant.rentalInsurance %}
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<dt class="text-gray-600 font-semibold">Leihmaterial-Versicherung</dt>
|
<dt class="text-gray-600 font-semibold">Leihmaterial-Versicherung</dt>
|
||||||
<dd>{{ participant.rentalInsurance.label }}</dd>
|
<dd>
|
||||||
|
{{ participant.rentalInsurance.label }}
|
||||||
|
{% if participant.rentalInsurance.price is not null and participant.rentalInsurance.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.rentalInsurance.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -215,7 +324,12 @@
|
|||||||
<dd>
|
<dd>
|
||||||
<ul class="list-disc list-inside">
|
<ul class="list-disc list-inside">
|
||||||
{% for course in participant.courses %}
|
{% for course in participant.courses %}
|
||||||
<li>{{ course.label }}</li>
|
<li>
|
||||||
|
{{ course.label }}
|
||||||
|
{% if course.price is not null and course.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ course.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -229,7 +343,12 @@
|
|||||||
<dd>
|
<dd>
|
||||||
<ul class="list-disc list-inside">
|
<ul class="list-disc list-inside">
|
||||||
{% for service in participant.additionalServices %}
|
{% for service in participant.additionalServices %}
|
||||||
<li>{{ service.label }}</li>
|
<li>
|
||||||
|
{{ service.label }}
|
||||||
|
{% if service.price is not null and service.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ service.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -240,7 +359,12 @@
|
|||||||
{% if participant.insurance %}
|
{% if participant.insurance %}
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<dt class="text-gray-600 font-semibold">Reiseversicherung</dt>
|
<dt class="text-gray-600 font-semibold">Reiseversicherung</dt>
|
||||||
<dd>{{ participant.insurance.label }}</dd>
|
<dd>
|
||||||
|
{{ participant.insurance.label }}
|
||||||
|
{% if participant.insurance.price is not null and participant.insurance.price != 0 %}
|
||||||
|
<span class="text-blue-700 font-semibold ml-1">(€{{ participant.insurance.price|number_format(2, ',', '.') }})</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
|
|||||||
Reference in New Issue
Block a user