From ebd14e59afe37be327eee025dbb7f1acd5ca4118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Krienb=C3=BChl?= Date: Fri, 29 Apr 2016 09:00:09 +0200 Subject: [PATCH] Adds the ability to deny selected dates from a reservation ticket Resolves #189 --- HISTORY.rst | 7 +- onegov/town/elements.py | 5 +- .../locale/de_ch/LC_MESSAGES/onegov.town.po | 78 +++++++----- onegov/town/models/resource.py | 2 +- onegov/town/models/ticket.py | 104 ++++++++++------ onegov/town/templates/macros.pt | 2 +- .../templates/mail_reservation_accepted.pt | 2 +- .../templates/mail_reservation_rejected.pt | 2 +- onegov/town/tests/test_views.py | 113 ++++++++++++++++-- onegov/town/theme/styles/town.scss | 9 +- onegov/town/views/reservation.py | 39 ++++-- 11 files changed, 264 insertions(+), 99 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 1f9fcc4..b505f86 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,10 +1,13 @@ Changelog --------- -- Removes extra text in ticket closed e-mail. +- Adds the ability to create multiple reservations in one ticket. [href] -- Adds the ability to create multiple reservations in one ticket. +- Adds the ability to deny selected dates from a reservation ticket. + [href] + +- Removes extra text in ticket closed e-mail. [href] - Shows an error if an uploaded's filename is too long. diff --git a/onegov/town/elements.py b/onegov/town/elements.py index af3a04e..3e21485 100644 --- a/onegov/town/elements.py +++ b/onegov/town/elements.py @@ -173,9 +173,10 @@ def __init__(self, src, alt=None, title=None, url=None): class LinkGroup(HiddenElementMixin): """ Represents a list of links. """ - __slots__ = ['title', 'links', 'model'] + __slots__ = ['title', 'links', 'model', 'right_side'] - def __init__(self, title, links, model=None): + def __init__(self, title, links, model=None, right_side=True): self.title = title self.links = links self.model = model + self.right_side = right_side diff --git a/onegov/town/locale/de_ch/LC_MESSAGES/onegov.town.po b/onegov/town/locale/de_ch/LC_MESSAGES/onegov.town.po index dfee0f3..306f6ff 100644 --- a/onegov/town/locale/de_ch/LC_MESSAGES/onegov.town.po +++ b/onegov/town/locale/de_ch/LC_MESSAGES/onegov.town.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE 1.0\n" -"POT-Creation-Date: 2016-04-28 12:26+0200\n" +"POT-Creation-Date: 2016-04-28 16:18+0200\n" "PO-Revision-Date: 2015-10-15 09:42+0200\n" "Last-Translator: Denis Krienbühl \n" "Language-Team: German\n" @@ -659,18 +659,12 @@ msgstr "Älter" msgid "Event" msgstr "Veranstaltung" +msgid "Reject reservations" +msgstr "Reservationen absagen" + msgid "Edit submission" msgstr "Eingabe bearbeiten" -msgid "Reject reservation" -msgstr "Reservation absagen" - -msgid "Do you really want to reject this reservation?" -msgstr "Möchten Sie diese Reservation wirklich absagen?" - -msgid "Rejecting this reservation can't be undone." -msgstr "Eine Absage kann nicht rückgängig gemacht werden." - msgid "Details about the reservation" msgstr "Details zu Ihrer Reservation" @@ -686,8 +680,17 @@ msgstr "Eine Absage kann nicht rückgängig gemacht werden." msgid "Edit event" msgstr "Veranstaltung bearbeiten" -msgid "Accept reservation" -msgstr "Reservation annehmen" +msgid "Accept all reservations" +msgstr "Alle Reservationen annehmen" + +msgid "Reject all" +msgstr "Alle absagen" + +msgid "Do you really want to reject all reservations?" +msgstr "Möchten Sie wirklich alle Reservationen absagen?" + +msgid "Rejecting these reservations can't be undone." +msgstr "Die Absage aller Reservationen kann nicht rückgängig gemacht werden." msgid "Edit details" msgstr "Details bearbeiten" @@ -695,6 +698,20 @@ msgstr "Details bearbeiten" msgid "Accept event" msgstr "Veranstaltung annehmen" +#, python-format +msgid "Reject ${title}" +msgstr "${title} absagen" + +msgid "Do you really want to reject this reservation?" +msgstr "Möchten Sie diese Reservation wirklich absagen?" + +#, python-format +msgid "Rejecting ${title} can't be undone." +msgstr "Die Absage von ${title} kann nicht rückgängig gemacht werden." + +msgid "Reject reservation" +msgstr "Reservation absagen" + msgid "Link" msgstr "Verknüpfung" @@ -1085,11 +1102,11 @@ msgstr "" "Sie können dieses E-Mail ignorieren, falls Sie Ihr Passwort nicht ändern " "möchten." -msgid "Your reservation has been accepted:" -msgstr "Ihre Reservation wurde angenommen:" +msgid "The following reservations have been accepted:" +msgstr "Die folgenden Reservationen wurden angenommen:" -msgid "Your reservation has unfortunately been rejected:" -msgstr "Ihre Reservation musste leider abgesagt werden:" +msgid "The following reservations has unfortunately been rejected:" +msgstr "Die folgenden Reservationen mussten leider abgesagt werden:" msgid "Your ticket has been closed" msgstr "Ihr Ticket wurde geschlossen" @@ -1173,7 +1190,9 @@ msgid "Go to calendar" msgstr "Zum Kalender" msgid "Select a free time span in the calendar below to create an allocation." -msgstr "Wählen Sie eine freie Zeitspanne im Kalender aus um eine Einteilung zu machen." +msgstr "" +"Wählen Sie eine freie Zeitspanne im Kalender aus um eine Einteilung zu " +"machen." msgid "Further Information" msgstr "Weitere Informationen" @@ -1439,9 +1458,6 @@ msgstr "Weiter" msgid "Confirm your reservation" msgstr "Bestätigen Sie Ihre Reservation" -msgid "The reservation was rejected" -msgstr "Die Reservation wurde abgesagt" - msgid "Reserve" msgstr "Reservieren" @@ -1451,17 +1467,23 @@ msgstr "Bestätigen" msgid "Thank you for your reservation!" msgstr "Vielen Dank für Ihre Reservation!" -msgid "The reservation was accepted" -msgstr "Die Reservation wurde angenommen" +msgid "The reservations were accepted" +msgstr "Die Reservationen wurden angenommen" + +msgid "The reservations have already been accepted" +msgstr "Die Reservationen wurden bereits angenommen" -msgid "The reservation has already been accepted" -msgstr "Die Reservation wurde bereits angenommen" +msgid "The following reservations were rejected" +msgstr "Die folgenden Reservationen wurden abgelehnt" -msgid "Your reservation was rejected" -msgstr "Ihre Reservation wurde abgesagt" +msgid "The reservations were rejected" +msgstr "Die Reservationen wurden abgelehnt" + +msgid "The reservation was rejected" +msgstr "Die Reservation wurde abgesagt" -msgid "Your reservation was accepted" -msgstr "Ihre Reservation wurde angenommen" +msgid "Your reservations were accepted" +msgstr "Ihre Reservationen wurden angenommen" #, python-format msgid "" diff --git a/onegov/town/models/resource.py b/onegov/town/models/resource.py index 91c708d..346cc3b 100644 --- a/onegov/town/models/resource.py +++ b/onegov/town/models/resource.py @@ -60,7 +60,7 @@ def request_bound_reservations(self, request, status='pending'): res = res.filter(Reservation.resource == self.id) res = res.filter(Reservation.status == status) res = res.order_by(False) # clear existing order - res = res.order_by(Reservation.id) + res = res.order_by(Reservation.start) return res diff --git a/onegov/town/models/ticket.py b/onegov/town/models/ticket.py index 8f42639..e1573a8 100644 --- a/onegov/town/models/ticket.py +++ b/onegov/town/models/ticket.py @@ -7,7 +7,7 @@ from onegov.libres import Resource from onegov.ticket import Ticket, Handler, handlers from onegov.town import _ -from onegov.town.elements import DeleteLink, Link +from onegov.town.elements import DeleteLink, Link, LinkGroup from onegov.town.layout import DefaultLayout, EventLayout from onegov.town.utils import correct_time_range from purl import URL @@ -135,25 +135,10 @@ def email(self): @property def title(self): - if self.resource.type == 'daypass': - template = '{start:%d.%m.%Y} ({quota})' - elif self.resource.type == 'room': - template = '{start:%d.%m.%Y} {start:%H:%M} - {end:%H:%M}' - else: - raise NotImplementedError - parts = [] for ix, reservation in enumerate(self.reservations): - parts.append( - correct_time_range( - template.format( - start=reservation.display_start(), - end=reservation.display_end(), - quota=reservation.quota - ) - ) - ) + parts.append(self.get_reservation_title(reservation)) if ix == 4: parts.append('…') @@ -161,6 +146,22 @@ def title(self): return ', '.join(parts) + def get_reservation_title(self, reservation): + if self.resource.type == 'daypass': + template = '{start:%d.%m.%Y} ({quota})' + elif self.resource.type == 'room': + template = '{start:%d.%m.%Y} {start:%H:%M} - {end:%H:%M}' + else: + raise NotImplementedError + + return correct_time_range( + template.format( + start=reservation.display_start(), + end=reservation.display_end(), + quota=reservation.quota + ) + ) + @property def subtitle(self): if self.submission: @@ -223,36 +224,71 @@ def get_links(self, request): links = [] - data = self.reservations[0].data or {} + accepted = tuple( + r.data and r.data.get('accepted') or False + for r in self.reservations + ) - if not data.get('accepted'): + if not all(accepted): link = URL(request.link(self.reservations[0], 'annehmen')) link = link.query_param('return-to', request.url) links.append( Link( - text=_("Accept reservation"), + text=_("Accept all reservations"), url=link.as_string(), classes=('accept-link', ) ) ) - link = URL(request.link(self.reservations[0], 'absagen')) - link = link.query_param('return-to', request.url) - links.append( - DeleteLink( - text=_("Reject reservation"), - url=link.as_string(), - confirm=_("Do you really want to reject this reservation?"), - extra_information=_( - "Rejecting this reservation can't be undone." - ), - yes_button_text=_("Reject reservation"), - request_method='GET', - redirect_after=request.url - ) + reject_all_link = URL(request.link(self.reservations[0], 'absagen')) + reject_all_link = reject_all_link.query_param('return-to', request.url) + + reject = LinkGroup( + _("Reject reservations"), + [ + DeleteLink( + text=_("Reject all"), + url=reject_all_link.as_string(), + confirm=_( + "Do you really want to reject all reservations?" + ), + extra_information=_( + "Rejecting these reservations can't be undone." + ), + yes_button_text=_("Reject reservations"), + request_method='GET', + redirect_after=request.url + ) + ], + right_side=False ) + for reservation in self.reservations: + link = URL(request.link(reservation, 'absagen')) + link = link.query_param('reservation-id', reservation.id) + link = link.query_param('return-to', request.url) + title = self.get_reservation_title(reservation) + reject.links.append( + DeleteLink( + text=_("Reject ${title}", mapping={'title': title}), + url=link.as_string(), + confirm=_( + "Do you really want to reject this reservation?" + ), + extra_information=_( + "Rejecting ${title} can't be undone.", mapping={ + 'title': title + } + ), + yes_button_text=_("Reject reservation"), + request_method='GET', + redirect_after=request.url + ) + ) + + links.append(reject) + if self.submission: link = URL(request.link(self.submission)) link = link.query_param('edit', '') diff --git a/onegov/town/templates/macros.pt b/onegov/town/templates/macros.pt index 6a02117..baba50b 100644 --- a/onegov/town/templates/macros.pt +++ b/onegov/town/templates/macros.pt @@ -37,7 +37,7 @@
-