diff --git a/doc/api/resources/checkin.rst b/doc/api/resources/checkin.rst index 551294de1..dd8eaf226 100644 --- a/doc/api/resources/checkin.rst +++ b/doc/api/resources/checkin.rst @@ -217,6 +217,7 @@ Checking a ticket in * ``rules`` - Check-in prevented by a user-defined rule. * ``ambiguous`` - Multiple tickets match scan, rejected. * ``revoked`` - Ticket code has been revoked. + * ``unapproved`` - Order has not yet been approved. * ``error`` - Internal error. In case of reason ``rules`` and ``invalid_time``, there might be an additional response field ``reason_explanation`` diff --git a/doc/api/resources/checkinlists.rst b/doc/api/resources/checkinlists.rst index 9fa2527dd..d815c3350 100644 --- a/doc/api/resources/checkinlists.rst +++ b/doc/api/resources/checkinlists.rst @@ -632,7 +632,8 @@ Order position endpoints set this to ``false``. In that case, questions will just be ignored. Defaults to ``true``. :[yes] "Is one or more block set on the ticket?" --> if "" then - -right->[no] "Return error BLOCKED" + -right->[yes] "Return error BLOCKED" else - -down->[yes] "If this is not an exit, is the valid_from/valid_until\nconstraint on the ticket fulfilled?" + -down->[no] "Is the order in status PENDING and not yet approved?" --> if "" then - -right->[no] "Return error INVALID_TIME" + -right->[yes] "Return error UNAPPROVED" else - -down->[yes] "Is the product part of the check-in list?" + -down->[no] "If this is not an exit, is the valid_from/valid_until\nconstraint on the ticket fulfilled?" --> if "" then - -right->[no] "Return error PRODUCT" + -right->[no] "Return error INVALID_TIME" else - -down->[yes] "Is the subevent part of the check-in list?" + -down->[yes] "Is the product part of the check-in list?" --> if "" then - -right->[no] "Return error INVALID" - note bottom: TODO\ninconsistent\nwith online\ncheck + -right->[no] "Return error PRODUCT" else - -down->[yes] "Is the order in status PAID?" + -down->[yes] "Is the subevent part of the check-in list?" --> if "" then - -right->[no] "Is Order.require_approval set?" + -right->[no] "Return error INVALID" + note bottom: TODO\ninconsistent\nwith online\ncheck + else + -down->[yes] "Is the order in status PAID?" --> if "" then - -->[yes] "Return error UNPAID " - else -right->[no] "Is Order.valid_if_pending set?" --> if "" then -->[yes] "Is this an entry or exit?" @@ -62,9 +62,9 @@ partition "data-based check" { endif endif endif + else + -down->[yes] "Is this an entry or exit?" endif - else - -down->[yes] "Is this an entry or exit?" endif endif endif diff --git a/doc/images/checkin_online.png b/doc/images/checkin_online.png index e05d9bccf..56dfaa69f 100644 Binary files a/doc/images/checkin_online.png and b/doc/images/checkin_online.png differ diff --git a/doc/images/checkin_online.puml b/doc/images/checkin_online.puml index fbdc63e22..67d04dd56 100644 --- a/doc/images/checkin_online.puml +++ b/doc/images/checkin_online.puml @@ -42,23 +42,25 @@ endif else -down->[yes || force] "Is one or more block set on the ticket?" --> if "" then - -right->[no && !force] "Return error BLOCKED" + -right->[yes && !force] "Return error BLOCKED" else - -down->[yes || force] "If this is not an exit, is the valid_from/valid_until\nconstraint on the ticket fulfilled?" + -down->[no || force] "Is the order in status PENDING and not yet approved?" --> if "" then - -right->[no && !force] "Return error INVALID_TIME" + -right->[yes && !force] "Return error UNAPPROVED" else - -down->[yes || force] "Is the product part of the check-in list?" + -down->[no || force] "If this is not an exit, is the valid_from/valid_until\nconstraint on the ticket fulfilled?" --> if "" then - -right->[no && !force] "Return error PRODUCT" + -right->[no && !force] "Return error INVALID_TIME" else - -down->[yes || force] "Is the subevent part of the check-in list?" + -down->[yes || force] "Is the product part of the check-in list?" --> if "" then - -right->[no && !force] "Return error PRODUCT " + -right->[no && !force] "Return error PRODUCT" else - -down->[yes] "Is the order in status PAID?" + -down->[yes || force] "Is the subevent part of the check-in list?" --> if "" then - -right->[no && !force] "Is Order.require_approval set?" + -right->[no && !force] "Return error PRODUCT " + else + -down->[yes] "Is the order in status PAID?" --> if "" then -->[no] "Is Order.valid_if_pending set?" --> if "" then @@ -77,10 +79,8 @@ else endif endif else - -->[yes] "Return error UNPAID " + -down->[yes || force] "Is this an entry or exit?\nIs the upload forced?" endif - else - -down->[yes || force] "Is this an entry or exit?\nIs the upload forced?" endif endif endif diff --git a/src/pretix/base/models/checkin.py b/src/pretix/base/models/checkin.py index c54ff9a5d..dfe0ab94d 100644 --- a/src/pretix/base/models/checkin.py +++ b/src/pretix/base/models/checkin.py @@ -352,6 +352,7 @@ class Checkin(models.Model): REASON_AMBIGUOUS = 'ambiguous' REASON_ERROR = 'error' REASON_BLOCKED = 'blocked' + REASON_UNAPPROVED = 'unapproved' REASON_INVALID_TIME = 'invalid_time' REASONS = ( (REASON_CANCELED, _('Order canceled')), @@ -365,6 +366,7 @@ class Checkin(models.Model): (REASON_AMBIGUOUS, _('Ticket code is ambiguous on list')), (REASON_ERROR, _('Server error')), (REASON_BLOCKED, _('Ticket blocked')), + (REASON_UNAPPROVED, _('Order not approved')), (REASON_INVALID_TIME, _('Ticket not valid at this time')), ) diff --git a/src/pretix/base/services/checkin.py b/src/pretix/base/services/checkin.py index 68fbb9e4f..9d9bbbbd0 100644 --- a/src/pretix/base/services/checkin.py +++ b/src/pretix/base/services/checkin.py @@ -874,6 +874,15 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict, 'blocked' ) + if op.order.status == Order.STATUS_PENDING and op.order.require_approval: + if force: + force_used = True + else: + raise CheckInError( + _('This order is not yet approved.'), + 'unapproved', + ) + if type != Checkin.TYPE_EXIT and op.valid_from and op.valid_from > dt: if force: force_used = True @@ -941,14 +950,6 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict, 'product' ) - if op.order.status != Order.STATUS_PAID and op.order.require_approval: - if force: - force_used = True - else: - raise CheckInError( - _('This order is not yet approved.'), - 'unpaid' - ) elif op.order.status != Order.STATUS_PAID and not op.order.valid_if_pending and not ( ignore_unpaid and clist.include_pending and op.order.status == Order.STATUS_PENDING ): diff --git a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue index a2994c7a4..dea601bc4 100644 --- a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue +++ b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue @@ -278,8 +278,10 @@ export default { return this.$root.strings['result.ok'] } else if (this.checkResult.status === 'incomplete') { return this.$root.strings['result.questions'] - } else { + } else if (this.$root.strings['result.' + this.checkResult.reason]) { return this.$root.strings['result.' + this.checkResult.reason] + } else { + return this.checkResult.reason } }, checkResultColor () { diff --git a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js index 744930d25..8917d28c0 100644 --- a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js +++ b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js @@ -62,6 +62,7 @@ window.vapp = new Vue({ 'result.invalid_time': gettext('Ticket not valid at this time'), 'result.canceled': gettext('Order canceled'), 'result.ambiguous': gettext('Ticket code is ambiguous on list'), + 'result.unapproved': gettext('Order not approved'), 'status.checkin': gettext('Checked-in Tickets'), 'status.position': gettext('Valid Tickets'), 'status.inside': gettext('Currently inside'), diff --git a/src/tests/base/test_checkin.py b/src/tests/base/test_checkin.py index 19a5389f6..765bb3e41 100644 --- a/src/tests/base/test_checkin.py +++ b/src/tests/base/test_checkin.py @@ -243,7 +243,7 @@ def test_require_approval(position, clist): clist.save() with pytest.raises(CheckInError) as excinfo: perform_checkin(position, clist, {}, ignore_unpaid=True) - assert excinfo.value.code == 'unpaid' + assert excinfo.value.code == 'unapproved' perform_checkin(position, clist, {}, ignore_unpaid=True, force=True) assert position.checkins.count() == 1