Check-in: New error reason for unapproved orders (#3741)

* Check-in: New error reason for unapproved orders

* Fix documentation verbiage
This commit is contained in:
Raphael Michel
2023-11-28 12:50:29 +01:00
committed by GitHub
parent 1593eacb6b
commit 965fcec9df
11 changed files with 46 additions and 37 deletions
+1
View File
@@ -217,6 +217,7 @@ Checking a ticket in
* ``rules`` - Check-in prevented by a user-defined rule. * ``rules`` - Check-in prevented by a user-defined rule.
* ``ambiguous`` - Multiple tickets match scan, rejected. * ``ambiguous`` - Multiple tickets match scan, rejected.
* ``revoked`` - Ticket code has been revoked. * ``revoked`` - Ticket code has been revoked.
* ``unapproved`` - Order has not yet been approved.
* ``error`` - Internal error. * ``error`` - Internal error.
In case of reason ``rules`` and ``invalid_time``, there might be an additional response field ``reason_explanation`` In case of reason ``rules`` and ``invalid_time``, there might be an additional response field ``reason_explanation``
+3 -1
View File
@@ -632,7 +632,8 @@ Order position endpoints
set this to ``false``. In that case, questions will just be ignored. Defaults set this to ``false``. In that case, questions will just be ignored. Defaults
to ``true``. to ``true``.
:<json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be :<json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
returned. Otherwise, canceled orders will return ``unpaid``. returned. Otherwise, canceled orders will return ``unpaid``. (**Deprecated**, in
the future, this will be ignored and ``canceled`` may always be returned.)
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used. :<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
:<json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required :<json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
questions that have not been filled. This is usually used to upload offline scans that already happened, questions that have not been filled. This is usually used to upload offline scans that already happened,
@@ -758,6 +759,7 @@ Order position endpoints
* ``rules`` - Check-in prevented by a user-defined rule. * ``rules`` - Check-in prevented by a user-defined rule.
* ``ambiguous`` - Multiple tickets match scan, rejected. * ``ambiguous`` - Multiple tickets match scan, rejected.
* ``revoked`` - Ticket code has been revoked. * ``revoked`` - Ticket code has been revoked.
* ``unapproved`` - Order has not yet been approved.
In case of reason ``rules`` or ``invalid_time``, there might be an additional response field ``reason_explanation`` In case of reason ``rules`` or ``invalid_time``, there might be an additional response field ``reason_explanation``
with a human-readable description of the violated rules. However, that field can also be missing or be ``null``. with a human-readable description of the violated rules. However, that field can also be missing or be ``null``.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 287 KiB

+14 -14
View File
@@ -25,27 +25,27 @@ partition "data-based check" {
else else
-down->[yes] "Is one or more block set on the ticket?" -down->[yes] "Is one or more block set on the ticket?"
--> if "" then --> if "" then
-right->[no] "Return error BLOCKED" -right->[yes] "Return error BLOCKED"
else 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 --> if "" then
-right->[no] "Return error INVALID_TIME" -right->[yes] "Return error UNAPPROVED"
else 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 --> if "" then
-right->[no] "Return error PRODUCT" -right->[no] "Return error INVALID_TIME"
else 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 --> if "" then
-right->[no] "Return error INVALID" -right->[no] "Return error PRODUCT"
note bottom: TODO\ninconsistent\nwith online\ncheck
else else
-down->[yes] "Is the order in status PAID?" -down->[yes] "Is the subevent part of the check-in list?"
--> if "" then --> 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 --> if "" then
-->[yes] "Return error UNPAID "
else
-right->[no] "Is Order.valid_if_pending set?" -right->[no] "Is Order.valid_if_pending set?"
--> if "" then --> if "" then
-->[yes] "Is this an entry or exit?" -->[yes] "Is this an entry or exit?"
@@ -62,9 +62,9 @@ partition "data-based check" {
endif endif
endif endif
endif endif
else
-down->[yes] "Is this an entry or exit?"
endif endif
else
-down->[yes] "Is this an entry or exit?"
endif endif
endif endif
endif endif
Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 183 KiB

+12 -12
View File
@@ -42,23 +42,25 @@ endif
else else
-down->[yes || force] "Is one or more block set on the ticket?" -down->[yes || force] "Is one or more block set on the ticket?"
--> if "" then --> if "" then
-right->[no && !force] "Return error BLOCKED" -right->[yes && !force] "Return error BLOCKED"
else 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 --> if "" then
-right->[no && !force] "Return error INVALID_TIME" -right->[yes && !force] "Return error UNAPPROVED"
else 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 --> if "" then
-right->[no && !force] "Return error PRODUCT" -right->[no && !force] "Return error INVALID_TIME"
else 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 --> if "" then
-right->[no && !force] "Return error PRODUCT " -right->[no && !force] "Return error PRODUCT"
else else
-down->[yes] "Is the order in status PAID?" -down->[yes || force] "Is the subevent part of the check-in list?"
--> if "" then --> 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 --> if "" then
-->[no] "Is Order.valid_if_pending set?" -->[no] "Is Order.valid_if_pending set?"
--> if "" then --> if "" then
@@ -77,10 +79,8 @@ else
endif endif
endif endif
else else
-->[yes] "Return error UNPAID " -down->[yes || force] "Is this an entry or exit?\nIs the upload forced?"
endif endif
else
-down->[yes || force] "Is this an entry or exit?\nIs the upload forced?"
endif endif
endif endif
endif endif
+2
View File
@@ -352,6 +352,7 @@ class Checkin(models.Model):
REASON_AMBIGUOUS = 'ambiguous' REASON_AMBIGUOUS = 'ambiguous'
REASON_ERROR = 'error' REASON_ERROR = 'error'
REASON_BLOCKED = 'blocked' REASON_BLOCKED = 'blocked'
REASON_UNAPPROVED = 'unapproved'
REASON_INVALID_TIME = 'invalid_time' REASON_INVALID_TIME = 'invalid_time'
REASONS = ( REASONS = (
(REASON_CANCELED, _('Order canceled')), (REASON_CANCELED, _('Order canceled')),
@@ -365,6 +366,7 @@ class Checkin(models.Model):
(REASON_AMBIGUOUS, _('Ticket code is ambiguous on list')), (REASON_AMBIGUOUS, _('Ticket code is ambiguous on list')),
(REASON_ERROR, _('Server error')), (REASON_ERROR, _('Server error')),
(REASON_BLOCKED, _('Ticket blocked')), (REASON_BLOCKED, _('Ticket blocked')),
(REASON_UNAPPROVED, _('Order not approved')),
(REASON_INVALID_TIME, _('Ticket not valid at this time')), (REASON_INVALID_TIME, _('Ticket not valid at this time')),
) )
+9 -8
View File
@@ -874,6 +874,15 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
'blocked' '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 type != Checkin.TYPE_EXIT and op.valid_from and op.valid_from > dt:
if force: if force:
force_used = True force_used = True
@@ -941,14 +950,6 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
'product' '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 ( 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 ignore_unpaid and clist.include_pending and op.order.status == Order.STATUS_PENDING
): ):
@@ -278,8 +278,10 @@ export default {
return this.$root.strings['result.ok'] return this.$root.strings['result.ok']
} else if (this.checkResult.status === 'incomplete') { } else if (this.checkResult.status === 'incomplete') {
return this.$root.strings['result.questions'] return this.$root.strings['result.questions']
} else { } else if (this.$root.strings['result.' + this.checkResult.reason]) {
return this.$root.strings['result.' + this.checkResult.reason] return this.$root.strings['result.' + this.checkResult.reason]
} else {
return this.checkResult.reason
} }
}, },
checkResultColor () { checkResultColor () {
@@ -62,6 +62,7 @@ window.vapp = new Vue({
'result.invalid_time': gettext('Ticket not valid at this time'), 'result.invalid_time': gettext('Ticket not valid at this time'),
'result.canceled': gettext('Order canceled'), 'result.canceled': gettext('Order canceled'),
'result.ambiguous': gettext('Ticket code is ambiguous on list'), 'result.ambiguous': gettext('Ticket code is ambiguous on list'),
'result.unapproved': gettext('Order not approved'),
'status.checkin': gettext('Checked-in Tickets'), 'status.checkin': gettext('Checked-in Tickets'),
'status.position': gettext('Valid Tickets'), 'status.position': gettext('Valid Tickets'),
'status.inside': gettext('Currently inside'), 'status.inside': gettext('Currently inside'),
+1 -1
View File
@@ -243,7 +243,7 @@ def test_require_approval(position, clist):
clist.save() clist.save()
with pytest.raises(CheckInError) as excinfo: with pytest.raises(CheckInError) as excinfo:
perform_checkin(position, clist, {}, ignore_unpaid=True) 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) perform_checkin(position, clist, {}, ignore_unpaid=True, force=True)
assert position.checkins.count() == 1 assert position.checkins.count() == 1