initial implementation

This commit is contained in:
Lukas Bockstaller
2026-01-26 14:23:16 +01:00
parent fd5dd989f7
commit 4a0884aaca
4 changed files with 116 additions and 92 deletions

View File

@@ -1719,6 +1719,13 @@ List of all order positions
:statuscode 401: Authentication failure :statuscode 401: Authentication failure
: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.
.. http:get:: /api/v1/organizers/(organizer)/orderpositions/
Returns a list of all order positions.
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.
Fetching individual positions Fetching individual positions
----------------------------- -----------------------------
@@ -1820,6 +1827,12 @@ 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`:
Order position ticket download Order position ticket download
@@ -1872,6 +1885,12 @@ 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
@@ -1964,6 +1983,12 @@ 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:
@@ -2043,6 +2068,12 @@ 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)/
Cancels an order position, identified by its internal ID. Cancels an order position, identified by its internal ID.
@@ -2071,6 +2102,12 @@ 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/
Blocks an order position from being used. The block name either needs to be ``"admin"`` or start with ``"api:"``. It Blocks an order position from being used. The block name either needs to be ``"admin"`` or start with ``"api:"``. It
@@ -2109,6 +2146,12 @@ 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/
Unblocks an order position from being used. The block name either needs to be ``"admin"`` or start with ``"api:"``. It Unblocks an order position from being used. The block name either needs to be ``"admin"`` or start with ``"api:"``. It
@@ -2147,6 +2190,12 @@ 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.
@@ -2200,6 +2249,13 @@ 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,6 +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)
team_router = routers.DefaultRouter() team_router = routers.DefaultRouter()
team_router.register(r'members', organizer.TeamMemberViewSet) team_router.register(r'members', organizer.TeamMemberViewSet)

View File

@@ -1093,7 +1093,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()
ctx['event'] = self.request.event if hasattr(self.request, 'event'):
ctx['event'] = self.request.event
ctx['pdf_data'] = self.request.query_params.get('pdf_data', 'false').lower() == 'true' 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'
return ctx return ctx
@@ -1104,7 +1105,10 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
else: else:
qs = OrderPosition.objects qs = OrderPosition.objects
qs = qs.filter(order__event=self.request.event) if hasattr(self.request, 'event'):
qs = qs.filter(order__event=self.request.event)
if hasattr(self.request, 'organizer'):
qs = qs.filter(order__event__organizer=self.request.organizer)
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(

View File

@@ -987,8 +987,11 @@ def test_refund_cancel(token_client, organizer, event, order):
assert resp.status_code == 400 assert resp.status_code == 400
@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(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 = '/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug)
i2 = copy.copy(item) i2 = copy.copy(item)
i2.pk = None i2.pk = None
i2.save() i2.save()
@@ -1006,87 +1009,61 @@ def test_orderposition_list(token_client, organizer, device, event, order, item,
res["print_logs"][0]["id"] = op.print_logs.first().pk res["print_logs"][0]["id"] = op.print_logs.first().pk
res["print_logs"][0]["device_id"] = device.device_id res["print_logs"][0]["device_id"] = device.device_id
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug)) resp = token_client.get(endpoint)
assert resp.status_code == 200 assert resp.status_code == 200
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?order__status=n')
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=n'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?order__status=p')
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=p'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?item={}'.format(item.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, item.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?item__in={},{}'.format(item.pk, i2.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?item__in={},{}'.format(
organizer.slug, event.slug, item.pk, i2.pk
))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?item={}'.format( i2.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, i2.pk))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?variation={}'.format(var.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?variation={}'.format(var2.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var2.pk))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?attendee_name=Peter')
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Peter'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?attendee_name=peter')
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=peter'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?attendee_name=Mark')
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Mark'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w')
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w'.format(
organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?secret=abc123')
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=abc123'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?pseudonymization_id=ABCDEFGHKL')
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=ABCDEFGHKL'.format(
organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?pseudonymization_id=FOO')
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=FOO'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?search=FO')
'/api/v1/organizers/{}/events/{}/orderpositions/?search=FO'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?search=z3fsn8j')
'/api/v1/organizers/{}/events/{}/orderpositions/?search=z3fsn8j'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?search=Peter')
'/api/v1/organizers/{}/events/{}/orderpositions/?search=Peter'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?search=5f4h6w')
'/api/v1/organizers/{}/events/{}/orderpositions/?search=5f4h6w'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?order=FOO')
'/api/v1/organizers/{}/events/{}/orderpositions/?order=FOO'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?order=BAR')
'/api/v1/organizers/{}/events/{}/orderpositions/?order=BAR'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?has_checkin=false')
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=false'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?has_checkin=true')
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
with scopes_disabled(): with scopes_disabled():
@@ -1104,37 +1081,30 @@ def test_orderposition_list(token_client, organizer, device, event, order, item,
'type': 'entry' 'type': 'entry'
}] }]
with django_assert_num_queries(16): with django_assert_num_queries(16):
resp = token_client.get( resp = token_client.get(endpoint+'?has_checkin=true')
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug)
)
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( resp = token_client.get(endpoint+'?subevent={}'.format(subevent.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?subevent__in={},{}'.format(subevent.pk, subevent2.pk))
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent__in={},{}'.format(organizer.slug, event.slug,
subevent.pk, subevent2.pk))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?subevent={}'.format(subevent.pk + 1))
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug,
subevent.pk + 1))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get( resp = token_client.get(endpoint+'?include_canceled_positions=false')
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=false'.format(organizer.slug, event.slug))
assert len(resp.data['results']) == 1 assert len(resp.data['results']) == 1
resp = token_client.get( resp = token_client.get(endpoint+'?include_canceled_positions=true')
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=true'.format(organizer.slug, event.slug))
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(token_client, organizer, event, order, item, question): def test_orderposition_detail(endpoint_template, token_client, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug)
res = dict(TEST_ORDERPOSITION_RES) res = dict(TEST_ORDERPOSITION_RES)
with scopes_disabled(): with scopes_disabled():
op = order.positions.first() op = order.positions.first()
@@ -1142,38 +1112,34 @@ def test_orderposition_detail(token_client, organizer, event, order, item, quest
res["id"] = op.pk res["id"] = op.pk
res["item"] = item.pk res["item"] = item.pk
res["answers"][0]["question"] = question.pk res["answers"][0]["question"] = question.pk
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug, resp = token_client.get(endpoint + '{}/'.format(op.pk))
op.pk))
assert resp.status_code == 200 assert resp.status_code == 200
assert res == resp.data assert res == resp.data
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('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug, resp = token_client.get(endpoint+'{}/'.format(op.pk))
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(token_client, organizer, event, order, item, question): def test_orderposition_detail_canceled(endpoint_template, token_client, organizer, event, order, item, question):
endpoint = endpoint_template.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('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug, resp = token_client.get(endpoint+'{}/'.format(op.pk))
op.pk))
assert resp.status_code == 404 assert resp.status_code == 404
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/?include_canceled_positions=true'.format( resp = token_client.get(endpoint+'{}/?include_canceled_positions=true'.format(op.pk))
organizer.slug, event.slug, 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(token_client, organizer, event, order, item, question): def test_orderposition_delete(endpoint_template, token_client, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug)
with scopes_disabled(): with scopes_disabled():
op = order.positions.first() op = order.positions.first()
resp = token_client.delete('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format( resp = token_client.delete(endpoint+'{}/'.format(op.pk))
organizer.slug, event.slug, 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.']
@@ -1192,9 +1158,7 @@ def test_orderposition_delete(token_client, organizer, event, order, item, quest
order.save() order.save()
assert order.positions.count() == 2 assert order.positions.count() == 2
resp = token_client.delete('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format( resp = token_client.delete(endpoint+'{}/'.format(op2.pk))
organizer.slug, event.slug, 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
@@ -1202,14 +1166,13 @@ def test_orderposition_delete(token_client, organizer, event, order, item, quest
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(token_client, team, organizer, event, order, item, question): def test_orderposition_printlog(endpoint_template, token_client, team, organizer, event, order, item, question):
endpoint = endpoint_template.format(organizer.slug, event.slug)
with scopes_disabled(): with scopes_disabled():
op = order.positions.first() op = order.positions.first()
resp = token_client.post('/api/v1/organizers/{}/events/{}/orderpositions/{}/printlog/'.format( resp = token_client.post(endpoint+'{}/printlog/'.format(op.pk), data={
organizer.slug, event.slug, 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",