コード例 #1
0
ファイル: test_checkin.py プロジェクト: tyagi004ujjwal/pretix
def test_question_required(token_client, organizer, clist, event, order,
                           question):
    with scopes_disabled():
        p = order.positions.first()
    question[0].required = True
    question[0].save()

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk, p.pk), {},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    with scopes_disabled():
        assert resp.data['questions'] == [QuestionSerializer(question[0]).data]

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk,
               p.pk), {'answers': {
                   question[0].pk: ""
               }},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    with scopes_disabled():
        assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
コード例 #2
0
ファイル: test_checkin.py プロジェクト: tyagi004ujjwal/pretix
def test_question_multiple_choice(token_client, organizer, clist, event, order,
                                  question):
    with scopes_disabled():
        p = order.positions.first()
    question[0].type = 'M'
    question[0].save()

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk, p.pk), {},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    with scopes_disabled():
        assert resp.data['questions'] == [QuestionSerializer(question[0]).data]

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk, p.pk), {
            'answers': {
                question[0].pk: "{},{}".format(question[1].pk, question[2].pk)
            }
        },
        format='json')
    assert resp.status_code == 201
    assert resp.data['status'] == 'ok'
    with scopes_disabled():
        assert order.positions.first().answers.get(
            question=question[0]).answer == 'M, L'
        assert set(order.positions.first().answers.get(
            question=question[0]).options.all()) == {question[1], question[2]}
コード例 #3
0
ファイル: test_checkin.py プロジェクト: tyagi004ujjwal/pretix
def test_question_choice_identifier(token_client, organizer, clist, event,
                                    order, question):
    with scopes_disabled():
        p = order.positions.first()
    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk, p.pk), {},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    with scopes_disabled():
        assert resp.data['questions'] == [QuestionSerializer(question[0]).data]

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk, p.pk),
        {'answers': {
            question[0].pk: str(question[1].identifier)
        }},
        format='json')
    print(resp.data)
    assert resp.status_code == 201
    assert resp.data['status'] == 'ok'
    with scopes_disabled():
        assert order.positions.first().answers.get(
            question=question[0]).answer == 'M'
        assert list(order.positions.first().answers.get(
            question=question[0]).options.all()) == [question[1]]
コード例 #4
0
def test_question_number(token_client, organizer, clist, event, order,
                         question):
    question[0].options.all().delete()
    question[0].type = 'N'
    question[0].save()

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk,
               order.positions.first().pk), {},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    assert resp.data['questions'] == [QuestionSerializer(question[0]).data]

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk,
               order.positions.first().pk),
        {'answers': {
            question[0].pk: "3.24"
        }},
        format='json')
    print(resp.data)
    assert resp.status_code == 201
    assert resp.data['status'] == 'ok'
    assert order.positions.first().answers.get(
        question=question[0]).answer == '3.24'
コード例 #5
0
ファイル: test_checkin.py プロジェクト: feitianyiren/pretix
def test_question_invalid(token_client, organizer, clist, event, order, question):
    resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
        organizer.slug, event.slug, clist.pk, order.positions.first().pk
    ), {'answers': {question[0].pk: "A"}}, format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    assert resp.data['questions'] == [QuestionSerializer(question[0]).data]
コード例 #6
0
ファイル: checkin.py プロジェクト: zjw2011/pretix
    def redeem(self, *args, **kwargs):
        force = bool(self.request.data.get('force', False))
        ignore_unpaid = bool(self.request.data.get('ignore_unpaid', False))
        nonce = self.request.data.get('nonce')
        op = self.get_object(ignore_status=True)

        if 'datetime' in self.request.data:
            dt = DateTimeField().to_internal_value(self.request.data.get('datetime'))
        else:
            dt = now()

        given_answers = {}
        if 'answers' in self.request.data:
            aws = self.request.data.get('answers')
            for q in op.item.questions.filter(ask_during_checkin=True):
                if str(q.pk) in aws:
                    try:
                        given_answers[q] = q.clean_answer(aws[str(q.pk)])
                    except ValidationError:
                        pass

        try:
            perform_checkin(
                op=op,
                clist=self.checkinlist,
                given_answers=given_answers,
                force=force,
                ignore_unpaid=ignore_unpaid,
                nonce=nonce,
                datetime=dt,
                questions_supported=self.request.data.get('questions_supported', True),
                canceled_supported=self.request.data.get('canceled_supported', False),
                user=self.request.user,
                auth=self.request.auth,
            )
        except RequiredQuestionsError as e:
            return Response({
                'status': 'incomplete',
                'require_attention': op.item.checkin_attention or op.order.checkin_attention,
                'position': CheckinListOrderPositionSerializer(op, context=self.get_serializer_context()).data,
                'questions': [
                    QuestionSerializer(q).data for q in e.questions
                ]
            }, status=400)
        except CheckInError as e:
            return Response({
                'status': 'error',
                'reason': e.code,
                'require_attention': op.item.checkin_attention or op.order.checkin_attention,
                'position': CheckinListOrderPositionSerializer(op, context=self.get_serializer_context()).data
            }, status=400)
        else:
            return Response({
                'status': 'ok',
                'require_attention': op.item.checkin_attention or op.order.checkin_attention,
                'position': CheckinListOrderPositionSerializer(op, context=self.get_serializer_context()).data
            }, status=201)
コード例 #7
0
ファイル: test_checkin.py プロジェクト: regnat/pretix
def test_question_upload(token_client, organizer, clist, event, order,
                         question):
    r = token_client.post(
        '/api/v1/upload',
        data={
            'media_type': 'image/png',
            'file': ContentFile('file.png', 'invalid png content')
        },
        format='upload',
        HTTP_CONTENT_DISPOSITION='attachment; filename="file.png"',
    )
    assert r.status_code == 201
    file_id_png = r.data['id']

    with scopes_disabled():
        p = order.positions.first()
    question[0].type = 'F'
    question[0].save()

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk, p.pk), {},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'
    with scopes_disabled():
        assert resp.data['questions'] == [QuestionSerializer(question[0]).data]

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk,
               p.pk), {'answers': {
                   question[0].pk: "invalid"
               }},
        format='json')
    assert resp.status_code == 400
    assert resp.data['status'] == 'incomplete'

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.
        format(organizer.slug, event.slug, clist.pk,
               p.pk), {'answers': {
                   question[0].pk: file_id_png
               }},
        format='json')
    assert resp.status_code == 201
    assert resp.data['status'] == 'ok'
    with scopes_disabled():
        assert order.positions.first().answers.get(
            question=question[0]).answer.startswith('file://')
        assert order.positions.first().answers.get(question=question[0]).file
コード例 #8
0
ファイル: checkin.py プロジェクト: regnat/pretix
    def redeem(self, *args, **kwargs):
        force = bool(self.request.data.get('force', False))
        type = self.request.data.get('type', None) or Checkin.TYPE_ENTRY
        if type not in dict(Checkin.CHECKIN_TYPES):
            raise ValidationError("Invalid check-in type.")
        ignore_unpaid = bool(self.request.data.get('ignore_unpaid', False))
        nonce = self.request.data.get('nonce')

        if 'datetime' in self.request.data:
            dt = DateTimeField().to_internal_value(
                self.request.data.get('datetime'))
        else:
            dt = now()

        try:
            queryset = self.get_queryset(ignore_status=True,
                                         ignore_products=True)
            if self.kwargs['pk'].isnumeric():
                op = queryset.get(
                    Q(pk=self.kwargs['pk']) | Q(secret=self.kwargs['pk']))
            else:
                op = queryset.get(secret=self.kwargs['pk'])
        except OrderPosition.DoesNotExist:
            revoked_matches = list(
                self.request.event.revoked_secrets.filter(
                    secret=self.kwargs['pk']))
            if len(revoked_matches) == 0 or not force:
                self.request.event.log_action('pretix.event.checkin.unknown',
                                              data={
                                                  'datetime': dt,
                                                  'type': type,
                                                  'list': self.checkinlist.pk,
                                                  'barcode': self.kwargs['pk']
                                              },
                                              user=self.request.user,
                                              auth=self.request.auth)
                raise Http404()

            op = revoked_matches[0].position
            op.order.log_action('pretix.event.checkin.revoked',
                                data={
                                    'datetime': dt,
                                    'type': type,
                                    'list': self.checkinlist.pk,
                                    'barcode': self.kwargs['pk']
                                },
                                user=self.request.user,
                                auth=self.request.auth)

        given_answers = {}
        if 'answers' in self.request.data:
            aws = self.request.data.get('answers')
            for q in op.item.questions.filter(ask_during_checkin=True):
                if str(q.pk) in aws:
                    try:
                        if q.type == Question.TYPE_FILE:
                            given_answers[q] = self._handle_file_upload(
                                aws[str(q.pk)])
                        else:
                            given_answers[q] = q.clean_answer(aws[str(q.pk)])
                    except ValidationError:
                        pass

        try:
            perform_checkin(
                op=op,
                clist=self.checkinlist,
                given_answers=given_answers,
                force=force,
                ignore_unpaid=ignore_unpaid,
                nonce=nonce,
                datetime=dt,
                questions_supported=self.request.data.get(
                    'questions_supported', True),
                canceled_supported=self.request.data.get(
                    'canceled_supported', False),
                user=self.request.user,
                auth=self.request.auth,
                type=type,
            )
        except RequiredQuestionsError as e:
            return Response(
                {
                    'status':
                    'incomplete',
                    'require_attention':
                    op.item.checkin_attention or op.order.checkin_attention,
                    'position':
                    CheckinListOrderPositionSerializer(
                        op, context=self.get_serializer_context()).data,
                    'questions':
                    [QuestionSerializer(q).data for q in e.questions]
                },
                status=400)
        except CheckInError as e:
            op.order.log_action('pretix.event.checkin.denied',
                                data={
                                    'position': op.id,
                                    'positionid': op.positionid,
                                    'errorcode': e.code,
                                    'force': force,
                                    'datetime': dt,
                                    'type': type,
                                    'list': self.checkinlist.pk
                                },
                                user=self.request.user,
                                auth=self.request.auth)
            return Response(
                {
                    'status':
                    'error',
                    'reason':
                    e.code,
                    'require_attention':
                    op.item.checkin_attention or op.order.checkin_attention,
                    'position':
                    CheckinListOrderPositionSerializer(
                        op, context=self.get_serializer_context()).data
                },
                status=400)
        else:
            return Response(
                {
                    'status':
                    'ok',
                    'require_attention':
                    op.item.checkin_attention or op.order.checkin_attention,
                    'position':
                    CheckinListOrderPositionSerializer(
                        op, context=self.get_serializer_context()).data
                },
                status=201)
コード例 #9
0
    def redeem(self, *args, **kwargs):
        force = bool(self.request.data.get('force', False))
        type = self.request.data.get('type', None) or Checkin.TYPE_ENTRY
        if type not in dict(Checkin.CHECKIN_TYPES):
            raise ValidationError("Invalid check-in type.")
        ignore_unpaid = bool(self.request.data.get('ignore_unpaid', False))
        nonce = self.request.data.get('nonce')

        if 'datetime' in self.request.data:
            dt = DateTimeField().to_internal_value(
                self.request.data.get('datetime'))
        else:
            dt = now()

        common_checkin_args = dict(
            raw_barcode=self.kwargs['pk'],
            type=type,
            list=self.checkinlist,
            datetime=dt,
            device=self.request.auth
            if isinstance(self.request.auth, Device) else None,
            gate=self.request.auth.gate
            if isinstance(self.request.auth, Device) else None,
            nonce=nonce,
            forced=force,
        )
        raw_barcode_for_checkin = None

        try:
            queryset = self.get_queryset(ignore_status=True,
                                         ignore_products=True)
            if self.kwargs['pk'].isnumeric():
                op = queryset.get(
                    Q(pk=self.kwargs['pk']) | Q(secret=self.kwargs['pk']))
            else:
                op = queryset.get(secret=self.kwargs['pk'])
        except OrderPosition.DoesNotExist:
            revoked_matches = list(
                self.request.event.revoked_secrets.filter(
                    secret=self.kwargs['pk']))
            if len(revoked_matches) == 0:
                self.request.event.log_action('pretix.event.checkin.unknown',
                                              data={
                                                  'datetime': dt,
                                                  'type': type,
                                                  'list': self.checkinlist.pk,
                                                  'barcode': self.kwargs['pk']
                                              },
                                              user=self.request.user,
                                              auth=self.request.auth)

                for k, s in self.request.event.ticket_secret_generators.items(
                ):
                    try:
                        parsed = s.parse_secret(self.kwargs['pk'])
                        common_checkin_args.update({
                            'raw_item':
                            parsed.item,
                            'raw_variation':
                            parsed.variation,
                            'raw_subevent':
                            parsed.subevent,
                        })
                    except:
                        pass

                Checkin.objects.create(
                    position=None,
                    successful=False,
                    error_reason=Checkin.REASON_INVALID,
                    **common_checkin_args,
                )

                if force and isinstance(self.request.auth, Device):
                    # There was a bug in libpretixsync: If you scanned a ticket in offline mode that was
                    # valid at the time but no longer exists at time of upload, the device would retry to
                    # upload the same scan over and over again. Since we can't update all devices quickly,
                    # here's a dirty workaround to make it stop.
                    try:
                        brand = self.request.auth.software_brand
                        ver = parse(self.request.auth.software_version)
                        legacy_mode = ((brand == 'pretixSCANPROXY'
                                        and ver < parse('0.0.3'))
                                       or (brand == 'pretixSCAN Android'
                                           and ver < parse('1.11.2'))
                                       or (brand == 'pretixSCAN'
                                           and ver < parse('1.11.2')))
                        if legacy_mode:
                            return Response(
                                {
                                    'status':
                                    'error',
                                    'reason':
                                    Checkin.REASON_ALREADY_REDEEMED,
                                    'reason_explanation':
                                    None,
                                    'require_attention':
                                    False,
                                    '__warning':
                                    'Compatibility hack active due to detected old pretixSCAN version',
                                },
                                status=400)
                    except:  # we don't care e.g. about invalid version numbers
                        pass

                return Response(
                    {
                        'detail': 'Not found.',  # for backwards compatibility
                        'status': 'error',
                        'reason': Checkin.REASON_INVALID,
                        'reason_explanation': None,
                        'require_attention': False,
                    },
                    status=404)
            elif revoked_matches and force:
                op = revoked_matches[0].position
                raw_barcode_for_checkin = self.kwargs['pk']
            else:
                op = revoked_matches[0].position
                op.order.log_action('pretix.event.checkin.revoked',
                                    data={
                                        'datetime': dt,
                                        'type': type,
                                        'list': self.checkinlist.pk,
                                        'barcode': self.kwargs['pk']
                                    },
                                    user=self.request.user,
                                    auth=self.request.auth)
                Checkin.objects.create(position=op,
                                       successful=False,
                                       error_reason=Checkin.REASON_REVOKED,
                                       **common_checkin_args)
                return Response(
                    {
                        'status':
                        'error',
                        'reason':
                        Checkin.REASON_REVOKED,
                        'reason_explanation':
                        None,
                        'require_attention':
                        False,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data
                    },
                    status=400)

        given_answers = {}
        if 'answers' in self.request.data:
            aws = self.request.data.get('answers')
            for q in op.item.questions.filter(ask_during_checkin=True):
                if str(q.pk) in aws:
                    try:
                        if q.type == Question.TYPE_FILE:
                            given_answers[q] = self._handle_file_upload(
                                aws[str(q.pk)])
                        else:
                            given_answers[q] = q.clean_answer(aws[str(q.pk)])
                    except ValidationError:
                        pass

        with language(self.request.event.settings.locale):
            try:
                perform_checkin(
                    op=op,
                    clist=self.checkinlist,
                    given_answers=given_answers,
                    force=force,
                    ignore_unpaid=ignore_unpaid,
                    nonce=nonce,
                    datetime=dt,
                    questions_supported=self.request.data.get(
                        'questions_supported', True),
                    canceled_supported=self.request.data.get(
                        'canceled_supported', False),
                    user=self.request.user,
                    auth=self.request.auth,
                    type=type,
                    raw_barcode=raw_barcode_for_checkin,
                    from_revoked_secret=True,
                )
            except RequiredQuestionsError as e:
                return Response(
                    {
                        'status':
                        'incomplete',
                        'require_attention':
                        op.item.checkin_attention
                        or op.order.checkin_attention,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data,
                        'questions':
                        [QuestionSerializer(q).data for q in e.questions]
                    },
                    status=400)
            except CheckInError as e:
                op.order.log_action('pretix.event.checkin.denied',
                                    data={
                                        'position': op.id,
                                        'positionid': op.positionid,
                                        'errorcode': e.code,
                                        'reason_explanation': e.reason,
                                        'force': force,
                                        'datetime': dt,
                                        'type': type,
                                        'list': self.checkinlist.pk
                                    },
                                    user=self.request.user,
                                    auth=self.request.auth)
                Checkin.objects.create(
                    position=op,
                    successful=False,
                    error_reason=e.code,
                    error_explanation=e.reason,
                    **common_checkin_args,
                )
                return Response(
                    {
                        'status':
                        'error',
                        'reason':
                        e.code,
                        'reason_explanation':
                        e.reason,
                        'require_attention':
                        op.item.checkin_attention
                        or op.order.checkin_attention,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data
                    },
                    status=400)
            else:
                return Response(
                    {
                        'status':
                        'ok',
                        'require_attention':
                        op.item.checkin_attention
                        or op.order.checkin_attention,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data
                    },
                    status=201)
コード例 #10
0
ファイル: checkin.py プロジェクト: Janfred/pretix
    def redeem(self, *args, **kwargs):
        force = bool(self.request.data.get('force', False))
        type = self.request.data.get('type', None) or Checkin.TYPE_ENTRY
        if type not in dict(Checkin.CHECKIN_TYPES):
            raise ValidationError("Invalid check-in type.")
        ignore_unpaid = bool(self.request.data.get('ignore_unpaid', False))
        nonce = self.request.data.get('nonce')

        if 'datetime' in self.request.data:
            dt = DateTimeField().to_internal_value(
                self.request.data.get('datetime'))
        else:
            dt = now()

        common_checkin_args = dict(
            raw_barcode=self.kwargs['pk'],
            type=type,
            list=self.checkinlist,
            datetime=dt,
            device=self.request.auth
            if isinstance(self.request.auth, Device) else None,
            gate=self.request.auth.gate
            if isinstance(self.request.auth, Device) else None,
            nonce=nonce,
            forced=force,
        )

        try:
            queryset = self.get_queryset(ignore_status=True,
                                         ignore_products=True)
            if self.kwargs['pk'].isnumeric():
                op = queryset.get(
                    Q(pk=self.kwargs['pk']) | Q(secret=self.kwargs['pk']))
            else:
                op = queryset.get(secret=self.kwargs['pk'])
        except OrderPosition.DoesNotExist:
            revoked_matches = list(
                self.request.event.revoked_secrets.filter(
                    secret=self.kwargs['pk']))
            if len(revoked_matches) == 0:
                self.request.event.log_action('pretix.event.checkin.unknown',
                                              data={
                                                  'datetime': dt,
                                                  'type': type,
                                                  'list': self.checkinlist.pk,
                                                  'barcode': self.kwargs['pk']
                                              },
                                              user=self.request.user,
                                              auth=self.request.auth)

                for k, s in self.request.event.ticket_secret_generators.items(
                ):
                    try:
                        parsed = s.parse_secret(self.kwargs['pk'])
                        common_checkin_args.update({
                            'raw_item':
                            parsed.item,
                            'raw_variation':
                            parsed.variation,
                            'raw_subevent':
                            parsed.subevent,
                        })
                    except:
                        pass

                Checkin.objects.create(
                    position=None,
                    successful=False,
                    error_reason=Checkin.REASON_INVALID,
                    **common_checkin_args,
                )
                raise Http404()
            else:
                op = revoked_matches[0].position
                op.order.log_action('pretix.event.checkin.revoked',
                                    data={
                                        'datetime': dt,
                                        'type': type,
                                        'list': self.checkinlist.pk,
                                        'barcode': self.kwargs['pk']
                                    },
                                    user=self.request.user,
                                    auth=self.request.auth)
                Checkin.objects.create(position=op,
                                       successful=False,
                                       error_reason=Checkin.REASON_REVOKED,
                                       **common_checkin_args)
                return Response(
                    {
                        'status':
                        'error',
                        'reason':
                        Checkin.REASON_REVOKED,
                        'reason_explanation':
                        None,
                        'require_attention':
                        False,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data
                    },
                    status=400)

        given_answers = {}
        if 'answers' in self.request.data:
            aws = self.request.data.get('answers')
            for q in op.item.questions.filter(ask_during_checkin=True):
                if str(q.pk) in aws:
                    try:
                        if q.type == Question.TYPE_FILE:
                            given_answers[q] = self._handle_file_upload(
                                aws[str(q.pk)])
                        else:
                            given_answers[q] = q.clean_answer(aws[str(q.pk)])
                    except ValidationError:
                        pass

        with language(self.request.event.settings.locale):
            try:
                perform_checkin(
                    op=op,
                    clist=self.checkinlist,
                    given_answers=given_answers,
                    force=force,
                    ignore_unpaid=ignore_unpaid,
                    nonce=nonce,
                    datetime=dt,
                    questions_supported=self.request.data.get(
                        'questions_supported', True),
                    canceled_supported=self.request.data.get(
                        'canceled_supported', False),
                    user=self.request.user,
                    auth=self.request.auth,
                    type=type,
                    raw_barcode=None,
                )
            except RequiredQuestionsError as e:
                return Response(
                    {
                        'status':
                        'incomplete',
                        'require_attention':
                        op.item.checkin_attention
                        or op.order.checkin_attention,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data,
                        'questions':
                        [QuestionSerializer(q).data for q in e.questions]
                    },
                    status=400)
            except CheckInError as e:
                op.order.log_action('pretix.event.checkin.denied',
                                    data={
                                        'position': op.id,
                                        'positionid': op.positionid,
                                        'errorcode': e.code,
                                        'reason_explanation': e.reason,
                                        'force': force,
                                        'datetime': dt,
                                        'type': type,
                                        'list': self.checkinlist.pk
                                    },
                                    user=self.request.user,
                                    auth=self.request.auth)
                Checkin.objects.create(
                    position=op,
                    successful=False,
                    error_reason=e.code,
                    error_explanation=e.reason,
                    **common_checkin_args,
                )
                return Response(
                    {
                        'status':
                        'error',
                        'reason':
                        e.code,
                        'reason_explanation':
                        e.reason,
                        'require_attention':
                        op.item.checkin_attention
                        or op.order.checkin_attention,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data
                    },
                    status=400)
            else:
                return Response(
                    {
                        'status':
                        'ok',
                        'require_attention':
                        op.item.checkin_attention
                        or op.order.checkin_attention,
                        'position':
                        CheckinListOrderPositionSerializer(
                            op, context=self.get_serializer_context()).data
                    },
                    status=201)