From 1c305e4b30bcaca8f4ff065485a6533a416e1793 Mon Sep 17 00:00:00 2001 From: Kara Engelhardt Date: Mon, 16 Feb 2026 16:30:25 +0100 Subject: [PATCH] Store failed offline checkin if successful online checkin with same nonce exists --- src/pretix/api/views/checkin.py | 6 +++++- src/tests/api/test_checkin.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/pretix/api/views/checkin.py b/src/pretix/api/views/checkin.py index 7a7d50e97..7fb054e24 100644 --- a/src/pretix/api/views/checkin.py +++ b/src/pretix/api/views/checkin.py @@ -188,11 +188,15 @@ class CheckinListViewSet(viewsets.ModelViewSet): clist = self.get_object() if serializer.validated_data.get('nonce'): if kwargs.get('position'): - prev = kwargs['position'].all_checkins.filter(nonce=serializer.validated_data['nonce']).first() + prev = kwargs['position'].all_checkins.filter( + nonce=serializer.validated_data['nonce'], + successful=False + ).first() else: prev = clist.checkins.filter( nonce=serializer.validated_data['nonce'], raw_barcode=serializer.validated_data['raw_barcode'], + successful=False ).first() if prev: # Ignore because nonce is already handled diff --git a/src/tests/api/test_checkin.py b/src/tests/api/test_checkin.py index 1dc696e6f..1fcb140a2 100644 --- a/src/tests/api/test_checkin.py +++ b/src/tests/api/test_checkin.py @@ -1177,6 +1177,30 @@ def test_store_failed(token_client, organizer, clist, event, order): assert resp.status_code == 400 +@pytest.mark.django_db +def test_store_failed_after_success(token_client, organizer, clist, event, order): + with scopes_disabled(): + p = order.positions.first() + p.all_checkins.create( + type=Checkin.TYPE_ENTRY, + nonce='foobar', + successful=True, + list=clist, + raw_barcode=p.secret + ) + resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/failed_checkins/'.format( + organizer.slug, event.slug, clist.pk, + ), { + 'raw_barcode': p.secret, + 'nonce': 'foobar', + 'position': p.pk, + 'error_reason': 'unpaid' + }, format='json') + assert resp.status_code == 201 + with scopes_disabled(): + assert Checkin.all.filter(position=p).count() == 2 + + @pytest.mark.django_db def test_redeem_unknown(token_client, organizer, clist, event, order): resp = _redeem(token_client, organizer, clist, 'unknown_secret', {'force': True})