From 4ed3df2b08fbac3031fe1ff46498a1f8a6830d61 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 2 Feb 2018 15:20:26 +0100 Subject: [PATCH] Voucher list: Refactor to use filter form --- src/pretix/control/forms/filter.py | 94 ++++++++++++++++++- .../pretixcontrol/vouchers/index.html | 59 +++++++----- src/pretix/control/views/vouchers.py | 45 ++++----- 3 files changed, 143 insertions(+), 55 deletions(-) diff --git a/src/pretix/control/forms/filter.py b/src/pretix/control/forms/filter.py index f354116663..60e824c19c 100644 --- a/src/pretix/control/forms/filter.py +++ b/src/pretix/control/forms/filter.py @@ -7,7 +7,7 @@ from django.utils.timezone import now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from pretix.base.models import ( - Event, Invoice, Item, Order, OrderPosition, Organizer, SubEvent, + Checkin, Event, Invoice, Item, Order, OrderPosition, Organizer, SubEvent, ) from pretix.base.signals import register_payment_providers from pretix.control.forms.widgets import Select2 @@ -596,3 +596,95 @@ class UserFilterForm(FilterForm): qs = qs.order_by(self.get_order_by()) return qs + + +class VoucherFilterForm(FilterForm): + orders = { + } + status = forms.ChoiceField( + label=_('Status'), + choices=( + ('', _('All')), + ('v', _('Valid')), + ('r', _('Redeemed')), + ('e', _('Expired')), + ('c', _('Redeemed and checked in with ticket')), + ), + required=False + ) + tag = forms.CharField( + label=_('Filter by tag'), + widget=forms.TextInput(attrs={ + 'placeholder': _('Filter by tag'), + }), + required=False + ) + search = forms.CharField( + label=_('Search voucher'), + widget=forms.TextInput(attrs={ + 'placeholder': _('Search voucher'), + 'autofocus': 'autofocus' + }), + required=False + ) + subevent = forms.ModelChoiceField( + label=pgettext_lazy('subevent', 'Date'), + queryset=SubEvent.objects.none(), + required=False, + empty_label=pgettext_lazy('subevent', 'All dates') + ) + + def __init__(self, *args, **kwargs): + self.event = kwargs.pop('event') + super().__init__(*args, **kwargs) + + if self.event.has_subevents: + self.fields['subevent'].queryset = self.event.subevents.all() + self.fields['subevent'].widget = Select2( + attrs={ + 'data-model-select2': 'event', + 'data-select2-url': reverse('control:event.subevents.select2', kwargs={ + 'event': self.event.slug, + 'organizer': self.event.organizer.slug, + }), + 'data-placeholder': pgettext_lazy('subevent', 'All dates') + } + ) + self.fields['subevent'].widget.choices = self.fields['subevent'].choices + elif 'subevent': + del self.fields['subevent'] + + def filter_qs(self, qs): + fdata = self.cleaned_data + + if fdata.get('search'): + s = fdata.get('search').strip() + qs = qs.filter(Q(code__icontains=s) | Q(tag__icontains=s) | Q(comment__icontains=s)) + + if fdata.get('tag'): + s = fdata.get('tag').strip() + qs = qs.filter(tag__icontains=s) + + if fdata.get('status'): + s = fdata.get('status') + if s == 'v': + qs = qs.filter(Q(valid_until__isnull=True) | Q(valid_until__gt=now())).filter(redeemed=0) + elif s == 'r': + qs = qs.filter(redeemed__gt=0) + elif s == 'e': + qs = qs.filter(Q(valid_until__isnull=False) & Q(valid_until__lt=now())).filter(redeemed=0) + elif s == 'c': + checkins = Checkin.objects.filter( + position__voucher=OuterRef('pk') + ) + qs = qs.annotate(has_checkin=Exists(checkins)).filter( + redeemed__gt=0, has_checkin=True + ) + + if fdata.get('subevent'): + qs = qs.filter(subevent_id=fdata.get('subevent').pk) + + if fdata.get('ordering'): + qs = qs.order_by(self.get_order_by()) + + return qs diff --git a/src/pretix/control/templates/pretixcontrol/vouchers/index.html b/src/pretix/control/templates/pretixcontrol/vouchers/index.html index d1ad54d5b1..1595eb1a3c 100644 --- a/src/pretix/control/templates/pretixcontrol/vouchers/index.html +++ b/src/pretix/control/templates/pretixcontrol/vouchers/index.html @@ -1,5 +1,7 @@ {% extends "pretixcontrol/vouchers/base.html" %} {% load i18n %} +{% load bootstrap3 %} +{% load urlreplace %} {% block title %}{% trans "Vouchers" %}{% endblock %} {% block inside %}

@@ -8,34 +10,36 @@ reserve some quota for your very special guests. {% endblocktrans %}

-
-

- - - +

+ +
+ {% bootstrap_field filter_form.search layout='inline' %} +
+
+ {% bootstrap_field filter_form.tag layout='inline' %} +
{% if request.event.has_subevents %} - +
+ {% bootstrap_field filter_form.status layout='inline' %} +
+
+ {% bootstrap_field filter_form.subevent layout='inline' %} +
+ {% else %} +
+ {% bootstrap_field filter_form.status layout='inline' %} +
{% endif %} - - -

- +
+ +
+ +
{% if vouchers|length == 0 %}

@@ -60,6 +64,9 @@ {% trans "Create multiple new vouchers" %} + + {% trans "Download list" %}

diff --git a/src/pretix/control/views/vouchers.py b/src/pretix/control/views/vouchers.py index bd105d814c..8950c8c428 100644 --- a/src/pretix/control/views/vouchers.py +++ b/src/pretix/control/views/vouchers.py @@ -5,19 +5,20 @@ from django.conf import settings from django.contrib import messages from django.core.urlresolvers import resolve, reverse from django.db import transaction -from django.db.models import Exists, OuterRef, Q, Sum +from django.db.models import Sum from django.http import ( Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, JsonResponse, ) -from django.utils.timezone import now +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from django.views.generic import ( CreateView, DeleteView, ListView, TemplateView, UpdateView, View, ) -from pretix.base.models import Checkin, Voucher +from pretix.base.models import Voucher from pretix.base.models.vouchers import _generate_random_code +from pretix.control.forms.filter import VoucherFilterForm from pretix.control.forms.vouchers import VoucherBulkForm, VoucherForm from pretix.control.permissions import EventPermissionRequiredMixin from pretix.control.signals import voucher_form_class @@ -32,31 +33,19 @@ class VoucherList(PaginationMixin, EventPermissionRequiredMixin, ListView): def get_queryset(self): qs = self.request.event.vouchers.all().select_related('item', 'variation') - if self.request.GET.get("search", "") != "": - s = self.request.GET.get("search", "").strip() - qs = qs.filter(Q(code__icontains=s) | Q(tag__icontains=s) | Q(comment__icontains=s)) - if self.request.GET.get("tag", "") != "": - s = self.request.GET.get("tag", "") - qs = qs.filter(tag__icontains=s) - if self.request.GET.get("status", "") != "": - s = self.request.GET.get("status", "") - if s == 'v': - qs = qs.filter(Q(valid_until__isnull=True) | Q(valid_until__gt=now())).filter(redeemed=0) - elif s == 'r': - qs = qs.filter(redeemed__gt=0) - elif s == 'e': - qs = qs.filter(Q(valid_until__isnull=False) & Q(valid_until__lt=now())).filter(redeemed=0) - elif s == 'c': - checkins = Checkin.objects.filter( - position__voucher=OuterRef('pk') - ) - qs = qs.annotate(has_checkin=Exists(checkins)).filter( - redeemed__gt=0, has_checkin=True - ) - if self.request.GET.get("subevent", "") != "": - s = self.request.GET.get("subevent", "") - qs = qs.filter(subevent_id=s) - return qs + if self.filter_form.is_valid(): + qs = self.filter_form.filter_qs(qs) + + return qs.distinct() + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + ctx['filter_form'] = self.filter_form + return ctx + + @cached_property + def filter_form(self): + return VoucherFilterForm(data=self.request.GET, event=self.request.event) def get(self, request, *args, **kwargs): if request.GET.get("download", "") == "yes":