API: Add list and case-insensitive filters to order(positions) resource

This commit is contained in:
Raphael Michel
2018-04-24 18:25:51 +02:00
parent edbdb17a2f
commit ad697369ef
5 changed files with 69 additions and 22 deletions
+16 -2
View File
@@ -254,6 +254,12 @@ Endpoints
Order position endpoints
------------------------
.. versionchanged:: 1.15
The order positions endpoint has been extended by the filter queries ``item__in``, ``variation__in``,
``order__status__in``, ``subevent__in``, and ``addon_to__in``. The search for attendee names and order codes is now
case-insensitive.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/
Returns a list of all order positions within a given event. The result is the same as
@@ -326,14 +332,22 @@ Order position endpoints
``attendee_name,positionid``
:query string order: Only return positions of the order with the given order code
:query integer item: Only return positions with the purchased item matching the given ID.
:query integer item__in: Only return positions with the purchased item matching one of the given comma-separated IDs.
:query integer variation: Only return positions with the purchased item variation matching the given ID.
:query integer variation__in: Only return positions with one of the purchased item variation matching the given
comma-separated IDs.
:query string attendee_name: Only return positions with the given value in the attendee_name field. Also, add-on
products positions are shown if they refer to an attendee with the given name.
:query string secret: Only return positions with the given ticket secret.
:query bollean has_checkin: If set to ``true`` or ``false``, only return positions that have or have not been
checked in already on this list.
:query string order__status: Only return positions with the given order status.
:query string order__status__in: Only return positions with one the given comma-separated order status.
:query boolean has_checkin: If set to ``true`` or ``false``, only return positions that have or have not been
checked in already.
:query integer subevent: Only return positions of the sub-event with the given ID
:query integer subevent__in: Only return positions of one of the sub-events with the given comma-separated IDs
:query integer addon_to: Only return positions that are add-ons to the position with the given ID.
:query integer addon_to__in: Only return positions that are add-ons to one of the positions with the given
comma-separated IDs.
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param list: The ID of the check-in list to look for
+18 -1
View File
@@ -150,6 +150,10 @@ answers list of objects Answers to user
Order endpoints
---------------
.. versionchanged:: 1.15
Filtering for emails or order codes is now case-insensitive.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orders/
Returns a list of all orders within a given event.
@@ -609,6 +613,12 @@ Order endpoints
Order position endpoints
------------------------
.. versionchanged:: 1.15
The order positions endpoint has been extended by the filter queries ``item__in``, ``variation__in``,
``order__status__in``, ``subevent__in``, and ``addon_to__in``. The search for attendee names and order codes is now
case-insensitive.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/
Returns a list of all order positions within a given event.
@@ -681,15 +691,22 @@ Order position endpoints
``order__datetime,positionid``
:query string order: Only return positions of the order with the given order code
:query integer item: Only return positions with the purchased item matching the given ID.
:query integer item__in: Only return positions with the purchased item matching one of the given comma-separated IDs.
:query integer variation: Only return positions with the purchased item variation matching the given ID.
:query integer variation__in: Only return positions with one of the purchased item variation matching the given
comma-separated IDs.
:query string attendee_name: Only return positions with the given value in the attendee_name field. Also, add-on
products positions are shown if they refer to an attendee with the given name.
:query string secret: Only return positions with the given ticket secret.
:query string order__status: Only return positions with the given order status.
:query bollean has_checkin: If set to ``true`` or ``false``, only return positions that have or have not been
:query string order__status__in: Only return positions with one the given comma-separated order status.
:query boolean has_checkin: If set to ``true`` or ``false``, only return positions that have or have not been
checked in already.
:query integer subevent: Only return positions of the sub-event with the given ID
:query integer subevent__in: Only return positions of one of the sub-events with the given comma-separated IDs
:query integer addon_to: Only return positions that are add-ons to the position with the given ID.
:query integer addon_to__in: Only return positions that are add-ons to one of the positions with the given
comma-separated IDs.
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:statuscode 200: no error
+4 -14
View File
@@ -1,5 +1,4 @@
import django_filters
from django.db.models import F, Max, OuterRef, Prefetch, Q, Subquery
from django.db.models import F, Max, OuterRef, Prefetch, Subquery
from django.db.models.functions import Coalesce
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property
@@ -9,6 +8,7 @@ from rest_framework import viewsets
from pretix.api.serializers.checkin import CheckinListSerializer
from pretix.api.serializers.order import OrderPositionSerializer
from pretix.api.views import RichOrderingFilter
from pretix.api.views.order import OrderPositionFilter
from pretix.base.models import Checkin, CheckinList, Order, OrderPosition
from pretix.base.models.organizer import TeamAPIToken
from pretix.helpers.database import FixedOrderBy
@@ -67,21 +67,11 @@ class CheckinListViewSet(viewsets.ModelViewSet):
super().perform_destroy(instance)
class OrderPositionFilter(FilterSet):
order = django_filters.CharFilter(name='order', lookup_expr='code')
has_checkin = django_filters.rest_framework.BooleanFilter(method='has_checkin_qs')
attendee_name = django_filters.CharFilter(method='attendee_name_qs')
class CheckinOrderPositionFilter(OrderPositionFilter):
def has_checkin_qs(self, queryset, name, value):
return queryset.filter(last_checked_in__isnull=not value)
def attendee_name_qs(self, queryset, name, value):
return queryset.filter(Q(attendee_name=value) | Q(addon_to__attendee_name=value))
class Meta:
model = OrderPosition
fields = ['item', 'variation', 'attendee_name', 'secret', 'order', 'has_checkin', 'addon_to', 'subevent']
class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = OrderPositionSerializer
@@ -109,7 +99,7 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
},
}
filter_class = OrderPositionFilter
filter_class = CheckinOrderPositionFilter
permission = 'can_view_orders'
@cached_property
+14 -4
View File
@@ -31,6 +31,10 @@ from pretix.base.signals import register_ticket_outputs
class OrderFilter(FilterSet):
email = django_filters.CharFilter(name='email', lookup_expr='iexact')
code = django_filters.CharFilter(name='code', lookup_expr='iexact')
status = django_filters.CharFilter(name='status', lookup_expr='iexact')
class Meta:
model = Order
fields = ['code', 'status', 'email', 'locale']
@@ -207,7 +211,7 @@ class OrderViewSet(viewsets.ReadOnlyModelViewSet):
class OrderPositionFilter(FilterSet):
order = django_filters.CharFilter(name='order', lookup_expr='code')
order = django_filters.CharFilter(name='order', lookup_expr='code__iexact')
has_checkin = django_filters.rest_framework.BooleanFilter(method='has_checkin_qs')
attendee_name = django_filters.CharFilter(method='attendee_name_qs')
@@ -215,12 +219,18 @@ class OrderPositionFilter(FilterSet):
return queryset.filter(checkins__isnull=not value)
def attendee_name_qs(self, queryset, name, value):
return queryset.filter(Q(attendee_name=value) | Q(addon_to__attendee_name=value))
return queryset.filter(Q(attendee_name__iexact=value) | Q(addon_to__attendee_name__iexact=value))
class Meta:
model = OrderPosition
fields = ['item', 'variation', 'attendee_name', 'secret', 'order', 'order__status', 'has_checkin',
'addon_to', 'subevent']
fields = {
'item': ['exact', 'in'],
'variation': ['exact', 'in'],
'secret': ['exact'],
'order__status': ['exact', 'in'],
'addon_to': ['exact', 'in'],
'subevent': ['exact', 'in']
}
class OrderPositionViewSet(viewsets.ReadOnlyModelViewSet):
+17 -1
View File
@@ -1,3 +1,4 @@
import copy
import datetime
from decimal import Decimal
from distutils.version import LooseVersion
@@ -203,7 +204,10 @@ def test_order_detail(token_client, organizer, event, order, item, taxrule, ques
@pytest.mark.django_db
def test_orderposition_list(token_client, organizer, event, order, item, subevent, question):
def test_orderposition_list(token_client, organizer, event, order, item, subevent, subevent2, question):
i2 = copy.copy(item)
i2.pk = None
i2.save()
var = item.variations.create(value="Children")
res = dict(TEST_ORDERPOSITION_RES)
op = order.positions.first()
@@ -228,6 +232,11 @@ def test_orderposition_list(token_client, organizer, event, order, item, subeven
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, item.pk))
assert [res] == resp.data['results']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?item__in={},{}'.format(
organizer.slug, event.slug, item.pk, i2.pk
))
assert [res] == resp.data['results']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, item.pk + 1))
assert [] == resp.data['results']
@@ -242,6 +251,9 @@ def test_orderposition_list(token_client, organizer, event, order, item, subeven
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Peter'.format(organizer.slug, event.slug))
assert [res] == resp.data['results']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=peter'.format(organizer.slug, event.slug))
assert [res] == resp.data['results']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Mark'.format(organizer.slug, event.slug))
assert [] == resp.data['results']
@@ -282,6 +294,10 @@ def test_orderposition_list(token_client, organizer, event, order, item, subeven
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
assert [res] == resp.data['results']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent__in={},{}'.format(organizer.slug, event.slug,
subevent.pk, subevent2.pk))
assert [res] == resp.data['results']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug,
subevent.pk + 1))