mirror of
https://github.com/pretix/pretix.git
synced 2026-08-14 11:26:26 +00:00
API: Add various filtering options
* API: Add various filtering options (#23158339) * fix query-param description * simplify payment provider qs-filter --------- Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
co-authored by
Richard Schreiber
parent
2aa989c293
commit
8d6d885f6e
@@ -56,10 +56,17 @@ from pretix.base.models import (
|
||||
)
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.helpers.dicts import merge_dicts
|
||||
from pretix.helpers.i18n import i18ncomp
|
||||
|
||||
with scopes_disabled():
|
||||
class ItemFilter(FilterSet):
|
||||
tax_rate = django_filters.CharFilter(method='tax_rate_qs')
|
||||
search = django_filters.CharFilter(method='search_qs')
|
||||
|
||||
def search_qs(self, queryset, name, value):
|
||||
return queryset.filter(
|
||||
Q(internal_name__icontains=value) | Q(name__icontains=i18ncomp(value))
|
||||
)
|
||||
|
||||
def tax_rate_qs(self, queryset, name, value):
|
||||
if value in ("0", "None", "0.00"):
|
||||
@@ -71,6 +78,18 @@ with scopes_disabled():
|
||||
model = Item
|
||||
fields = ['active', 'category', 'admission', 'tax_rate', 'free_price']
|
||||
|
||||
class ItemVariationFilter(FilterSet):
|
||||
search = django_filters.CharFilter(method='search_qs')
|
||||
|
||||
def search_qs(self, queryset, name, value):
|
||||
return queryset.filter(
|
||||
Q(value__icontains=i18ncomp(value))
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = ItemVariation
|
||||
fields = ['active']
|
||||
|
||||
|
||||
class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = ItemSerializer
|
||||
@@ -140,6 +159,7 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = ItemVariationSerializer
|
||||
queryset = ItemVariation.objects.none()
|
||||
filter_backends = (DjangoFilterBackend, TotalOrderingFilter,)
|
||||
filterset_class = ItemVariationFilter
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
|
||||
@@ -108,6 +108,7 @@ with scopes_disabled():
|
||||
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
|
||||
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
|
||||
created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
|
||||
created_before = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='lt')
|
||||
subevent_after = django_filters.IsoDateTimeFilter(method='subevent_after_qs')
|
||||
subevent_before = django_filters.IsoDateTimeFilter(method='subevent_before_qs')
|
||||
search = django_filters.CharFilter(method='search_qs')
|
||||
@@ -115,6 +116,8 @@ with scopes_disabled():
|
||||
variation = django_filters.CharFilter(field_name='all_positions', lookup_expr='variation_id', distinct=True)
|
||||
subevent = django_filters.CharFilter(field_name='all_positions', lookup_expr='subevent_id', distinct=True)
|
||||
customer = django_filters.CharFilter(field_name='customer__identifier')
|
||||
sales_channel = django_filters.CharFilter(field_name='sales_channel__identifier')
|
||||
payment_provider = django_filters.CharFilter(method='provider_qs')
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
@@ -138,6 +141,11 @@ with scopes_disabled():
|
||||
)
|
||||
return qs
|
||||
|
||||
def provider_qs(self, qs, name, value):
|
||||
return qs.filter(Exists(
|
||||
OrderPayment.objects.filter(order=OuterRef('pk'), provider=value)
|
||||
))
|
||||
|
||||
def subevent_before_qs(self, qs, name, value):
|
||||
if getattr(self.request, 'event', None):
|
||||
subevents = self.request.event.subevents
|
||||
|
||||
@@ -24,10 +24,11 @@ from decimal import Decimal
|
||||
import django_filters
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.db import transaction
|
||||
from django.db.models import OuterRef, Subquery, Sum
|
||||
from django.db.models import OuterRef, Q, Subquery, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import mixins, serializers, status, views, viewsets
|
||||
@@ -136,11 +137,19 @@ class SeatingPlanViewSet(viewsets.ModelViewSet):
|
||||
with scopes_disabled():
|
||||
class GiftCardFilter(FilterSet):
|
||||
secret = django_filters.CharFilter(field_name='secret', lookup_expr='iexact')
|
||||
expired = django_filters.BooleanFilter(method='expired_qs')
|
||||
value = django_filters.NumberFilter(field_name='cached_value')
|
||||
|
||||
class Meta:
|
||||
model = GiftCard
|
||||
fields = ['secret', 'testmode']
|
||||
|
||||
def expired_qs(self, qs, name, value):
|
||||
if value:
|
||||
return qs.filter(expires__isnull=False, expires__lt=now())
|
||||
else:
|
||||
return qs.filter(Q(expires__isnull=True) | Q(expires__gte=now()))
|
||||
|
||||
|
||||
class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = GiftCardSerializer
|
||||
|
||||
@@ -86,6 +86,18 @@ def test_giftcard_list(token_client, organizer, event, giftcard, other_giftcard)
|
||||
assert resp.status_code == 200
|
||||
assert 2 == len(resp.data['results'])
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?expired=false'.format(organizer.slug))
|
||||
assert 1 == len(resp.data['results'])
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?expired=true'.format(organizer.slug))
|
||||
assert 0 == len(resp.data['results'])
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=23.00'.format(organizer.slug))
|
||||
assert 1 == len(resp.data['results'])
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=23'.format(organizer.slug))
|
||||
assert 1 == len(resp.data['results'])
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=24'.format(organizer.slug))
|
||||
assert 0 == len(resp.data['results'])
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_giftcard_detail(token_client, organizer, event, giftcard):
|
||||
|
||||
@@ -370,6 +370,13 @@ def test_item_list(token_client, organizer, event, team, item):
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/?search=Budget'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/?search=Free'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_item_detail(token_client, organizer, event, team, item):
|
||||
@@ -1412,6 +1419,21 @@ def test_variations_list(token_client, organizer, event, item, variation):
|
||||
assert res['position'] == resp.data['results'][0]['position']
|
||||
assert res['price'] == resp.data['results'][0]['price']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?active=true'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res['value'] == resp.data['results'][0]['value']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/variations/?active=false'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?search=Child'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res['value'] == resp.data['results'][0]['value']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?search=Incorrect'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variations_detail(token_client, organizer, event, item, variation):
|
||||
|
||||
@@ -414,6 +414,16 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi
|
||||
'/api/v1/organizers/{}/events/{}/orders/?email=foo@example.org'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=banktransfer'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=manual'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=web'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=bar'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=en'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=de'.format(organizer.slug, event.slug))
|
||||
@@ -434,6 +444,36 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
||||
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
||||
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_positions=false'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.data['results'][0]['positions']) == 1
|
||||
|
||||
Reference in New Issue
Block a user