feat: refactored accommodation booking status model

This commit is contained in:
Björn Fromme
2026-08-19 11:46:52 +02:00
parent e8accbb3ed
commit 5a3957e143
42 changed files with 1190 additions and 277 deletions
@@ -1,5 +1 @@
{#- Offen covers two situations that need different office action, told apart by the access
link: no link yet means the offer still has to be prepared, a link means the customer is
the one who has to act. Display only — both are the same status. -#}
{{- booking.status.label -}}
{%- if booking.open %} · {{ booking.accessLinkIssuedAt is not null ? 'Angebot versendet' : 'Angebot ausstehend' }}{% endif -%}
@@ -1,7 +1,7 @@
{% extends 'layout_admin.html.twig' %}
{% block content %}
<twig:page:heading>Buchung {{ booking.groupName }}</twig:page:heading>
<twig:page:heading>{{ booking.recordLabel }} {{ booking.groupName }}</twig:page:heading>
<p class="text-sm text-gray-500 mb-6">{{ booking.accommodation.name }}</p>
{% form_theme form 'forms_admin.html.twig' %}
@@ -39,9 +39,13 @@
{% endif %}
<h2 class="lg:col-span-2 text-base font-bold pt-2">Status & Rabatt</h2>
<div class="lg:col-span-2">
{{ form_row(form.status) }}
</div>
{# Read-only: the status only ever moves through a named action on the detail page,
so that it cannot be set without the email and timestamp that belong to it. #}
<p class="lg:col-span-2 text-sm">
<span class="font-medium">Status:</span>
{% include 'admin/accommodation_booking/_status_label.html.twig' %}
<span class="text-gray-500">· Herkunft: {{ booking.origin.label }}</span>
</p>
{% if booking.acceptedAt is not null %}
<p class="lg:col-span-2 text-xs text-gray-500">
Angenommen am {{ booking.acceptedAt | date('d.m.Y, H:i') }}
@@ -66,7 +66,7 @@
{% endif %}
</td>
<td>
{{ booking.type.label }} · {% include 'admin/accommodation_booking/_status_label.html.twig' %}
{{ booking.recordLabel }} · {% include 'admin/accommodation_booking/_status_label.html.twig' %}
</td>
<td>
{% set discounts = [] %}
@@ -3,7 +3,7 @@
{% block content %}
<div class="text-xl font-bold pb-4">
Neue Buchung
Neues Angebot
</div>
{{ form_start(form) }}
<div class="grid lg:grid-cols-2 gap-y-4 lg:gap-x-8">
@@ -15,9 +15,6 @@
{{ form_row(form.paxCount) }}
{{ form_row(form.minorsCount) }}
{{ form_row(form.childrenCount) }}
<div class="lg:col-span-2">
{{ form_row(form.status) }}
</div>
<div class="lg:col-span-2">
{{ form_row(form.email) }}
</div>
@@ -0,0 +1,16 @@
{% extends 'htmx_confirmation_modal.html.twig' %}
{% block title %}{{ booking.recordLabel }} absagen{% endblock %}
{% block content %}
<div>
Möchtest du {{ booking.acceptedAt is not null ? 'die Buchung' : 'das Angebot' }} für
<em>{{ booking.groupName }}</em> absagen?
{% if booking.open %}
Das versendete Angebot kann danach nicht mehr angenommen werden.
{% endif %}
Der Kunde wird nicht automatisch benachrichtigt.
</div>
{% endblock %}
{% block button_confirm %}Absagen{% endblock %}
@@ -7,7 +7,7 @@
{{ form_row(form.dateFrom) }}
{{ form_row(form.dateTo) }}
{{ form_row(form.status) }}
{{ form_row(form.type) }}
{{ form_row(form.origin) }}
<div class="lg:col-span-2">
{{ form_row(form.accommodation) }}
</div>
@@ -0,0 +1,12 @@
{% extends 'htmx_confirmation_modal.html.twig' %}
{% block title %}Angebot senden{% endblock %}
{% block content %}
<div>
Möchtest du das Angebot für <em>{{ booking.groupName }}</em> an <em>{{ booking.email }}</em> senden?
Der Kunde kann es anschließend über den Zugangslink annehmen.
</div>
{% endblock %}
{% block button_confirm %}Angebot senden{% endblock %}
@@ -2,7 +2,7 @@
{% block content %}
<twig:page:heading>
{{ booking.type.label }} · {% include 'admin/accommodation_booking/_status_label.html.twig' %}
{{ booking.recordLabel }} · {% include 'admin/accommodation_booking/_status_label.html.twig' %}
{{ booking.groupName }}
</twig:page:heading>
@@ -53,8 +53,8 @@
<dt class="font-medium">davon Kinder (4{{ booking.accommodation.maxAdolescentAge }} Jahre)</dt>
<dd>{{ booking.childrenCount }}</dd>
{% endif %}
<dt class="font-medium">Art</dt>
<dd>{{ booking.type.label }}</dd>
<dt class="font-medium">Herkunft</dt>
<dd>{{ booking.origin.label }}</dd>
<dt class="font-medium">Status</dt>
<dd>{% include 'admin/accommodation_booking/_status_label.html.twig' %}</dd>
{% if booking.acceptedAt is not null %}
@@ -177,6 +177,23 @@
{% endif %}
</div>
{% if booking.draft or booking.requested %}
<div class="mt-6 border-t border-gray-200 pt-6">
<h2 class="text-lg font-bold mb-2">Angebot</h2>
<p class="text-sm text-gray-500 mb-2">
Das Angebot wurde dem Kunden noch nicht zugestellt. Beim Versand wird der Zugangslink
erzeugt und die Buchung wartet anschließend auf die Annahme durch den Kunden.
</p>
<button type="button"
class="button button--primary button--small"
hx-get="{{ path('app_admin_accommodationbooking_send_offer', { id: booking.id }) }}"
hx-target="body"
hx-swap="beforeend">
Angebot per E-Mail senden
</button>
</div>
{% endif %}
{% if booking.received %}
<div class="mt-6 border-t border-gray-200 pt-6">
<h2 class="text-lg font-bold mb-2">Bestätigung</h2>
@@ -238,6 +255,15 @@
zurück
</a>
<div class="flex items-center gap-2">
{% if not booking.confirmed and not booking.discarded %}
<button type="button"
class="button button--warning button--small"
hx-get="{{ path('app_admin_accommodationbooking_discard', { id: booking.id }) }}"
hx-target="body"
hx-swap="beforeend">
Absagen
</button>
{% endif %}
{% if booking.confirmed %}
<a href="{{ path('app_admin_accommodationbooking_pdf', { 'id': booking.id }) }}" class="button button--secondary button--small">
PDF herunterladen
@@ -2,7 +2,7 @@
{% block body %}
<h1>
Neue Unterkunfts{% if booking.inquiry %}anfrage{% else %}buchung{% endif %}
Neue Unterkunfts{% if booking.directBooking %}buchung{% else %}anfrage{% endif %}
</h1>
{% if accessLink %}
+2 -2
View File
@@ -61,7 +61,7 @@
{% if booking.boardServiceLabel or booking.additionalServices | length > 0 %}
<div>
<h2 class="text-xl font-bold mb-2">
{{ booking.acceptedAt is not null ? 'Gebuchte' : 'Angefragte' }} Leistungen
{{ booking.acceptedAt is not null ? 'Gebuchte' : 'Angebotene' }} Leistungen
</h2>
<ul class="list-disc pl-4">
{% if booking.boardServiceLabel %}
@@ -74,7 +74,7 @@
</div>
{% endif %}
{% if booking.inquiry and booking.open %}
{% if booking.open %}
<div>
<button type="button"
class="button button--primary w-full"
+2 -2
View File
@@ -1,6 +1,6 @@
{% extends 'layout.html.twig' %}
{% block title %}{{ resultType == 'booking' ? 'Buchung erfolgreich' : 'Anfrage erfolgreich' }}{% endblock %}
{% block title %}{{ resultType == 'direct' ? 'Buchung erfolgreich' : 'Anfrage erfolgreich' }}{% endblock %}
{% block background %}bg-outer bg-outer--summer{% endblock %}
@@ -10,7 +10,7 @@
level: 'success',
title: 'Vielen Dank!',
messages: [
resultType == 'booking'
resultType == 'direct'
? 'Deine Buchung ist bei uns eingegangen. Sobald sie geprüft ist, erhälst du eine Bestätigung per E-Mail.'
: 'Deine Anfrage ist bei uns eingegangen. Wir melden uns so schnell wie möglich bei dir.'
]
@@ -2,7 +2,7 @@
<html lang="de">
<head>
<meta charset="utf-8">
<title>Buchung {{ booking.id }} {{ booking.groupName }}</title>
<title>{{ booking.recordLabel }} {{ booking.id }} {{ booking.groupName }}</title>
<style>
@page { size: A4 portrait; margin: 16mm 15mm; }
@@ -52,7 +52,7 @@
</tr>
</table>
<h1>{{ booking.type.label }} · {{ booking.groupName }}</h1>
<h1>{{ booking.recordLabel }} · {{ booking.groupName }}</h1>
<table class="columns">
<tr>
@@ -90,7 +90,6 @@
{% if booking.childrenCount > 0 %}
<tr><th>davon Kinder (4{{ booking.accommodation.maxAdolescentAge }} J.)</th><td>{{ booking.childrenCount }}</td></tr>
{% endif %}
<tr><th>Art</th><td>{{ booking.type.label }}</td></tr>
</table>
</td>
</tr>