Add basic sale statistics (closes #57)

This commit is contained in:
Raphael Michel
2015-04-17 21:54:38 +02:00
parent 747a9e55fd
commit 51b2201f3b
5 changed files with 110 additions and 7 deletions

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-15 10:03+0200\n"
"PO-Revision-Date: 2015-04-15 10:31+0100\n"
"PO-Revision-Date: 2015-04-17 21:32+0100\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: Raphael Michel <michel@rami.io>\n"
"Language: de\n"
@@ -1113,7 +1113,7 @@ msgstr "Zahlung ausstehend"
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html:6
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html:6
msgid "Paid"
msgstr "Bezahlt"
msgstr "bezahlt"
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html:10
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html:10
@@ -1123,7 +1123,7 @@ msgstr "storniert"
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html:12
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html:12
msgid "Refunded"
msgstr "Erstattet"
msgstr "erstattet"
#: pretix/control/templates/pretixcontrol/orders/index.html:11
msgid "Order total"

View File

@@ -6,6 +6,7 @@
@import "sb-admin-2.less";
@import "forms.less";
@import "flags.less";
@import "orders.less";
footer {
text-align: center;

View File

@@ -81,11 +81,25 @@
</ul>
</li>
<li>
<a href="{% url 'control:event.orders' organizer=request.event.organizer.slug event=request.event.slug %}"
{% if "event.order" in url_name %}class="active"{% endif %}>
<a href="#">
<i class="fa fa-shopping-cart fa-fw"></i>
{% trans "Orders" %}
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li>
<a href="{% url 'control:event.orders' organizer=request.event.organizer.slug event=request.event.slug %}"
{% if url_name == "event.orders" or "event.order." in url_name %}class="active"{% endif %}>
{% trans "All orders" %}
</a>
</li>
<li>
<a href="{% url 'control:event.orders.overview' organizer=request.event.organizer.slug event=request.event.slug %}"
{% if url_name == "event.orders.overview" %}class="active"{% endif %}>
{% trans "Overview" %}
</a>
</li>
</ul>
</li>
{% for nav in nav_event %}
<li>

View File

@@ -52,6 +52,7 @@ urlpatterns = [
url(r'^orders/(?P<code>[0-9A-Z]+)/extend$', orders.OrderExtend.as_view(),
name='event.order.extend'),
url(r'^orders/(?P<code>[0-9A-Z]+)/$', orders.OrderDetail.as_view(), name='event.order'),
url(r'^orders/overview/$', orders.OverView.as_view(), name='event.orders.overview'),
url(r'^orders/$', orders.OrderList.as_view(), name='event.orders'),
])),
]

View File

@@ -1,15 +1,16 @@
from itertools import groupby
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.db.models import Count
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.utils.functional import cached_property
from django.views.generic import ListView, DetailView
from django.views.generic import ListView, DetailView, TemplateView
from pretix.base.forms import VersionedModelForm
from pretix.base.models import Order, Quota
from pretix.base.models import Order, Quota, OrderPosition
from pretix.base.signals import register_payment_providers
from pretix.control.permissions import EventPermissionRequiredMixin
@@ -203,3 +204,89 @@ class OrderExtend(OrderView):
def form(self):
return ExtendForm(instance=self.order,
data=self.request.POST if self.request.method == "POST" else None)
class OverView(EventPermissionRequiredMixin, TemplateView):
template_name = 'pretixcontrol/orders/overview.html'
permission = 'can_view_orders'
def get_context_data(self, **kwargs):
ctx = super().get_context_data()
items = self.request.event.items.all().select_related(
'category', # for re-grouping
).prefetch_related(
'properties', # for .get_all_available_variations()
).order_by('category__position', 'category_id', 'name')
num_total = {
(p['item'], p['variation']): p['cnt']
for p in OrderPosition.objects.current.filter(
order__event=self.request.event
).values('item', 'variation').annotate(cnt=Count('id'))
}
num_cancelled = {
(p['item'], p['variation']): p['cnt']
for p in OrderPosition.objects.current.filter(
order__event=self.request.event, order__status=Order.STATUS_CANCELLED
).values('item', 'variation').annotate(cnt=Count('id'))
}
num_refunded = {
(p['item'], p['variation']): p['cnt']
for p in OrderPosition.objects.current.filter(
order__event=self.request.event, order__status=Order.STATUS_REFUNDED
).values('item', 'variation').annotate(cnt=Count('id'))
}
num_pending = {
(p['item'], p['variation']): p['cnt']
for p in OrderPosition.objects.current.filter(
order__event=self.request.event, order__status__in=(Order.STATUS_PENDING, Order.STATUS_EXPIRED)
).values('item', 'variation').annotate(cnt=Count('id'))
}
num_paid = {
(p['item'], p['variation']): p['cnt']
for p in OrderPosition.objects.current.filter(
order__event=self.request.event, order__status=Order.STATUS_PAID
).values('item', 'variation').annotate(cnt=Count('id'))
}
for item in items:
item.all_variations = sorted(item.get_all_variations(),
key=lambda vd: vd.ordered_values())
for var in item.all_variations:
variid = var['variation'].identity if 'variation' in var else None
var.num_total = num_total.get((item.identity, variid), 0)
var.num_pending = num_pending.get((item.identity, variid), 0)
var.num_cancelled = num_cancelled.get((item.identity, variid), 0)
var.num_refunded = num_refunded.get((item.identity, variid), 0)
var.num_paid = num_paid.get((item.identity, variid), 0)
item.has_variations = (len(item.all_variations) != 1
or not item.all_variations[0].empty())
item.num_total = sum(var.num_total for var in item.all_variations)
item.num_pending = sum(var.num_pending for var in item.all_variations)
item.num_cancelled = sum(var.num_cancelled for var in item.all_variations)
item.num_refunded = sum(var.num_refunded for var in item.all_variations)
item.num_paid = sum(var.num_paid for var in item.all_variations)
# Regroup those by category
ctx['items_by_category'] = sorted([
# a group is a tuple of a category and a list of items
(cat, [i for i in items if i.category == cat])
for cat in set([i.category for i in items]) # insert categories into a set for uniqueness
# a set is unsorted, so sort again by category
], key=lambda group: (group[0].position, group[0].identity) if group[0] is not None else (0, ""))
for c in ctx['items_by_category']:
c[0].num_total = sum(item.num_total for item in c[1])
c[0].num_pending = sum(item.num_pending for item in c[1])
c[0].num_cancelled = sum(item.num_cancelled for item in c[1])
c[0].num_refunded = sum(item.num_refunded for item in c[1])
c[0].num_paid = sum(item.num_paid for item in c[1])
ctx['total'] = {
'num_total': sum(c.num_total for c, i in ctx['items_by_category']),
'num_pending': sum(c.num_pending for c, i in ctx['items_by_category']),
'num_cancelled': sum(c.num_cancelled for c, i in ctx['items_by_category']),
'num_refunded': sum(c.num_refunded for c, i in ctx['items_by_category']),
'num_paid': sum(c.num_total for c, i in ctx['items_by_category'])
}
return ctx