From e5253f9adbc871eb9742c89b3e31ee955f479771 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Fri, 3 May 2024 17:21:20 +0200 Subject: [PATCH] Allow to cancel bookings --- deploy/cancel_booking.sql | 23 +++++++ pkg/booking/admin.go | 15 +++++ pkg/database/funcs.go | 5 ++ po/ca.po | 31 ++++++--- po/es.po | 31 ++++++--- po/fr.po | 31 ++++++--- revert/cancel_booking.sql | 7 ++ sqitch.plan | 1 + test/cancel_booking.sql | 89 +++++++++++++++++++++++++ verify/cancel_booking.sql | 7 ++ web/static/camper.css | 5 ++ web/templates/admin/booking/form.gohtml | 4 ++ 12 files changed, 216 insertions(+), 33 deletions(-) create mode 100644 deploy/cancel_booking.sql create mode 100644 revert/cancel_booking.sql create mode 100644 test/cancel_booking.sql create mode 100644 verify/cancel_booking.sql diff --git a/deploy/cancel_booking.sql b/deploy/cancel_booking.sql new file mode 100644 index 0000000..19adf30 --- /dev/null +++ b/deploy/cancel_booking.sql @@ -0,0 +1,23 @@ +-- Deploy camper:cancel_booking to pg +-- requires: roles +-- requires: schema_camper +-- requires: booking +-- requires: booking_campsite + +begin; + +set search_path to camper, public; + +create or replace function cancel_booking(bid integer) returns void as +$$ + delete from booking_campsite where booking_id = bid; + update booking set booking_status = 'cancelled' where booking_id = bid; +$$ + language sql +; + +revoke execute on function cancel_booking(integer) from public; +grant execute on function cancel_booking(integer) to employee; +grant execute on function cancel_booking(integer) to admin; + +commit; diff --git a/pkg/booking/admin.go b/pkg/booking/admin.go index 58e8a7e..1c008d3 100644 --- a/pkg/booking/admin.go +++ b/pkg/booking/admin.go @@ -484,6 +484,21 @@ func updateBooking(w http.ResponseWriter, r *http.Request, user *auth.User, comp } panic(err) } + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if len(r.Form["cancel"]) > 0 { + if err := conn.CancelBooking(r.Context(), bookingID); err != nil { + panic(err) + } + if bookingStatus == "created" { + httplib.Redirect(w, r, "/admin/prebookings", http.StatusSeeOther) + } else { + httplib.Redirect(w, r, "/admin/bookings", http.StatusSeeOther) + } + return + } processAdminBookingForm(w, r, user, company, conn, bookingID, func(ctx context.Context, tx *database.Tx, f *adminBookingForm) error { var err error _, err = tx.EditBookingFromPayment(ctx, slug, f.PaymentSlug.Val) diff --git a/pkg/database/funcs.go b/pkg/database/funcs.go index 46930f1..5f33f81 100644 --- a/pkg/database/funcs.go +++ b/pkg/database/funcs.go @@ -366,6 +366,11 @@ func (tx *Tx) EditBooking(ctx context.Context, bookingID int, customerName strin return err } +func (c *Conn) CancelBooking(ctx context.Context, bookingID int) error { + _, err := c.Exec(ctx, "select cancel_booking($1)", bookingID) + return err +} + func (c *Conn) CheckInGuests(ctx context.Context, bookingSlug string, guests []*CheckedInGuest) error { _, err := c.Exec(ctx, "select check_in_guests(booking_id, $2) from booking where slug = $1", bookingSlug, CheckedInGuestArray(guests)) return err diff --git a/po/ca.po b/po/ca.po index fb500fe..9c53976 100644 --- a/po/ca.po +++ b/po/ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2024-05-03 00:56+0200\n" +"POT-Creation-Date: 2024-05-03 17:19+0200\n" "PO-Revision-Date: 2024-02-06 10:04+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -2748,6 +2748,15 @@ msgctxt "action" msgid "Invoice Booking" msgstr "Factura la reserva" +#: web/templates/admin/booking/form.gohtml:58 +msgid "Are you sure you wish to cancel this booking?" +msgstr "Esteu segur de voler cancel·lar aquesta reserva?" + +#: web/templates/admin/booking/form.gohtml:59 +msgctxt "action" +msgid "Cancel booking" +msgstr "Cancel·la la reserva" + #: web/templates/admin/booking/checkin.gohtml:6 msgctxt "title" msgid "Check-in Booking" @@ -2933,7 +2942,7 @@ msgid "Email can not be empty." msgstr "No podeu deixar el correu-e en blanc." #: pkg/app/login.go:57 pkg/app/user.go:247 pkg/customer/admin.go:345 -#: pkg/company/admin.go:225 pkg/booking/admin.go:582 pkg/booking/public.go:593 +#: pkg/company/admin.go:225 pkg/booking/admin.go:597 pkg/booking/public.go:593 msgid "This email is not valid. It should be like name@domain.com." msgstr "Aquest correu-e no és vàlid. Hauria de ser similar a nom@domini.com." @@ -3144,7 +3153,7 @@ msgctxt "header" msgid "Children (aged 2 to 10)" msgstr "Mainada (entre 2 i 10 anys)" -#: pkg/campsite/admin.go:280 pkg/booking/admin.go:558 pkg/booking/public.go:177 +#: pkg/campsite/admin.go:280 pkg/booking/admin.go:573 pkg/booking/public.go:177 #: pkg/booking/public.go:232 msgid "Selected campsite type is not valid." msgstr "El tipus d’allotjament escollit no és vàlid." @@ -3196,12 +3205,12 @@ msgid "ID document number can not be empty." msgstr "No podeu deixar el número document d’identitat en blanc." #: pkg/customer/admin.go:333 pkg/booking/checkin.go:291 -#: pkg/booking/checkin.go:292 pkg/booking/admin.go:570 +#: pkg/booking/checkin.go:292 pkg/booking/admin.go:585 #: pkg/booking/public.go:581 msgid "Full name can not be empty." msgstr "No podeu deixar el nom i els cognoms en blanc." -#: pkg/customer/admin.go:334 pkg/booking/admin.go:571 pkg/booking/public.go:582 +#: pkg/customer/admin.go:334 pkg/booking/admin.go:586 pkg/booking/public.go:582 msgid "Full name must have at least one letter." msgstr "El nom i els cognoms han de tenir com a mínim una lletra." @@ -3217,13 +3226,13 @@ msgstr "No podeu deixar la població en blanc." msgid "Postcode can not be empty." msgstr "No podeu deixar el codi postal en blanc." -#: pkg/customer/admin.go:340 pkg/company/admin.go:234 pkg/booking/admin.go:577 +#: pkg/customer/admin.go:340 pkg/company/admin.go:234 pkg/booking/admin.go:592 #: pkg/booking/public.go:588 msgid "This postcode is not valid." msgstr "Aquest codi postal no és vàlid." #: pkg/customer/admin.go:348 pkg/company/admin.go:220 -#: pkg/booking/checkin.go:304 pkg/booking/admin.go:587 +#: pkg/booking/checkin.go:304 pkg/booking/admin.go:602 #: pkg/booking/public.go:596 msgid "This phone number is not valid." msgstr "Aquest número de telèfon no és vàlid." @@ -3492,19 +3501,19 @@ msgctxt "filename" msgid "bookings.ods" msgstr "reserves.ods" -#: pkg/booking/admin.go:576 +#: pkg/booking/admin.go:591 msgid "Country can not be empty to validate the postcode." msgstr "No podeu deixar el país en blanc per validar el codi postal." -#: pkg/booking/admin.go:586 +#: pkg/booking/admin.go:601 msgid "Country can not be empty to validate the phone." msgstr "No podeu deixar el país en blanc per validar el telèfon." -#: pkg/booking/admin.go:593 +#: pkg/booking/admin.go:608 msgid "You must select at least one accommodation." msgstr "Heu d’escollir com a mínim un allotjament." -#: pkg/booking/admin.go:599 +#: pkg/booking/admin.go:614 msgid "The selected accommodations have no available openings in the requested dates." msgstr "Els allotjaments escollits no estan disponibles a les dates demanades." diff --git a/po/es.po b/po/es.po index e2407bd..a238b9f 100644 --- a/po/es.po +++ b/po/es.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2024-05-03 00:56+0200\n" +"POT-Creation-Date: 2024-05-03 17:19+0200\n" "PO-Revision-Date: 2024-02-06 10:04+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -2748,6 +2748,15 @@ msgctxt "action" msgid "Invoice Booking" msgstr "Facturar la reserva" +#: web/templates/admin/booking/form.gohtml:58 +msgid "Are you sure you wish to cancel this booking?" +msgstr "¿Estáis seguro de querer cancelar esta reserva?" + +#: web/templates/admin/booking/form.gohtml:59 +msgctxt "action" +msgid "Cancel booking" +msgstr "Cancelar la reserva" + #: web/templates/admin/booking/checkin.gohtml:6 msgctxt "title" msgid "Check-in Booking" @@ -2933,7 +2942,7 @@ msgid "Email can not be empty." msgstr "No podéis dejar el correo-e en blanco." #: pkg/app/login.go:57 pkg/app/user.go:247 pkg/customer/admin.go:345 -#: pkg/company/admin.go:225 pkg/booking/admin.go:582 pkg/booking/public.go:593 +#: pkg/company/admin.go:225 pkg/booking/admin.go:597 pkg/booking/public.go:593 msgid "This email is not valid. It should be like name@domain.com." msgstr "Este correo-e no es válido. Tiene que ser parecido a nombre@dominio.com." @@ -3144,7 +3153,7 @@ msgctxt "header" msgid "Children (aged 2 to 10)" msgstr "Niños (de 2 a 10 años)" -#: pkg/campsite/admin.go:280 pkg/booking/admin.go:558 pkg/booking/public.go:177 +#: pkg/campsite/admin.go:280 pkg/booking/admin.go:573 pkg/booking/public.go:177 #: pkg/booking/public.go:232 msgid "Selected campsite type is not valid." msgstr "El tipo de alojamiento escogido no es válido." @@ -3196,12 +3205,12 @@ msgid "ID document number can not be empty." msgstr "No podéis dejar el número del documento de identidad en blanco." #: pkg/customer/admin.go:333 pkg/booking/checkin.go:291 -#: pkg/booking/checkin.go:292 pkg/booking/admin.go:570 +#: pkg/booking/checkin.go:292 pkg/booking/admin.go:585 #: pkg/booking/public.go:581 msgid "Full name can not be empty." msgstr "No podéis dejar el nombre y los apellidos en blanco." -#: pkg/customer/admin.go:334 pkg/booking/admin.go:571 pkg/booking/public.go:582 +#: pkg/customer/admin.go:334 pkg/booking/admin.go:586 pkg/booking/public.go:582 msgid "Full name must have at least one letter." msgstr "El nombre y los apellidos tienen que tener como mínimo una letra." @@ -3217,13 +3226,13 @@ msgstr "No podéis dejar la población en blanco." msgid "Postcode can not be empty." msgstr "No podéis dejar el código postal en blanco." -#: pkg/customer/admin.go:340 pkg/company/admin.go:234 pkg/booking/admin.go:577 +#: pkg/customer/admin.go:340 pkg/company/admin.go:234 pkg/booking/admin.go:592 #: pkg/booking/public.go:588 msgid "This postcode is not valid." msgstr "Este código postal no es válido." #: pkg/customer/admin.go:348 pkg/company/admin.go:220 -#: pkg/booking/checkin.go:304 pkg/booking/admin.go:587 +#: pkg/booking/checkin.go:304 pkg/booking/admin.go:602 #: pkg/booking/public.go:596 msgid "This phone number is not valid." msgstr "Este teléfono no es válido." @@ -3492,19 +3501,19 @@ msgctxt "filename" msgid "bookings.ods" msgstr "reservas.ods" -#: pkg/booking/admin.go:576 +#: pkg/booking/admin.go:591 msgid "Country can not be empty to validate the postcode." msgstr "No podéis dejar el país en blanco para validar el código postal." -#: pkg/booking/admin.go:586 +#: pkg/booking/admin.go:601 msgid "Country can not be empty to validate the phone." msgstr "No podéis dejar el país en blanco para validar el teléfono." -#: pkg/booking/admin.go:593 +#: pkg/booking/admin.go:608 msgid "You must select at least one accommodation." msgstr "Tenéis que seleccionar como mínimo un alojamiento." -#: pkg/booking/admin.go:599 +#: pkg/booking/admin.go:614 msgid "The selected accommodations have no available openings in the requested dates." msgstr "Los alojamientos seleccionados no tienen disponibilidad en las fechas pedidas." diff --git a/po/fr.po b/po/fr.po index dfd255b..77a0f26 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2024-05-03 00:56+0200\n" +"POT-Creation-Date: 2024-05-03 17:19+0200\n" "PO-Revision-Date: 2024-02-06 10:05+0100\n" "Last-Translator: Oriol Carbonell \n" "Language-Team: French \n" @@ -2748,6 +2748,15 @@ msgctxt "action" msgid "Invoice Booking" msgstr "Facturer la réservation" +#: web/templates/admin/booking/form.gohtml:58 +msgid "Are you sure you wish to cancel this booking?" +msgstr "Êtes-vous sûr de vouloir annuler cette réservation ?" + +#: web/templates/admin/booking/form.gohtml:59 +msgctxt "action" +msgid "Cancel booking" +msgstr "Annuler la réservation" + #: web/templates/admin/booking/checkin.gohtml:6 msgctxt "title" msgid "Check-in Booking" @@ -2933,7 +2942,7 @@ msgid "Email can not be empty." msgstr "L’e-mail ne peut pas être vide." #: pkg/app/login.go:57 pkg/app/user.go:247 pkg/customer/admin.go:345 -#: pkg/company/admin.go:225 pkg/booking/admin.go:582 pkg/booking/public.go:593 +#: pkg/company/admin.go:225 pkg/booking/admin.go:597 pkg/booking/public.go:593 msgid "This email is not valid. It should be like name@domain.com." msgstr "Cette adresse e-mail n’est pas valide. Il devrait en être name@domain.com." @@ -3144,7 +3153,7 @@ msgctxt "header" msgid "Children (aged 2 to 10)" msgstr "Enfants (de 2 à 10 anys)" -#: pkg/campsite/admin.go:280 pkg/booking/admin.go:558 pkg/booking/public.go:177 +#: pkg/campsite/admin.go:280 pkg/booking/admin.go:573 pkg/booking/public.go:177 #: pkg/booking/public.go:232 msgid "Selected campsite type is not valid." msgstr "Le type d’emplacement sélectionné n’est pas valide." @@ -3196,12 +3205,12 @@ msgid "ID document number can not be empty." msgstr "Le numéro de documento d’identité ne peut pas être vide." #: pkg/customer/admin.go:333 pkg/booking/checkin.go:291 -#: pkg/booking/checkin.go:292 pkg/booking/admin.go:570 +#: pkg/booking/checkin.go:292 pkg/booking/admin.go:585 #: pkg/booking/public.go:581 msgid "Full name can not be empty." msgstr "Le nom complet ne peut pas être vide." -#: pkg/customer/admin.go:334 pkg/booking/admin.go:571 pkg/booking/public.go:582 +#: pkg/customer/admin.go:334 pkg/booking/admin.go:586 pkg/booking/public.go:582 msgid "Full name must have at least one letter." msgstr "Le nom complet doit comporter au moins une lettre." @@ -3217,13 +3226,13 @@ msgstr "La ville ne peut pas être vide." msgid "Postcode can not be empty." msgstr "Le code postal ne peut pas être vide." -#: pkg/customer/admin.go:340 pkg/company/admin.go:234 pkg/booking/admin.go:577 +#: pkg/customer/admin.go:340 pkg/company/admin.go:234 pkg/booking/admin.go:592 #: pkg/booking/public.go:588 msgid "This postcode is not valid." msgstr "Ce code postal n’est pas valide." #: pkg/customer/admin.go:348 pkg/company/admin.go:220 -#: pkg/booking/checkin.go:304 pkg/booking/admin.go:587 +#: pkg/booking/checkin.go:304 pkg/booking/admin.go:602 #: pkg/booking/public.go:596 msgid "This phone number is not valid." msgstr "Ce numéro de téléphone n’est pas valide." @@ -3492,19 +3501,19 @@ msgctxt "filename" msgid "bookings.ods" msgstr "reservations.ods" -#: pkg/booking/admin.go:576 +#: pkg/booking/admin.go:591 msgid "Country can not be empty to validate the postcode." msgstr "Le pays ne peut pas être vide pour valider le code postal." -#: pkg/booking/admin.go:586 +#: pkg/booking/admin.go:601 msgid "Country can not be empty to validate the phone." msgstr "Le pays ne peut pas être vide pour valider le téléphone." -#: pkg/booking/admin.go:593 +#: pkg/booking/admin.go:608 msgid "You must select at least one accommodation." msgstr "Vous devez sélectionner au moins un hébergement." -#: pkg/booking/admin.go:599 +#: pkg/booking/admin.go:614 msgid "The selected accommodations have no available openings in the requested dates." msgstr "Les hébergements sélectionnés n’ont pas de disponibilités aux dates demandées." diff --git a/revert/cancel_booking.sql b/revert/cancel_booking.sql new file mode 100644 index 0000000..5ed6e32 --- /dev/null +++ b/revert/cancel_booking.sql @@ -0,0 +1,7 @@ +-- Revert camper:cancel_booking from pg + +begin; + +drop function if exists camper.cancel_booking(integer); + +commit; diff --git a/sqitch.plan b/sqitch.plan index 6af6387..6101d68 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -332,3 +332,4 @@ edit_contact [roles schema_camper email country_code contact extension_pg_libpho booking_invoice [roles schema_camper booking invoice] 2024-04-28T19:45:05Z jordi fita mas # Add relation of booking invoices marshal_payment [roles schema_camper payment payment_customer payment_option payment__acsi_card payment_customer__-acsi_card] 2024-04-29T17:11:59Z jordi fita mas # Add function to marshal a payment unmarshal_booking [roles schema_camper booking booking_option extension_pg_libphonenumber] 2024-04-29T17:20:38Z jordi fita mas # Add function to unmarshal a booking +cancel_booking [roles schema_camper booking booking_campsite] 2024-05-03T14:27:31Z jordi fita mas # Add function to cancel a booking diff --git a/test/cancel_booking.sql b/test/cancel_booking.sql new file mode 100644 index 0000000..d408e24 --- /dev/null +++ b/test/cancel_booking.sql @@ -0,0 +1,89 @@ +-- Test cancel_booking +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(12); + +set search_path to camper, public; + +select has_function('camper', 'cancel_booking', array['integer']); +select function_lang_is('camper', 'cancel_booking', array['integer'], 'sql'); +select function_returns('camper', 'cancel_booking', array['integer'], 'void'); +select isnt_definer('camper', 'cancel_booking', array['integer']); +select volatility_is('camper', 'cancel_booking', array['integer'], 'volatile'); +select function_privs_are('camper', 'cancel_booking', array ['integer'], 'guest', array[]::text[]); +select function_privs_are('camper', 'cancel_booking', array ['integer'], 'employee', array['EXECUTE']); +select function_privs_are('camper', 'cancel_booking', array ['integer'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'cancel_booking', array ['integer'], 'authenticator', array[]::text[]); + + +set client_min_messages to warning; +truncate booking_campsite cascade; +truncate booking cascade; +truncate campsite_type cascade; +truncate media cascade; +truncate media_content cascade; +truncate company cascade; +reset client_min_messages; + +insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, rtc_number, tourist_tax, tourist_tax_max_days, country_code, currency_code, default_lang_tag) +values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 7, 'ES', 'EUR', 'ca') +; + +insert into media_content (media_type, bytes) +values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};') +; + +insert into media (media_id, company_id, original_filename, content_hash) +values (6, 2, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};')) +; + +insert into campsite_type (campsite_type_id, company_id, name, media_id, max_campers, bookable_nights) +values (10, 2, 'Wooden lodge', 6, 7, '[1, 7]') +; + +insert into campsite (campsite_id, company_id, label, campsite_type_id) +values (12, 2, 'A', 10) + , (14, 2, 'B', 10) + , (16, 2, 'C', 10) +; + +insert into booking (booking_id, company_id, campsite_type_id, holder_name, stay, acsi_card, currency_code, zone_preferences, subtotal_nights, number_adults, subtotal_adults, number_teenagers, subtotal_teenagers, number_children, subtotal_children, number_dogs, subtotal_dogs, subtotal_tourist_tax, total) +values (18, 2, 10, 'Holder 2', daterange('2024-01-18', '2024-01-29'), false, 'EUR', '', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) + , (20, 2, 10, 'Holder 4', daterange('2024-01-28', '2024-01-29'), true, 'USD', 'None', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) +; + +insert into booking_campsite (booking_id, campsite_id, stay) +values (18, 12, daterange('2024-01-18', '2024-01-29')) + , (18, 14, daterange('2024-01-18', '2024-01-29')) + , (20, 16, daterange('2024-01-28', '2024-01-29')) +; + +select lives_ok( + $$ select cancel_booking(18) $$, + 'Should be able to cancel the first booking' +); + + +select bag_eq( + $$ select booking_id, company_id, campsite_type_id, stay, holder_name, address, postal_code, city, country_code::text, email::text, phone::text, lang_tag, zone_preferences, subtotal_nights::integer, number_adults::integer, subtotal_adults::integer, number_teenagers::integer, subtotal_teenagers::integer, number_children::integer, subtotal_children::integer, number_dogs::integer, subtotal_dogs::integer, subtotal_tourist_tax::integer, total::integer, acsi_card, currency_code::text, booking_status from booking $$, + $$ values (18, 2, 10, daterange('2024-01-18', '2024-01-29'), 'Holder 2', null, null, null, null, null, null, 'und', '', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, false, 'EUR', 'cancelled') + , (20, 2, 10, daterange('2024-01-28', '2024-01-29'), 'Holder 4', null, null, null, null, null, null, 'und', 'None', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, true, 'USD', 'created') + $$, + 'Should have updated the bookings' +); + +select bag_eq ( + $$ select booking_id, campsite_id, stay from booking_campsite $$, + $$ values (20, 16, daterange('2024-01-28', '2024-01-29')) + $$ , + 'Should have deleted the cancelled booking’ campsites' +); + +select * +from finish(); + +rollback; diff --git a/verify/cancel_booking.sql b/verify/cancel_booking.sql new file mode 100644 index 0000000..6c31361 --- /dev/null +++ b/verify/cancel_booking.sql @@ -0,0 +1,7 @@ +-- Verify camper:cancel_booking on pg + +begin; + +select has_function_privilege('camper.cancel_booking(integer)', 'execute'); + +rollback; diff --git a/web/static/camper.css b/web/static/camper.css index 9f5b19c..1e70f5a 100644 --- a/web/static/camper.css +++ b/web/static/camper.css @@ -883,6 +883,11 @@ label[x-show] > span, label[x-show] > br { grid-template-columns: repeat(4, 1fr); } +#booking-form > footer { + display: flex; + justify-content: space-between; +} + #booking-form fieldset fieldset, #booking-form .colspan { grid-column: span 2; } diff --git a/web/templates/admin/booking/form.gohtml b/web/templates/admin/booking/form.gohtml index ae8162a..71179c5 100644 --- a/web/templates/admin/booking/form.gohtml +++ b/web/templates/admin/booking/form.gohtml @@ -54,6 +54,10 @@ {{( pgettext "Add" "action" )}} {{- end -}} + {{- if .ID -}} + {{ $confirm := ( gettext "Are you sure you wish to cancel this booking?" )}} + + {{- end }} {{- end }}