From 09b24ce6068bf4489421976e01b5e55e8bc2bcf7 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Thu, 16 Apr 2015 18:05:25 +0200 Subject: [PATCH] Implement ticket download dates (closes #15) --- src/pretix/base/forms.py | 3 +- src/pretix/base/settings.py | 4 ++ .../templates/pretixcontrol/event/base.html | 6 ++ .../pretixcontrol/event/tickets.html | 23 +++++++ src/pretix/control/urls.py | 1 + src/pretix/control/views/event.py | 60 +++++++++++++++++++ .../templates/pretixpresale/event/order.html | 25 ++++++++ src/pretix/presale/views/order.py | 21 ++++++- 8 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/pretix/control/templates/pretixcontrol/event/tickets.html diff --git a/src/pretix/base/forms.py b/src/pretix/base/forms.py index 5f9a355947..e6ba80653b 100644 --- a/src/pretix/base/forms.py +++ b/src/pretix/base/forms.py @@ -81,8 +81,7 @@ class SettingsForm(forms.Form): def __init__(self, *args, **kwargs): self.obj = kwargs.pop('obj') - if 'initial' not in kwargs: - kwargs['initial'] = self.obj.settings + kwargs['initial'] = self.obj.settings super().__init__(*args, **kwargs) def save(self): diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index cbbf4cc0f4..bf83128078 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -73,6 +73,10 @@ DEFAULTS = { 'default': 'True', 'type': bool }, + 'ticket_download_date': { + 'default': None, + 'type': datetime + }, 'last_order_modification_date': { 'default': None, 'type': datetime diff --git a/src/pretix/control/templates/pretixcontrol/event/base.html b/src/pretix/control/templates/pretixcontrol/event/base.html index cf909cf751..3d42ccd513 100644 --- a/src/pretix/control/templates/pretixcontrol/event/base.html +++ b/src/pretix/control/templates/pretixcontrol/event/base.html @@ -34,6 +34,12 @@ {% trans "Plugins" %} +
  • + + {% trans "Tickets" %} + +
  • diff --git a/src/pretix/control/templates/pretixcontrol/event/tickets.html b/src/pretix/control/templates/pretixcontrol/event/tickets.html new file mode 100644 index 0000000000..827ac631e9 --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/event/tickets.html @@ -0,0 +1,23 @@ +{% extends "pretixcontrol/event/settings_base.html" %} +{% load i18n %} +{% load bootstrap3 %} +{% block inside %} +
    + {% if "success" in request.GET %} +
    + {% trans "Your changes have been saved." %} +
    + {% endif %} + {% csrf_token %} +
    + {% trans "Ticket download" %} + {% bootstrap_field form.ticket_download layout="horizontal" %} + {% bootstrap_field form.ticket_download_date layout="horizontal" %} +
    +
    + +
    +
    +{% endblock %} diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index 43311029ed..129b76443d 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -13,6 +13,7 @@ urlpatterns = [ url(r'^settings/$', event.EventUpdate.as_view(), name='event.settings'), url(r'^settings/plugins$', event.EventPlugins.as_view(), name='event.settings.plugins'), url(r'^settings/payment$', event.PaymentSettings.as_view(), name='event.settings.payment'), + url(r'^settings/tickets$', event.TicketSettings.as_view(), name='event.settings.tickets'), url(r'^items/$', item.ItemList.as_view(), name='event.items'), url(r'^items/add$', item.ItemCreate.as_view(), name='event.items.add'), url(r'^items/(?P[0-9a-f-]+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'), diff --git a/src/pretix/control/views/event.py b/src/pretix/control/views/event.py index 71dcbd52c0..6e668440ae 100644 --- a/src/pretix/control/views/event.py +++ b/src/pretix/control/views/event.py @@ -2,6 +2,7 @@ from collections import OrderedDict from django.conf import settings from django.shortcuts import render, redirect from django.utils.functional import cached_property +from django.views.generic import FormView from django.views.generic.base import TemplateView from django.views.generic.detail import SingleObjectMixin from django import forms @@ -303,5 +304,64 @@ class PaymentSettings(EventPermissionRequiredMixin, TemplateView, SingleObjectMi }) + '?success=true' +class TicketSettingsForm(SettingsForm): + ticket_download = forms.BooleanField( + label=_("Use feature"), + help_text=_("Use pretix to generate tickets for the user to download and print out."), + required=False + ) + ticket_download_date = forms.DateTimeField( + label=_("Download date"), + help_text=_("Ticket download will be offered after this date."), + required=True + ) + + def prepare_fields(self): + # See clean() + for k, v in self.fields.items(): + v._required = v.required + v.required = False + v.widget.is_required = False + + def clean(self): + # required=True files should only be required if the feature is enabled + cleaned_data = super().clean() + enabled = cleaned_data.get('ticket_download') == 'True' + if not enabled: + return + for k, v in self.fields.items(): + val = cleaned_data.get(k) + if v._required and (val is None or val == ""): + print(enabled, k, v) + self.add_error(k, _('This field is required.')) + + +class TicketSettings(EventPermissionRequiredMixin, FormView): + model = Event + form_class = TicketSettingsForm + template_name = 'pretixcontrol/event/tickets.html' + permission = 'can_change_settings' + + def form_valid(self, form): + form.save() + return super().form_valid(form) + + def get_success_url(self) -> str: + return reverse('control:event.settings.tickets', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug + }) + '?success=true' + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs['obj'] = self.request.event + return kwargs + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.prepare_fields() + return form + + def index(request, organizer, event): return render(request, 'pretixcontrol/event/index.html', {}) diff --git a/src/pretix/presale/templates/pretixpresale/event/order.html b/src/pretix/presale/templates/pretixpresale/event/order.html index c3b42a05cd..6b4ae6c194 100644 --- a/src/pretix/presale/templates/pretixpresale/event/order.html +++ b/src/pretix/presale/templates/pretixpresale/event/order.html @@ -24,6 +24,31 @@ {% endif %} + {% if order.status == 'p' and event.settings.ticket_download %} +
    +
    +

    {% trans "Ticket download" %}

    +
    +
    + {% if can_download %} +

    + {% blocktrans trimmed %} + Please use the buttons below to obtain your ticket. Please have your ticket ready when + entering the event. + {% endblocktrans %} +

    + + {% trans "Download PDF" %} + + {% else %} + {% blocktrans trimmed with date=event.settings.ticket_download_date|date %} + You will be able to download your tickets here on {{ date }}. + {% endblocktrans %} + {% endif %} +
    +
    + {% endif %}
    {% if order.can_modify_answers %} diff --git a/src/pretix/presale/views/order.py b/src/pretix/presale/views/order.py index 6f102f02a7..492e604a69 100644 --- a/src/pretix/presale/views/order.py +++ b/src/pretix/presale/views/order.py @@ -2,6 +2,7 @@ from io import StringIO, BytesIO from django.contrib import messages from django.core.urlresolvers import reverse from django.shortcuts import redirect +from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property from django.views.generic import TemplateView, View @@ -48,6 +49,11 @@ class OrderDetails(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx['order'] = self.order + ctx['can_download'] = ( + self.request.event.settings.ticket_download + and now() > self.request.event.settings.ticket_download_date + and self.order.status == Order.STATUS_PAID + ) ctx['cart'] = self.get_cart( answers=True, queryset=OrderPosition.objects.current.filter(order=self.order) @@ -144,6 +150,13 @@ class OrderCancel(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, class OrderDownload(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, View): + def get_order_url(self): + return reverse('presale:event.order', kwargs={ + 'event': self.request.event.slug, + 'organizer': self.request.event.organizer.slug, + 'order': self.order.code, + }) + def get(self, request, *args, **kwargs): from reportlab.graphics.shapes import Drawing from reportlab.pdfgen import canvas @@ -151,8 +164,14 @@ class OrderDownload(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, from reportlab.graphics.barcode.qr import QrCodeWidget from reportlab.graphics import renderPDF from PyPDF2 import PdfFileWriter, PdfFileReader + if self.order.status != Order.STATUS_PAID: - return HttpResponseForbidden(_('Order is not paid')) + messages.error(request, _('Order is not paid.')) + return redirect(self.get_order_url()) + if not self.request.event.settings.ticket_download or now() < self.request.event.settings.ticket_download_date: + messages.error(request, _('Ticket download is not (yet) enabled.')) + return redirect(self.get_order_url()) + response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'inline; filename="order%s%s.pdf"' % (request.event.slug, self.order.code)