diff --git a/src/pretix/api/views/checkin.py b/src/pretix/api/views/checkin.py index 866e7a639d..861459018f 100644 --- a/src/pretix/api/views/checkin.py +++ b/src/pretix/api/views/checkin.py @@ -35,6 +35,7 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 from django.utils.functional import cached_property from django.utils.timezone import now +from django.utils.translation import gettext from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_scopes import scopes_disabled from packaging.version import parse @@ -586,6 +587,32 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force, 'list': MiniCheckinListSerializer(list_by_event[revoked_matches[0].event_id]).data, }, status=400) else: + if media.linked_orderposition.order.event_id not in list_by_event: + # Medium exists but connected ticket is for the wrong event + if not simulate: + checkinlists[0].event.log_action('pretix.event.checkin.unknown', data={ + 'datetime': datetime, + 'type': checkin_type, + 'list': checkinlists[0].pk, + 'barcode': raw_barcode, + 'searched_lists': [cl.pk for cl in checkinlists] + }, user=user, auth=auth) + Checkin.objects.create( + position=None, + successful=False, + error_reason=Checkin.REASON_INVALID, + error_explanation=gettext('Medium connected to other event'), + **common_checkin_args, + ) + return Response({ + 'detail': 'Not found.', # for backwards compatibility + 'status': 'error', + 'reason': Checkin.REASON_INVALID, + 'reason_explanation': gettext('Medium connected to other event'), + 'require_attention': False, + 'checkin_texts': [], + 'list': MiniCheckinListSerializer(checkinlists[0]).data, + }, status=404) op_candidates = [media.linked_orderposition] if list_by_event[media.linked_orderposition.order.event_id].addon_match: op_candidates += list(media.linked_orderposition.addons.all()) diff --git a/src/tests/api/test_checkinrpc.py b/src/tests/api/test_checkinrpc.py index 7624098f2e..4e287bd8f5 100644 --- a/src/tests/api/test_checkinrpc.py +++ b/src/tests/api/test_checkinrpc.py @@ -308,6 +308,25 @@ def test_by_medium_not_connected(token_client, organizer, clist, event, order): assert resp.data['reason'] == 'invalid' +@pytest.mark.django_db +def test_by_medium_wrong_event(token_client, organizer, clist, event, order2): + with scopes_disabled(): + ReusableMedium.objects.create( + type="barcode", + identifier="abcdef", + organizer=organizer, + linked_orderposition=order2.positions.first(), + ) + resp = _redeem(token_client, organizer, clist, "abcdef", {"source_type": "barcode"}) + assert resp.status_code == 404 + assert resp.data['status'] == 'error' + assert resp.data['reason'] == 'invalid' + with scopes_disabled(): + ci = clist.checkins.get() + assert ci.raw_barcode == "abcdef" + assert ci.raw_source_type == "barcode" + + @pytest.mark.django_db def test_by_medium_wrong_type(token_client, organizer, clist, event, order): with scopes_disabled():