mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Allow quotas to "close" when once full (#1344)
* Model * Some UI * API and logging * Permission check * Add tests * Move option around
This commit is contained in:
@@ -169,7 +169,8 @@ class QuotaForm(I18nModelForm):
|
||||
fields = [
|
||||
'name',
|
||||
'size',
|
||||
'subevent'
|
||||
'subevent',
|
||||
'close_when_sold_out'
|
||||
]
|
||||
field_classes = {
|
||||
'subevent': SafeModelChoiceField,
|
||||
|
||||
@@ -263,6 +263,8 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.quota.added': _('The quota has been added.'),
|
||||
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
||||
'pretix.event.quota.changed': _('The quota has been changed.'),
|
||||
'pretix.event.quota.closed': _('The quota has closed.'),
|
||||
'pretix.event.quota.opened': _('The quota has been re-opened.'),
|
||||
'pretix.event.category.added': _('The category has been added.'),
|
||||
'pretix.event.category.deleted': _('The category has been deleted.'),
|
||||
'pretix.event.category.changed': _('The category has been changed.'),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{% load i18n %}
|
||||
{% if availability.0 == 10 %}
|
||||
{% if closed %}
|
||||
<span class="label label-danger">{% trans "Closed" %}</span>
|
||||
{% elif availability.0 == 10 %}
|
||||
<span class="label label-warning">{% trans "Sold out (pending orders)" %}</span>
|
||||
{% elif availability.0 == 100 %}
|
||||
{% if availability.1 != None %}
|
||||
|
||||
@@ -20,6 +20,27 @@
|
||||
<span class="fa fa-calendar"></span> {{ quota.subevent.name }} – {{ quota.subevent.get_date_range_display }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% if quota.closed %}
|
||||
{% if closed_and_sold_out %}
|
||||
<div class="alert alert-info">
|
||||
<button type="submit" class="btn btn-default pull-right" name="disable" value="true">
|
||||
{% trans "Open quota and disable closing" %}
|
||||
</button>
|
||||
{% trans "This quota is sold out and closed. Even if tickets become available e.g. through cancellations, they will not become available again unless you manually re-open the quota on this page." %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="submit" class="btn btn-primary pull-right" name="reopen" value="true">{% trans "Open quota" %}</button>
|
||||
{% trans "This quota is closed since it has been sold out before. Tickets are theoretically available, but will not be sold unless you manually re-open the quota." %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="row" id="quota-stats">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<legend>{% trans "Usage overview" %}</legend>
|
||||
@@ -30,7 +51,6 @@
|
||||
</div>
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<legend>{% trans "Availability calculation" %}</legend>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-9">{% trans "Total quota" %}</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
{% if form.subevent %}
|
||||
{% bootstrap_field form.subevent layout="control" %}
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Items" %}</legend>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
@@ -35,6 +37,10 @@
|
||||
</p>
|
||||
{% bootstrap_field form.itemvars layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Advanced options" %}</legend>
|
||||
{% bootstrap_field form.close_when_sold_out layout="control" %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<td>{{ q.subevent.name }} – {{ q.subevent.get_date_range_display }}</td>
|
||||
{% endif %}
|
||||
<td>{% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %}</td>
|
||||
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.availability %}</td>
|
||||
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.availability closed=q.closed %}</td>
|
||||
<td class="text-right">
|
||||
<a href="{% url "control:event.items.quotas.edit" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "control:event.items.quotas.delete" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.files import File
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, F, Prefetch, Q
|
||||
@@ -684,6 +685,8 @@ class QuotaView(ChartContainingView, DetailView):
|
||||
Q(Q(self.object._position_lookup) | Q(quota=self.object)) &
|
||||
Q(redeemed__lt=F('max_usages'))
|
||||
).exists()
|
||||
if self.object.closed:
|
||||
ctx['closed_and_sold_out'] = self.object._availability(ignore_closed=True)[0] <= Quota.AVAILABILITY_ORDERED
|
||||
|
||||
return ctx
|
||||
|
||||
@@ -695,6 +698,32 @@ class QuotaView(ChartContainingView, DetailView):
|
||||
except Quota.DoesNotExist:
|
||||
raise Http404(_("The requested quota does not exist."))
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_items', request):
|
||||
raise PermissionDenied()
|
||||
quota = self.get_object()
|
||||
if 'reopen' in request.POST:
|
||||
quota.closed = False
|
||||
quota.save(update_fields=['closed'])
|
||||
quota.log_action('pretix.event.quota.opened', user=request.user)
|
||||
messages.success(request, _('The quota has been re-opened.'))
|
||||
if 'disable' in request.POST:
|
||||
quota.closed = False
|
||||
quota.close_when_sold_out = False
|
||||
quota.save(update_fields=['closed', 'close_when_sold_out'])
|
||||
quota.log_action('pretix.event.quota.opened', user=request.user)
|
||||
quota.log_action(
|
||||
'pretix.event.quota.changed', user=self.request.user, data={
|
||||
'close_when_sold_out': False
|
||||
}
|
||||
)
|
||||
messages.success(request, _('The quota has been re-opened and will not close again.'))
|
||||
return redirect(reverse('control:event.items.quotas.show', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
'quota': quota.pk
|
||||
}))
|
||||
|
||||
|
||||
class QuotaUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Quota
|
||||
|
||||
Reference in New Issue
Block a user