From 4b8d4b4792a2e0e498de432c939814ba379b5f80 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 3 Oct 2018 11:32:55 +0200 Subject: [PATCH] Allow to bulk-delete vouchers --- .../pretixcontrol/vouchers/delete_bulk.html | 40 +++++++ .../pretixcontrol/vouchers/index.html | 107 ++++++++++-------- src/pretix/control/urls.py | 1 + src/pretix/control/views/vouchers.py | 40 ++++++- 4 files changed, 142 insertions(+), 46 deletions(-) create mode 100644 src/pretix/control/templates/pretixcontrol/vouchers/delete_bulk.html diff --git a/src/pretix/control/templates/pretixcontrol/vouchers/delete_bulk.html b/src/pretix/control/templates/pretixcontrol/vouchers/delete_bulk.html new file mode 100644 index 0000000000..c0210716ae --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/vouchers/delete_bulk.html @@ -0,0 +1,40 @@ +{% extends "pretixcontrol/event/base.html" %} +{% load i18n %} +{% load bootstrap3 %} +{% block title %}{% trans "Delete vouchers" %}{% endblock %} +{% block content %} +

{% trans "Delete vouchers" %}

+
+ {% csrf_token %} + {% if allowed %} +

{% blocktrans %}Are you sure you want to delete the following vouchers?{% endblocktrans %}

+ + {% endif %} + {% if forbidden %} +

{% blocktrans trimmed %}The following vouchers can't be deleted as they already have been redeemed, but they will be set to fully redeemed instead.{% endblocktrans %}

+ + {% endif %} +
+ + {% trans "Cancel" %} + + +
+
+{% endblock %} diff --git a/src/pretix/control/templates/pretixcontrol/vouchers/index.html b/src/pretix/control/templates/pretixcontrol/vouchers/index.html index 2f7f1e1fce..58e740dd92 100644 --- a/src/pretix/control/templates/pretixcontrol/vouchers/index.html +++ b/src/pretix/control/templates/pretixcontrol/vouchers/index.html @@ -83,56 +83,73 @@ class="btn btn-default"> {% trans "Download list" %}

-
- - - - - - - - - {% if request.event.has_subevents %} - - {% endif %} - - - - - {% for v in vouchers %} + + {% csrf_token %} +
+
{% trans "Voucher code" %}{% trans "Redemptions" %}{% trans "Expiry" %}{% trans "Tag" %}{% trans "Product" %}{% trans "Date" context "subevent" %}
+ - - - - - + + + + + {% if request.event.has_subevents %} - + {% endif %} - + - {% endfor %} - -
- {{ v.code }} - {{ v.redeemed }} / {{ v.max_usages }}{{ v.valid_until|date }} - {{ v.tag }} - - {% if v.item %} - {{ v.item }} - {% if v.variation %} - – {{ v.variation }} - {% endif %} - {% else %} - {% blocktrans trimmed with quota=v.quota.name %} - Any product in quota "{{ quota }}" - {% endblocktrans %} + + {% if "can_change_vouchers" in request.eventpermset %} + {% endif %} - + {% trans "Voucher code" %}{% trans "Redemptions" %}{% trans "Expiry" %}{% trans "Tag" %}{% trans "Product" %}{{ v.subevent.name }} – {{ v.subevent.get_date_range_display }}{% trans "Date" context "subevent" %} - -
-
+ + + {% for v in vouchers %} + + + {% if "can_change_vouchers" in request.eventpermset %} + + {% endif %} + + + {{ v.code }} + + {{ v.redeemed }} / {{ v.max_usages }} + {{ v.valid_until|date }} + + {{ v.tag }} + + + {% if v.item %} + {{ v.item }} + {% if v.variation %} + – {{ v.variation }} + {% endif %} + {% else %} + {% blocktrans trimmed with quota=v.quota.name %} + Any product in quota "{{ quota }}" + {% endblocktrans %} + {% endif %} + + {% if request.event.has_subevents %} + {{ v.subevent.name }} – {{ v.subevent.get_date_range_display }} + {% endif %} + + + + + {% endfor %} + + + + {% if "can_change_vouchers" in request.eventpermset %} + + {% endif %} + {% include "pretixcontrol/pagination.html" %} {% endif %} {% endblock %} diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index dd6b052655..01cb0af1e8 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -179,6 +179,7 @@ urlpatterns = [ url(r'^vouchers/add$', vouchers.VoucherCreate.as_view(), name='event.vouchers.add'), url(r'^vouchers/go$', vouchers.VoucherGo.as_view(), name='event.vouchers.go'), url(r'^vouchers/bulk_add$', vouchers.VoucherBulkCreate.as_view(), name='event.vouchers.bulk'), + url(r'^vouchers/bulk_action$', vouchers.VoucherBulkAction.as_view(), name='event.vouchers.bulkaction'), url(r'^orders/(?P[0-9A-Z]+)/transition$', orders.OrderTransition.as_view(), name='event.order.transition'), url(r'^orders/(?P[0-9A-Z]+)/resend$', orders.OrderResendLink.as_view(), diff --git a/src/pretix/control/views/vouchers.py b/src/pretix/control/views/vouchers.py index 59bff24a76..149dfb60b4 100644 --- a/src/pretix/control/views/vouchers.py +++ b/src/pretix/control/views/vouchers.py @@ -9,7 +9,7 @@ from django.http import ( Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, JsonResponse, ) -from django.shortcuts import redirect +from django.shortcuts import redirect, render from django.urls import resolve, reverse from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ @@ -322,3 +322,41 @@ class VoucherRNG(EventPermissionRequiredMixin, View): 'organizer': self.request.event.organizer.slug, 'event': self.request.event.slug, }) + + +class VoucherBulkAction(EventPermissionRequiredMixin, View): + permission = 'can_change_vouchers' + + @cached_property + def objects(self): + return self.request.event.vouchers.filter( + id__in=self.request.POST.getlist('voucher') + ) + + @transaction.atomic + def post(self, request, *args, **kwargs): + if request.POST.get('action') == 'delete': + return render(request, 'pretixcontrol/vouchers/delete_bulk.html', { + 'allowed': self.objects.filter(redeemed=0), + 'forbidden': self.objects.exclude(redeemed=0), + }) + elif request.POST.get('action') == 'delete_confirm': + for obj in self.objects: + if obj.allow_delete(): + obj.log_action('pretix.voucher.deleted', user=self.request.user) + obj.delete() + else: + obj.log_action('pretix.voucher.changed', user=self.request.user, data={ + 'max_usages': min(obj.redeemed, obj.max_usages), + 'bulk': True + }) + obj.max_usages = min(obj.redeemed, obj.max_usages) + obj.save(update_fields=['max_usages']) + messages.success(request, _('The selected vouchers have been deleted or disabled.')) + return redirect(self.get_success_url()) + + def get_success_url(self) -> str: + return reverse('control:event.vouchers', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug, + })