diff --git a/doc/plugins/pretixdroid.rst b/doc/plugins/pretixdroid.rst index a0fa2fe5f2..d62ac2206d 100644 --- a/doc/plugins/pretixdroid.rst +++ b/doc/plugins/pretixdroid.rst @@ -92,6 +92,68 @@ uses to communicate with the pretix server. } :query query: Search query + :query key: Secret API key + :statuscode 200: Valid request + :statuscode 404: Unknown organizer or event + :statuscode 403: Invalid authorization key + +.. http:get:: /pretixdroid/api/(organizer)/(event)/status/ + + Returns status information, such as the total number of tickets and the + number of performed checkins. + + **Example request**: + + .. sourcecode:: http + + GET /pretixdroid/api/demoorga/democon/status/?key=ABCDEF HTTP/1.1 + Host: demo.pretix.eu + Accept: application/json, text/javascript + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: text/json + + { + 'checkins': 17, + 'total': 42, + 'version': 2, + 'items': [ + { + 'name': 'T-Shirt', + 'id': 1, + 'checkins': 1, + 'admission': False, + 'total': 1, + 'variations': [ + { + 'name': 'Red', + 'id': 1, + 'checkins': 1, + 'total': 12 + }, + { + 'name': 'Blue', + 'id': 2, + 'checkins': 4, + 'total': 8 + } + ] + }, + { + 'name': 'Ticket', + 'id': 2, + 'checkins': 15, + 'admission': True, + 'total': 22, + 'variations': [] + } + ] + } + :query key: Secret API key :statuscode 200: Valid request :statuscode 404: Unknown organizer or event diff --git a/src/pretix/plugins/pretixdroid/urls.py b/src/pretix/plugins/pretixdroid/urls.py index e8f005b56d..2f48d39d7b 100644 --- a/src/pretix/plugins/pretixdroid/urls.py +++ b/src/pretix/plugins/pretixdroid/urls.py @@ -9,4 +9,6 @@ urlpatterns = [ name='api.redeem'), url(r'^pretixdroid/api/(?P[^/]+)/(?P[^/]+)/search/', views.ApiSearchView.as_view(), name='api.search'), + url(r'^pretixdroid/api/(?P[^/]+)/(?P[^/]+)/status/', views.ApiStatusView.as_view(), + name='api.status'), ] diff --git a/src/pretix/plugins/pretixdroid/views.py b/src/pretix/plugins/pretixdroid/views.py index a3c9045b3c..36e3e69762 100644 --- a/src/pretix/plugins/pretixdroid/views.py +++ b/src/pretix/plugins/pretixdroid/views.py @@ -3,7 +3,7 @@ import logging import string from django.db import transaction -from django.db.models import Q +from django.db.models import Count, Q from django.http import ( HttpResponseForbidden, HttpResponseNotFound, JsonResponse, ) @@ -133,3 +133,66 @@ class ApiSearchView(ApiView): response['results'] = [] return JsonResponse(response) + + +class ApiStatusView(ApiView): + def get(self, request, **kwargs): + response = { + 'version': API_VERSION, + 'checkins': Checkin.objects.filter( + position__order__event=self.event + ).count(), + 'total': OrderPosition.objects.filter( + order__event=self.event, order__status=Order.STATUS_PAID + ).count() + } + + op_by_item = { + p['item']: p['cnt'] + for p in OrderPosition.objects.filter( + order__event=self.event, + order__status=Order.STATUS_PAID + ).order_by().values('item').annotate(cnt=Count('id')) + } + op_by_variation = { + p['variation']: p['cnt'] + for p in OrderPosition.objects.filter( + order__event=self.event, + order__status=Order.STATUS_PAID + ).order_by().values('variation').annotate(cnt=Count('id')) + } + c_by_item = { + p['position__item']: p['cnt'] + for p in Checkin.objects.filter( + position__order__event=self.event, + position__order__status=Order.STATUS_PAID + ).order_by().values('position__item').annotate(cnt=Count('id')) + } + c_by_variation = { + p['position__variation']: p['cnt'] + for p in Checkin.objects.filter( + position__order__event=self.event, + position__order__status=Order.STATUS_PAID + ).order_by().values('position__variation').annotate(cnt=Count('id')) + } + + response['items'] = [] + for item in self.event.items.prefetch_related('variations'): + i = { + 'id': item.pk, + 'name': str(item), + 'admission': item.admission, + 'checkins': c_by_item.get(item.pk, 0), + 'total': op_by_item.get(item.pk, 0), + 'variations': [] + } + for var in item.variations.all(): + i['variations'].append({ + 'id': var.pk, + 'name': str(var), + 'checkins': c_by_variation.get(var.pk, 0), + 'total': op_by_variation.get(var.pk, 0), + }) + response['items'].append(i) + + return JsonResponse(response) diff --git a/src/tests/plugins/test_pretixdroid.py b/src/tests/plugins/test_pretixdroid.py index 9f32da001a..e3b50336ec 100644 --- a/src/tests/plugins/test_pretixdroid.py +++ b/src/tests/plugins/test_pretixdroid.py @@ -5,7 +5,7 @@ import pytest from django.utils.timezone import now from pretix.base.models import ( - Event, EventPermission, Item, ItemVariation, Order, OrderPosition, + Checkin, Event, EventPermission, Item, ItemVariation, Order, OrderPosition, Organizer, User, ) @@ -111,7 +111,44 @@ def test_search(client, env): env[0].settings.set('pretixdroid_key', 'abcdefg') resp = client.get('/pretixdroid/api/%s/%s/search/?key=%s&query=%s' % ( env[0].organizer.slug, env[0].slug, 'abcdefg', '567891')) - print(resp.content) jdata = json.loads(resp.content.decode("utf-8")) assert len(jdata['results']) == 1 assert jdata['results'][0]['secret'] == '5678910' + + +@pytest.mark.django_db +def test_status(client, env): + env[0].settings.set('pretixdroid_key', 'abcdefg') + Checkin.objects.create(position=env[3]) + resp = client.get('/pretixdroid/api/%s/%s/status/?key=%s' % ( + env[0].organizer.slug, env[0].slug, 'abcdefg')) + jdata = json.loads(resp.content.decode("utf-8")) + assert jdata['checkins'] == 1 + assert jdata['total'] == 2 + assert jdata['items'] == [ + {'name': 'T-Shirt', + 'id': 1, + 'checkins': 1, + 'admission': False, + 'total': 1, + 'variations': [ + {'name': 'Red', + 'id': 1, + 'checkins': 1, + 'total': 1 + }, + {'name': 'Blue', + 'id': 2, + 'checkins': 0, + 'total': 0 + } + ] + }, + {'name': 'Ticket', + 'id': 2, + 'checkins': 0, + 'admission': False, + 'total': 1, + 'variations': [] + } + ]