Show paid tickets instead of available quota in event list

This commit is contained in:
Raphael Michel
2017-10-18 13:05:25 +02:00
parent 0f2b56adb4
commit c616c8ce29
11 changed files with 84 additions and 29 deletions
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.5 on 2017-10-18 09:06
from __future__ import unicode_literals
from django.db import migrations, models
def clear_quota_caches(app, schema_editor):
Quota = app.get_model('pretixbase', 'Quota')
Quota.objects.all().update(cached_availability_time=None)
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0080_auto_20171016_1553'),
]
operations = [
migrations.AddField(
model_name='quota',
name='cached_availability_paid_orders',
field=models.PositiveIntegerField(blank=True, null=True),
),
migrations.RunPython(
clear_quota_caches, migrations.RunPython.noop
)
]
+10 -3
View File
@@ -727,6 +727,7 @@ class Quota(LoggedModel):
) )
cached_availability_state = models.PositiveIntegerField(null=True, blank=True) cached_availability_state = models.PositiveIntegerField(null=True, blank=True)
cached_availability_number = models.PositiveIntegerField(null=True, blank=True) cached_availability_number = models.PositiveIntegerField(null=True, blank=True)
cached_availability_paid_orders = models.PositiveIntegerField(null=True, blank=True)
cached_availability_time = models.DateTimeField(null=True, blank=True) cached_availability_time = models.DateTimeField(null=True, blank=True)
class Meta: class Meta:
@@ -783,8 +784,13 @@ class Quota(LoggedModel):
self.cached_availability_state = res[0] self.cached_availability_state = res[0]
self.cached_availability_number = res[1] self.cached_availability_number = res[1]
self.cached_availability_time = now_dt self.cached_availability_time = now_dt
if self.size is None:
self.cached_availability_paid_orders = self.count_pending_orders()
self.save( self.save(
update_fields=['cached_availability_state', 'cached_availability_number', 'cached_availability_time'], update_fields=[
'cached_availability_state', 'cached_availability_number', 'cached_availability_time',
'cached_availability_paid_orders'
],
clear_cache=False clear_cache=False
) )
@@ -799,8 +805,9 @@ class Quota(LoggedModel):
if size_left is None: if size_left is None:
return Quota.AVAILABILITY_OK, None return Quota.AVAILABILITY_OK, None
# TODO: Test for interference with old versions of Item-Quota-relations, etc. paid_orders = self.count_paid_orders()
size_left -= self.count_paid_orders() self.cached_availability_paid_orders = paid_orders
size_left -= paid_orders
if size_left <= 0: if size_left <= 0:
return Quota.AVAILABILITY_GONE, 0 return Quota.AVAILABILITY_GONE, 0
+2 -2
View File
@@ -10,11 +10,11 @@ from ..signals import periodic_task
@receiver(signal=periodic_task) @receiver(signal=periodic_task)
def build_all_quota_caches(sender, **kwargs): def build_all_quota_caches(sender, **kwargs):
refresh_quota_cashes.apply_async() refresh_quota_caches.apply_async()
@app.task @app.task
def refresh_quota_cashes(): def refresh_quota_caches():
last_activity = LogEntry.objects.filter( last_activity = LogEntry.objects.filter(
event=OuterRef('event_id'), event=OuterRef('event_id'),
).order_by().values('event').annotate( ).order_by().values('event').annotate(
+1 -1
View File
@@ -260,7 +260,7 @@ class EventFilterForm(FilterForm):
'date_from': 'order_from', 'date_from': 'order_from',
'date_to': 'order_to', 'date_to': 'order_to',
'live': 'live', 'live': 'live',
'sum_quota_available': 'sum_quota_available' 'sum_tickets_paid': 'sum_tickets_paid'
} }
status = forms.ChoiceField( status = forms.ChoiceField(
label=_('Status'), label=_('Status'),
@@ -68,9 +68,9 @@
<a href="?{% url_replace request 'ordering' 'date_to' %}"><i class="fa fa-caret-up"></i></a> <a href="?{% url_replace request 'ordering' 'date_to' %}"><i class="fa fa-caret-up"></i></a>
</th> </th>
<th> <th>
{% trans "Quota available" %} {% trans "Paid tickets per quota" %}
<a href="?{% url_replace request 'ordering' '-sum_quota_available' %}"><i class="fa fa-caret-down"></i></a> <a href="?{% url_replace request 'ordering' '-sum_tickets_paid' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'sum_quota_available' %}"><i class="fa fa-caret-up"></i></a> <a href="?{% url_replace request 'ordering' 'sum_tickets_paid' %}"><i class="fa fa-caret-up"></i></a>
</th> </th>
<th class="text-right"> <th class="text-right">
{% trans "Status" %} {% trans "Status" %}
@@ -97,7 +97,7 @@
<span class="label label-default">{% trans "Series" %}</span> <span class="label label-default">{% trans "Series" %}</span>
{% endif %} {% endif %}
{% if e.settings.show_date_to and e.date_to %} {% if e.settings.show_date_to and e.date_to %}
<br> <br>
{% if e.has_subevents %} {% if e.has_subevents %}
{{ e.max_fromto|default_if_none:e.max_from|default_if_none:e.max_to|default_if_none:""|date:"SHORT_DATETIME_FORMAT" }} {{ e.max_fromto|default_if_none:e.max_from|default_if_none:e.max_to|default_if_none:""|date:"SHORT_DATETIME_FORMAT" }}
{% else %} {% else %}
@@ -107,7 +107,7 @@
</td> </td>
<td> <td>
{% for q in e.first_quotas|slice:":3" %} {% for q in e.first_quotas|slice:":3" %}
{% include "pretixcontrol/fragment_quota_box.html" with quota=q %} {% include "pretixcontrol/fragment_quota_box_paid.html" with quota=q %}
{% endfor %} {% endfor %}
{% if e.first_quotas|length > 3 %} {% if e.first_quotas|length > 3 %}
<a href="{% url "control:event.items.quotas" organizer=e.organizer.slug event=e.slug %}" <a href="{% url "control:event.items.quotas" organizer=e.organizer.slug event=e.slug %}"
@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<div class="quotabox" data-toggle="tooltip_html" data-placement="top" <div class="quotabox availability" data-toggle="tooltip_html" data-placement="top"
title="{% trans "Quota:" %} {{ q.name }}<br>{% blocktrans with date=q.cached_availability_time|date:"SHORT_DATETIME_FORMAT" %}Numbers as of {{ date }}{% endblocktrans %}"> title="{% trans "Quota:" %} {{ q.name }}<br>{% blocktrans with date=q.cached_availability_time|date:"SHORT_DATETIME_FORMAT" %}Numbers as of {{ date }}{% endblocktrans %}">
{% if q.size|default_if_none:"NONE" == "NONE" %} {% if q.size|default_if_none:"NONE" == "NONE" %}
<div class="progress"> <div class="progress">
@@ -0,0 +1,16 @@
{% load i18n %}
<div class="quotabox" data-toggle="tooltip_html" data-placement="top"
title="{% trans "Quota:" %} {{ q.name }}<br>{% blocktrans with date=q.cached_availability_time|date:"SHORT_DATETIME_FORMAT" %}Numbers as of {{ date }}{% endblocktrans %}{% if q.cached_avail.1 is not None %}<br>{% blocktrans with num=q.cached_avail.1 %}Currently available: {{ num }}{% endblocktrans %}{% endif %}">
{% if q.size|default_if_none:"NONE" == "NONE" %}
<div class="progress">
</div>
{% else %}
<div class="progress">
<div class="progress-bar progress-bar-{% if q.cached_avail.0 < 10 %}danger{% elif q.cached_avail.0 < 100 %}warning{% else %}success{% endif %} progress-bar-{{ q.percent_paid }}">
</div>
</div>
{% endif %}
<div class="numbers">
{{ q.cached_availability_paid_orders|default_if_none:"?" }} / {{ q.size|default_if_none:"∞" }}
</div>
</div>
@@ -52,9 +52,9 @@
<a href="?{% url_replace request 'ordering' 'date_from' %}"><i class="fa fa-caret-up"></i></a> <a href="?{% url_replace request 'ordering' 'date_from' %}"><i class="fa fa-caret-up"></i></a>
</th> </th>
<th> <th>
{% trans "Quota available" %} {% trans "Paid tickets per quota" %}
<a href="?{% url_replace request 'ordering' '-sum_quota_available' %}"><i class="fa fa-caret-down"></i></a> <a href="?{% url_replace request 'ordering' '-sum_tickets_paid' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'sum_quota_available' %}"><i class="fa fa-caret-up"></i></a> <a href="?{% url_replace request 'ordering' 'sum_tickets_paid' %}"><i class="fa fa-caret-up"></i></a>
</th> </th>
<th> <th>
{% trans "Status" %} {% trans "Status" %}
@@ -74,7 +74,7 @@
<td>{{ s.get_date_from_display }}</td> <td>{{ s.get_date_from_display }}</td>
<td> <td>
{% for q in s.first_quotas|slice:":3" %} {% for q in s.first_quotas|slice:":3" %}
{% include "pretixcontrol/fragment_quota_box.html" with quota=q %} {% include "pretixcontrol/fragment_quota_box_paid.html" with quota=q %}
{% endfor %} {% endfor %}
{% if s.first_quotas|length > 3 %} {% if s.first_quotas|length > 3 %}
<a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}?subevent={{ s.id }}" <a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}?subevent={{ s.id }}"
+8 -6
View File
@@ -44,16 +44,16 @@ class EventList(ListView):
order_to=Coalesce('max_fromto', 'max_to', 'max_from', 'date_to'), order_to=Coalesce('max_fromto', 'max_to', 'max_from', 'date_to'),
) )
sum_quota_available = Quota.objects.filter( sum_tickets_paid = Quota.objects.filter(
event=OuterRef('pk'), subevent__isnull=True event=OuterRef('pk'), subevent__isnull=True
).order_by().values('event').annotate( ).order_by().values('event').annotate(
s=Sum('cached_availability_number') s=Sum('cached_availability_paid_orders')
).values( ).values(
's' 's'
) )
qs = qs.annotate( qs = qs.annotate(
sum_quota_available=Subquery(sum_quota_available, output_field=IntegerField()) sum_tickets_paid=Subquery(sum_tickets_paid, output_field=IntegerField())
).prefetch_related( ).prefetch_related(
Prefetch('quotas', Prefetch('quotas',
queryset=Quota.objects.filter(subevent__isnull=True).annotate(s=Coalesce(F('size'), 0)).order_by('-s'), queryset=Quota.objects.filter(subevent__isnull=True).annotate(s=Coalesce(F('size'), 0)).order_by('-s'),
@@ -80,9 +80,11 @@ class EventList(ListView):
if q.cached_availability_time is not None if q.cached_availability_time is not None
else q.availability(allow_cache=True) else q.availability(allow_cache=True)
) )
if q.cached_avail[1] is not None: if q.size is not None:
q.percent = round(q.cached_avail[1] / q.size * 100) if q.size > 0 else 0 q.percent_paid = min(
q.inv_percent = 100 - q.percent 100,
round(q.cached_availability_paid_orders / q.size * 100) if q.size > 0 else 100
)
return ctx return ctx
@cached_property @cached_property
+8 -6
View File
@@ -31,16 +31,16 @@ class SubEventList(EventPermissionRequiredMixin, ListView):
permission = 'can_change_settings' permission = 'can_change_settings'
def get_queryset(self): def get_queryset(self):
sum_quota_available = Quota.objects.filter( sum_tickets_paid = Quota.objects.filter(
subevent=OuterRef('pk') subevent=OuterRef('pk')
).order_by().values('subevent').annotate( ).order_by().values('subevent').annotate(
s=Sum('cached_availability_number') s=Sum('cached_availability_paid_orders')
).values( ).values(
's' 's'
) )
qs = self.request.event.subevents.annotate( qs = self.request.event.subevents.annotate(
sum_quota_available=Subquery(sum_quota_available, output_field=IntegerField()) sum_tickets_paid=Subquery(sum_tickets_paid, output_field=IntegerField())
).prefetch_related( ).prefetch_related(
Prefetch('quotas', Prefetch('quotas',
queryset=Quota.objects.annotate(s=Coalesce(F('size'), 0)).order_by('-s'), queryset=Quota.objects.annotate(s=Coalesce(F('size'), 0)).order_by('-s'),
@@ -61,9 +61,11 @@ class SubEventList(EventPermissionRequiredMixin, ListView):
if q.cached_availability_time is not None if q.cached_availability_time is not None
else q.availability(allow_cache=True) else q.availability(allow_cache=True)
) )
if q.cached_avail[1] is not None: if q.size is not None:
q.percent = round(q.cached_avail[1] / q.size * 100) if q.size > 0 else 0 q.percent_paid = min(
q.inv_percent = 100 - q.percent 100,
round(q.cached_availability_paid_orders / q.size * 100) if q.size > 0 else 100
)
return ctx return ctx
@cached_property @cached_property
@@ -418,7 +418,7 @@ body.loading #wrapper {
display: block; display: block;
text-align: center; text-align: center;
} }
.progress-bar-success { &.availability .progress-bar-success {
background: lighten($brand-success, 20%); background: lighten($brand-success, 20%);
} }
} }