split out organizer list endpoint

This commit is contained in:
Lukas Bockstaller
2026-01-28 17:31:46 +01:00
parent 00c2763748
commit d693cd1bdc
4 changed files with 142 additions and 143 deletions

View File

@@ -1721,9 +1721,47 @@ List of all order positions
.. http:get:: /api/v1/organizers/(organizer)/orderpositions/ .. http:get:: /api/v1/organizers/(organizer)/orderpositions/
Returns a list of all order positions. Returns a list of all order positions within all events of a given organizer (with sufficient access permissions).
It works in the same way as :http:get:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/`
but does not make use of the event parameter, operating across all order positions of an organizer. Supported query parameters and output format of this endpoint are identical to the list endpoint within an event,
with the exception that the ``pdf_data`` parameter is not supported here.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/orderpositions/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
X-Page-Generated: 2017-12-01T10:00:00Z
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id:": 23442
"code": "ABC12",
"event": "sampleconf",
...
}
]
}
:param organizer: The ``slug`` field of the organizer to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
Fetching individual positions Fetching individual positions
@@ -1827,11 +1865,6 @@ Fetching individual positions
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource. :statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
:statuscode 404: The requested order position does not exist. :statuscode 404: The requested order position does not exist.
.. http:get:: /api/v1/organizers/(organizer)/orderpositions/(id)/
Returns information on one order position, identified by its internal ID.
It works in the same way as :http:get:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. _`order-position-ticket-download`: .. _`order-position-ticket-download`:
@@ -1885,12 +1918,6 @@ Order position ticket download
:statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting for a few :statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting for a few
seconds. seconds.
.. http:get:: /api/v1/organizers/(organizer)/orderpositions/(id)/download/(output)/
Download tickets for one order position, identified by its internal ID.
It works in the same way as :http:get:`/api/v1/organizers/(organizer)/orderpositions/(id)/download/(output)/`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. _rest-orderpositions-manipulate: .. _rest-orderpositions-manipulate:
Manipulating individual positions Manipulating individual positions
@@ -1983,12 +2010,6 @@ Manipulating individual positions
:statuscode 401: Authentication failure :statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order. :statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order.
.. http:patch:: /api/v1/organizers/(organizer)/orderpositions/(id)/
Updates specific fields of an order position.
It works in the same way as :http:patch:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/ .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/
Adds a new position to an order. Currently, only the following fields are supported: Adds a new position to an order. Currently, only the following fields are supported:
@@ -2068,11 +2089,6 @@ Manipulating individual positions
:statuscode 401: Authentication failure :statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this position. :statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this position.
.. http:post:: /api/v1/organizers/(organizer)/orderpositions/
Adds a new position to an order.
It works in the same way as :http:post:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/ .. http:delete:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/
@@ -2102,11 +2118,6 @@ Manipulating individual positions
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource. :statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
:statuscode 404: The requested order position does not exist. :statuscode 404: The requested order position does not exist.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/
Cancels an order position, identified by its internal ID.
It works in the same way as :http:delete:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/add_block/ .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/add_block/
@@ -2146,11 +2157,6 @@ Manipulating individual positions
:statuscode 401: Authentication failure :statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order position. :statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order position.
.. http:post:: /api/v1/organizers/(organizer)/orderpositions/(id)/add_block/
Blocks an order position from being used.
It works in the same way as :http:post:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/add_block/`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/remove_block/ .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/remove_block/
@@ -2190,12 +2196,6 @@ Manipulating individual positions
:statuscode 401: Authentication failure :statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order position. :statuscode 403: The requested organizer/event does not exist **or** you have no permission to update this order position.
.. http:post:: /api/v1/organizers/(organizer)/orderpositions/(id)/remove_block/
Unblocks an order position from being used.
It works in the same way as :http:post:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/remove_block/`
but does not make use of the event parameter, operating across all order positions of an organizer.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/printlog/ .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/printlog/
Creates a print log, stating that this ticket has been printed. Creates a print log, stating that this ticket has been printed.
@@ -2249,12 +2249,6 @@ Manipulating individual positions
:statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting for a few :statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting for a few
seconds. seconds.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/printlog/
Creates a print log, stating that this ticket has been printed.
It works in the same way as :http:post:`/api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/printlog/`
but does not make use of the event parameter, operating across all order positions of an organizer.
Changing order contents Changing order contents
----------------------- -----------------------

View File

@@ -67,7 +67,7 @@ orga_router.register(r'invoices', order.InvoiceViewSet)
orga_router.register(r'scheduled_exports', exporters.ScheduledOrganizerExportViewSet) orga_router.register(r'scheduled_exports', exporters.ScheduledOrganizerExportViewSet)
orga_router.register(r'exporters', exporters.OrganizerExportersViewSet, basename='exporters') orga_router.register(r'exporters', exporters.OrganizerExportersViewSet, basename='exporters')
orga_router.register(r'transactions', order.OrganizerTransactionViewSet) orga_router.register(r'transactions', order.OrganizerTransactionViewSet)
orga_router.register(r'orderpositions', order.OrderPositionViewSet) orga_router.register(r'orderpositions', order.OrganizerPositionViewSet, basename='orderpositions')
team_router = routers.DefaultRouter() team_router = routers.DefaultRouter()
team_router.register(r'members', organizer.TeamMemberViewSet) team_router.register(r'members', organizer.TeamMemberViewSet)
@@ -84,7 +84,7 @@ event_router.register(r'discounts', discount.DiscountViewSet)
event_router.register(r'quotas', item.QuotaViewSet) event_router.register(r'quotas', item.QuotaViewSet)
event_router.register(r'vouchers', voucher.VoucherViewSet) event_router.register(r'vouchers', voucher.VoucherViewSet)
event_router.register(r'orders', order.EventOrderViewSet) event_router.register(r'orders', order.EventOrderViewSet)
event_router.register(r'orderpositions', order.OrderPositionViewSet) event_router.register(r'orderpositions', order.EventOrderPositionViewSet)
event_router.register(r'transactions', order.TransactionViewSet) event_router.register(r'transactions', order.TransactionViewSet)
event_router.register(r'invoices', order.InvoiceViewSet) event_router.register(r'invoices', order.InvoiceViewSet)
event_router.register(r'revokedsecrets', order.RevokedSecretViewSet, basename='revokedsecrets') event_router.register(r'revokedsecrets', order.RevokedSecretViewSet, basename='revokedsecrets')

View File

@@ -41,12 +41,11 @@ from django.utils.translation import gettext as _
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from PIL import Image from PIL import Image
from rest_framework import serializers, status, viewsets from rest_framework import mixins, serializers, status, viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ( from rest_framework.exceptions import (
APIException, NotFound, PermissionDenied, ValidationError, APIException, NotFound, PermissionDenied, ValidationError,
) )
from rest_framework.mixins import CreateModelMixin
from rest_framework.permissions import SAFE_METHODS from rest_framework.permissions import SAFE_METHODS
from rest_framework.response import Response from rest_framework.response import Response
@@ -1071,7 +1070,7 @@ with scopes_disabled():
} }
class OrderPositionViewSet(viewsets.ModelViewSet): class OrderPositionViewSetMixin:
serializer_class = OrderPositionSerializer serializer_class = OrderPositionSerializer
queryset = OrderPosition.all.none() queryset = OrderPosition.all.none()
filter_backends = (DjangoFilterBackend, RichOrderingFilter) filter_backends = (DjangoFilterBackend, RichOrderingFilter)
@@ -1093,10 +1092,8 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
def get_serializer_context(self): def get_serializer_context(self):
ctx = super().get_serializer_context() ctx = super().get_serializer_context()
if hasattr(self.request, 'event'):
ctx['event'] = self.request.event
ctx['pdf_data'] = self.request.query_params.get('pdf_data', 'false').lower() == 'true'
ctx['check_quotas'] = self.request.query_params.get('check_quotas', 'true').lower() == 'true' ctx['check_quotas'] = self.request.query_params.get('check_quotas', 'true').lower() == 'true'
ctx['pdf_data'] = False
return ctx return ctx
def get_queryset(self): def get_queryset(self):
@@ -1105,22 +1102,6 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
else: else:
qs = OrderPosition.objects qs = OrderPosition.objects
perm = self.permission if self.request.method in SAFE_METHODS else self.write_permission
if hasattr(self.request, 'event'):
qs = qs.filter(order__event=self.request.event)
else:
if isinstance(self.request.auth, (TeamAPIToken, Device)):
qs = qs.filter(
order__event__organizer=self.request.organizer,
order__event__in=self.request.auth.get_events_with_permission(perm, request=self.request)
)
elif self.request.user.is_authenticated:
qs = qs.filter(
order__event__organizer=self.request.organizer,
order__event__in=self.request.auth.get_events_with_permission(perm, request=self.request)
)
if self.request.query_params.get('pdf_data', 'false').lower() == 'true': if self.request.query_params.get('pdf_data', 'false').lower() == 'true':
prefetch_related_objects([self.request.organizer], 'meta_properties') prefetch_related_objects([self.request.organizer], 'meta_properties')
prefetch_related_objects( prefetch_related_objects(
@@ -1190,6 +1171,40 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
return prov return prov
raise NotFound('Unknown output provider.') raise NotFound('Unknown output provider.')
class OrganizerPositionViewSet(OrderPositionViewSetMixin, viewsets.ReadOnlyModelViewSet):
def get_queryset(self):
qs = super().get_queryset()
perm = self.permission if self.request.method in SAFE_METHODS else self.write_permission
if isinstance(self.request.auth, (TeamAPIToken, Device)):
qs = qs.filter(
order__event__organizer=self.request.organizer,
order__event__in=self.request.auth.get_events_with_permission(perm, request=self.request)
)
elif self.request.user.is_authenticated:
qs = qs.filter(
order__event__organizer=self.request.organizer,
order__event__in=self.request.auth.get_events_with_permission(perm, request=self.request)
)
return qs
class EventOrderPositionViewSet(OrderPositionViewSetMixin, viewsets.ModelViewSet):
def get_serializer_context(self):
ctx = super().get_serializer_context()
if hasattr(self.request, 'event'):
ctx['event'] = self.request.event
ctx['pdf_data'] = self.request.query_params.get('pdf_data', 'false').lower() == 'true'
return ctx
def get_queryset(self):
qs = super().get_queryset()
qs = qs.filter(order__event=self.request.event)
return qs
@action(detail=True, methods=['POST'], url_name='price_calc') @action(detail=True, methods=['POST'], url_name='price_calc')
def price_calc(self, request, *args, **kwargs): def price_calc(self, request, *args, **kwargs):
""" """
@@ -1593,7 +1608,7 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
return Response(self.get_serializer_class()(instance=serializer.instance, context=self.get_serializer_context()).data) return Response(self.get_serializer_class()(instance=serializer.instance, context=self.get_serializer_context()).data)
class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet): class PaymentViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
serializer_class = OrderPaymentSerializer serializer_class = OrderPaymentSerializer
queryset = OrderPayment.objects.none() queryset = OrderPayment.objects.none()
permission = 'can_view_orders' permission = 'can_view_orders'
@@ -1770,7 +1785,7 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
return self.retrieve(request, [], **kwargs) return self.retrieve(request, [], **kwargs)
class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet): class RefundViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
serializer_class = OrderRefundSerializer serializer_class = OrderRefundSerializer
queryset = OrderRefund.objects.none() queryset = OrderRefund.objects.none()
permission = 'can_view_orders' permission = 'can_view_orders'

View File

@@ -1022,9 +1022,14 @@ def test_refund_cancel(token_client, organizer, event, order):
assert resp.status_code == 400 assert resp.status_code == 400
@pytest.mark.parametrize("endpoint_template, response_code", [('/api/v1/organizers/{}/events/{}/orderpositions/', 403),('/api/v1/organizers/{}/orderpositions/', 200)]) @pytest.mark.parametrize(
"endpoint_template, response_code",
[('/api/v1/organizers/{}/events/{}/orderpositions/', 403), ('/api/v1/organizers/{}/orderpositions/', 200)]
)
@pytest.mark.django_db @pytest.mark.django_db
def test_orderposition_list_limited_read(endpoint_template, response_code, limited_token_client, organizer, device, event, order, item, subevent, subevent2, question): def test_orderposition_list_limited_read(
endpoint_template, response_code, limited_token_client, organizer, device, event, order, item, subevent, subevent2, question
):
endpoint = endpoint_template.format(organizer.slug, event.slug) endpoint = endpoint_template.format(organizer.slug, event.slug)
i2 = copy.copy(item) i2 = copy.copy(item)
@@ -1032,7 +1037,6 @@ def test_orderposition_list_limited_read(endpoint_template, response_code, limit
i2.save() i2.save()
with scopes_disabled(): with scopes_disabled():
var = item.variations.create(value="Children") var = item.variations.create(value="Children")
var2 = item.variations.create(value="Children")
res = copy.copy(TEST_ORDERPOSITION_RES) res = copy.copy(TEST_ORDERPOSITION_RES)
op = order.positions.first() op = order.positions.first()
op.variation = var op.variation = var
@@ -1052,7 +1056,10 @@ def test_orderposition_list_limited_read(endpoint_template, response_code, limit
assert resp.json() == {'detail': 'You do not have permission to perform this action.'} assert resp.json() == {'detail': 'You do not have permission to perform this action.'}
@pytest.mark.parametrize("endpoint_template", [('/api/v1/organizers/{}/events/{}/orderpositions/'),('/api/v1/organizers/{}/orderpositions/')]) @pytest.mark.parametrize(
"endpoint_template",
[('/api/v1/organizers/{}/events/{}/orderpositions/'), ('/api/v1/organizers/{}/orderpositions/')]
)
@pytest.mark.django_db @pytest.mark.django_db
def test_orderposition_list(endpoint_template, token_client, organizer, device, event, order, item, subevent, subevent2, question, django_assert_num_queries): def test_orderposition_list(endpoint_template, token_client, organizer, device, event, order, item, subevent, subevent2, question, django_assert_num_queries):
endpoint = endpoint_template.format(organizer.slug, event.slug) endpoint = endpoint_template.format(organizer.slug, event.slug)
@@ -1078,57 +1085,57 @@ def test_orderposition_list(endpoint_template, token_client, organizer, device,
assert resp.status_code == 200 assert resp.status_code == 200
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?order__status=n') resp = token_client.get(endpoint + '?order__status=n')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?order__status=p') resp = token_client.get(endpoint + '?order__status=p')
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?item={}'.format(item.pk)) resp = token_client.get(endpoint + '?item={}'.format(item.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?item__in={},{}'.format(item.pk, i2.pk)) resp = token_client.get(endpoint + '?item__in={},{}'.format(item.pk, i2.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?item={}'.format( i2.pk)) resp = token_client.get(endpoint + '?item={}'.format(i2.pk))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?variation={}'.format(var.pk)) resp = token_client.get(endpoint + '?variation={}'.format(var.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?variation={}'.format(var2.pk)) resp = token_client.get(endpoint + '?variation={}'.format(var2.pk))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?attendee_name=Peter') resp = token_client.get(endpoint + '?attendee_name=Peter')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?attendee_name=peter') resp = token_client.get(endpoint + '?attendee_name=peter')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?attendee_name=Mark') resp = token_client.get(endpoint + '?attendee_name=Mark')
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w') resp = token_client.get(endpoint + '?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?secret=abc123') resp = token_client.get(endpoint + '?secret=abc123')
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?pseudonymization_id=ABCDEFGHKL') resp = token_client.get(endpoint + '?pseudonymization_id=ABCDEFGHKL')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?pseudonymization_id=FOO') resp = token_client.get(endpoint + '?pseudonymization_id=FOO')
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?search=FO') resp = token_client.get(endpoint + '?search=FO')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?search=z3fsn8j') resp = token_client.get(endpoint + '?search=z3fsn8j')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?search=Peter') resp = token_client.get(endpoint + '?search=Peter')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?search=5f4h6w') resp = token_client.get(endpoint + '?search=5f4h6w')
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?order=FOO') resp = token_client.get(endpoint + '?order=FOO')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?order=BAR') resp = token_client.get(endpoint + '?order=BAR')
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?has_checkin=false') resp = token_client.get(endpoint + '?has_checkin=false')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?has_checkin=true') resp = token_client.get(endpoint + '?has_checkin=true')
assert [] == resp.data['results'] assert [] == resp.data['results']
with scopes_disabled(): with scopes_disabled():
@@ -1147,32 +1154,32 @@ def test_orderposition_list(endpoint_template, token_client, organizer, device,
}] }]
if '/events/' in endpoint: if '/events/' in endpoint:
with django_assert_num_queries(16): with django_assert_num_queries(16):
resp = token_client.get(endpoint+'?has_checkin=true') resp = token_client.get(endpoint + '?has_checkin=true')
else: else:
with django_assert_num_queries(15): with django_assert_num_queries(15):
resp = token_client.get(endpoint+'?has_checkin=true') resp = token_client.get(endpoint + '?has_checkin=true')
assert [res] == resp.data['results'] assert [res] == resp.data['results']
op.subevent = subevent op.subevent = subevent
op.save() op.save()
res['subevent'] = subevent.pk res['subevent'] = subevent.pk
resp = token_client.get(endpoint+'?subevent={}'.format(subevent.pk)) resp = token_client.get(endpoint + '?subevent={}'.format(subevent.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?subevent__in={},{}'.format(subevent.pk, subevent2.pk)) resp = token_client.get(endpoint + '?subevent__in={},{}'.format(subevent.pk, subevent2.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get(endpoint+'?subevent={}'.format(subevent.pk + 1)) resp = token_client.get(endpoint + '?subevent={}'.format(subevent.pk + 1))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get(endpoint+'?include_canceled_positions=false') resp = token_client.get(endpoint + '?include_canceled_positions=false')
assert len(resp.data['results']) == 1 assert len(resp.data['results']) == 1
resp = token_client.get(endpoint+'?include_canceled_positions=true') resp = token_client.get(endpoint + '?include_canceled_positions=true')
assert len(resp.data['results']) == 2 assert len(resp.data['results']) == 2
@pytest.mark.parametrize("endpoint_template", [('/api/v1/organizers/{}/events/{}/orderpositions/'),('/api/v1/organizers/{}/orderpositions/')])
@pytest.mark.django_db @pytest.mark.django_db
def test_orderposition_detail(endpoint_template, token_client, organizer, event, order, item, question): def test_orderposition_detail(token_client, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug) endpoint = '/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug)
res = dict(TEST_ORDERPOSITION_RES) res = dict(TEST_ORDERPOSITION_RES)
with scopes_disabled(): with scopes_disabled():
@@ -1188,27 +1195,27 @@ def test_orderposition_detail(endpoint_template, token_client, organizer, event,
order.status = 'p' order.status = 'p'
order.save() order.save()
event.settings.ticketoutput_pdf__enabled = True event.settings.ticketoutput_pdf__enabled = True
resp = token_client.get(endpoint+'{}/'.format(op.pk)) resp = token_client.get(endpoint + '{}/'.format(op.pk))
assert len(resp.data['downloads']) == 1 assert len(resp.data['downloads']) == 1
@pytest.mark.parametrize("endpoint_template", [('/api/v1/organizers/{}/events/{}/orderpositions/'),('/api/v1/organizers/{}/orderpositions/')])
@pytest.mark.django_db @pytest.mark.django_db
def test_orderposition_detail_canceled(endpoint_template, token_client, organizer, event, order, item, question): def test_orderposition_detail_canceled(token_client, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug) endpoint = '/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug)
with scopes_disabled(): with scopes_disabled():
op = order.all_positions.filter(canceled=True).first() op = order.all_positions.filter(canceled=True).first()
resp = token_client.get(endpoint+'{}/'.format(op.pk)) resp = token_client.get(endpoint + '{}/'.format(op.pk))
assert resp.status_code == 404 assert resp.status_code == 404
resp = token_client.get(endpoint+'{}/?include_canceled_positions=true'.format(op.pk)) resp = token_client.get(endpoint + '{}/?include_canceled_positions=true'.format(op.pk))
assert resp.status_code == 200 assert resp.status_code == 200
@pytest.mark.parametrize("endpoint_template", [('/api/v1/organizers/{}/events/{}/orderpositions/'),('/api/v1/organizers/{}/orderpositions/')])
@pytest.mark.django_db @pytest.mark.django_db
def test_orderposition_delete(endpoint_template, token_client, organizer, event, order, item, question): def test_orderposition_delete(token_client, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug) endpoint = '/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug)
with scopes_disabled(): with scopes_disabled():
op = order.positions.first() op = order.positions.first()
resp = token_client.delete(endpoint+'{}/'.format(op.pk)) resp = token_client.delete(endpoint + '{}/'.format(op.pk))
assert resp.status_code == 400 assert resp.status_code == 400
assert resp.data == ['This operation would leave the order empty. Please cancel the order itself instead.'] assert resp.data == ['This operation would leave the order empty. Please cancel the order itself instead.']
@@ -1227,7 +1234,7 @@ def test_orderposition_delete(endpoint_template, token_client, organizer, event,
order.save() order.save()
assert order.positions.count() == 2 assert order.positions.count() == 2
resp = token_client.delete(endpoint+'{}/'.format(op2.pk)) resp = token_client.delete(endpoint + '{}/'.format(op2.pk))
assert resp.status_code == 204 assert resp.status_code == 204
with scopes_disabled(): with scopes_disabled():
assert order.positions.count() == 1 assert order.positions.count() == 1
@@ -1235,13 +1242,13 @@ def test_orderposition_delete(endpoint_template, token_client, organizer, event,
order.refresh_from_db() order.refresh_from_db()
assert order.total == Decimal('23.25') assert order.total == Decimal('23.25')
@pytest.mark.parametrize("endpoint_template", [('/api/v1/organizers/{}/events/{}/orderpositions/'),('/api/v1/organizers/{}/orderpositions/')])
@pytest.mark.django_db @pytest.mark.django_db
def test_orderposition_printlog(endpoint_template, token_client, team, organizer, event, order, item, question): def test_orderposition_printlog(token_client, team, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug) endpoint = '/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug)
with scopes_disabled(): with scopes_disabled():
op = order.positions.first() op = order.positions.first()
resp = token_client.post(endpoint+'{}/printlog/'.format(op.pk), data={ resp = token_client.post(endpoint + '{}/printlog/'.format(op.pk), data={
"datetime": "2023-09-04T12:23:45+02:00", "datetime": "2023-09-04T12:23:45+02:00",
"source": "pretixscan", "source": "pretixscan",
"type": "badge", "type": "badge",
@@ -1258,23 +1265,6 @@ def test_orderposition_printlog(endpoint_template, token_client, team, organizer
assert l.api_token.team == team assert l.api_token.team == team
assert l.datetime.isoformat() == "2023-09-04T10:23:45+00:00" assert l.datetime.isoformat() == "2023-09-04T10:23:45+00:00"
@pytest.mark.parametrize("endpoint_template, response_code", [
('/api/v1/organizers/{}/events/{}/orderpositions/', 403),
('/api/v1/organizers/{}/orderpositions/', 404)])
@pytest.mark.django_db
def test_orderposition_printlog(endpoint_template, response_code, limited_token_client, team, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug)
with scopes_disabled():
op = order.positions.first()
resp = limited_token_client.post(endpoint+'{}/printlog/'.format(op.pk), data={
"datetime": "2023-09-04T12:23:45+02:00",
"source": "pretixscan",
"type": "badge",
"info": {
"cashier": 1234,
}
}, format='json')
assert resp.status_code == response_code
@pytest.mark.django_db @pytest.mark.django_db
def test_order_mark_paid_pending(token_client, organizer, event, order): def test_order_mark_paid_pending(token_client, organizer, event, order):