diff --git a/src/pretix/control/templates/pretixcontrol/items/quota.html b/src/pretix/control/templates/pretixcontrol/items/quota.html
index cb9d964935..e1f07d33ba 100644
--- a/src/pretix/control/templates/pretixcontrol/items/quota.html
+++ b/src/pretix/control/templates/pretixcontrol/items/quota.html
@@ -43,6 +43,21 @@
{% if quota.size == None %}{% trans "Infinite" %}{% else %}{{ avail.1 }}{% endif %}
+ {% if quota_overbooked > 0 %}
+
+ {% blocktrans trimmed with num=quota_overbooked %}
+ This quota is currently overbooked by {{ num }} tickets.
+ {% endblocktrans %}
+
+ {% endif %}
+ {% if has_ignore_vouchers %}
+
+ {% blocktrans trimmed %}
+ Your event contains vouchers that affect products covered by this quota and that
+ allow a user to buy products even if this quota is sold out.
+ {% endblocktrans %}
+
+ {% endif %}
{% eventsignal request.event "pretix.control.signals.quota_detail_html" quota=quota %}
diff --git a/src/pretix/control/views/item.py b/src/pretix/control/views/item.py
index 861094930b..191d4422e8 100644
--- a/src/pretix/control/views/item.py
+++ b/src/pretix/control/views/item.py
@@ -4,7 +4,7 @@ from django.contrib import messages
from django.core.files import File
from django.core.urlresolvers import resolve, reverse
from django.db import transaction
-from django.db.models import Count
+from django.db.models import Count, F, Q
from django.forms.models import ModelMultipleChoiceField, inlineformset_factory
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import redirect
@@ -19,7 +19,7 @@ from django.views.generic.edit import DeleteView
from pretix.base.forms import I18nFormSet
from pretix.base.models import (
CachedTicket, Item, ItemCategory, ItemVariation, Order, Question,
- QuestionAnswer, QuestionOption, Quota,
+ QuestionAnswer, QuestionOption, Quota, Voucher,
)
from pretix.control.forms.item import (
CategoryForm, ItemCreateForm, ItemUpdateForm, ItemVariationForm,
@@ -624,12 +624,24 @@ class QuotaView(ChartContainingView, DetailView):
]
ctx['quota_table_rows'] = list(data)
+ sum_values = sum([d['value'] for d in data])
+
if self.object.size is not None:
data.append({
'label': ugettext('Current availability'),
'value': avail[1]
})
+
ctx['quota_chart_data'] = json.dumps(data)
+ ctx['quota_overbooked'] = sum_values - self.object.size if self.object.size is not None else 0
+
+ ctx['has_ignore_vouchers'] = Voucher.objects.filter(
+ Q(allow_ignore_quota=True) &
+ Q(Q(valid_until__isnull=True) | Q(valid_until__gte=now())) &
+ Q(Q(self.object._position_lookup) | Q(quota=self.object)) &
+ Q(redeemed__lt=F('max_usages'))
+ ).exists()
+
return ctx
def get_object(self, queryset=None) -> Quota:
@@ -672,9 +684,10 @@ class QuotaUpdate(EventPermissionRequiredMixin, QuotaEditorMixin, UpdateView):
return super().form_valid(form)
def get_success_url(self) -> str:
- return reverse('control:event.items.quotas', kwargs={
+ return reverse('control:event.items.quotas.show', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
+ 'quota': self.object.pk
})