Check-in: New scan type "print"

This commit is contained in:
Raphael Michel
2023-08-11 14:48:23 +02:00
parent 83811c0343
commit 8759477cf5
7 changed files with 26 additions and 7 deletions

View File

@@ -34,7 +34,7 @@ Checking a ticket in
:<json string secret: Scanned QR code corresponding to the ``secret`` attribute of a ticket. :<json string secret: Scanned QR code corresponding to the ``secret`` attribute of a ticket.
:<json string source_type: Type of source the ``secret`` was obtained form. Defaults to ``"barcode"``. :<json string source_type: Type of source the ``secret`` was obtained form. Defaults to ``"barcode"``.
:<json array lists: List of check-in list IDs to search on. No two check-in lists may be from the same event. :<json array lists: List of check-in list IDs to search on. No two check-in lists may be from the same event.
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry. :<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry, ``"print"`` for a badge print scan.
:<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,

View File

@@ -631,7 +631,7 @@ Order position endpoints
:<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,
because there's no point in validating them since they happened whether they are valid or not. Defaults to ``false``. because there's no point in validating them since they happened whether they are valid or not. Defaults to ``false``.
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry. :<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry, ``"print"`` for a badge print scan.
:<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state. :<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
Defaults to ``false`` and only works when ``include_pending`` is set on the check-in Defaults to ``false`` and only works when ``include_pending`` is set on the check-in
list. list.

View File

@@ -179,7 +179,7 @@ class CheckinList(LoggedModel):
# dedupliate by position and count it up. # dedupliate by position and count it up.
cl = self cl = self
base_q, base_params = ( base_q, base_params = (
Checkin.all.filter(*c_q, successful=True, list=cl) Checkin.all.filter(*c_q, successful=True, list=cl, type__in=[Checkin.TYPE_ENTRY, Checkin.TYPE_EXIT])
.annotate( .annotate(
cnt_exists_after=Window( cnt_exists_after=Window(
expression=Count("position_id", filter=Q(type=Value("exit"))), expression=Count("position_id", filter=Q(type=Value("exit"))),
@@ -322,9 +322,11 @@ class Checkin(models.Model):
""" """
TYPE_ENTRY = 'entry' TYPE_ENTRY = 'entry'
TYPE_EXIT = 'exit' TYPE_EXIT = 'exit'
TYPE_PRINT = 'print'
CHECKIN_TYPES = ( CHECKIN_TYPES = (
(TYPE_ENTRY, _('Entry')), (TYPE_ENTRY, _('Entry')),
(TYPE_EXIT, _('Exit')), (TYPE_EXIT, _('Exit')),
(TYPE_PRINT, _('Print')),
) )
REASON_CANCELED = 'canceled' REASON_CANCELED = 'canceled'

View File

@@ -773,7 +773,7 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
'blocked' 'blocked'
) )
if type != Checkin.TYPE_EXIT and op.valid_from and op.valid_from > dt: if type not in (Checkin.TYPE_PRINT, Checkin.TYPE_EXIT) and op.valid_from and op.valid_from > dt:
if force: if force:
force_used = True force_used = True
else: else:
@@ -787,7 +787,7 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
), ),
) )
if type != Checkin.TYPE_EXIT and op.valid_until and op.valid_until < dt: if type not in (Checkin.TYPE_PRINT, Checkin.TYPE_EXIT) and op.valid_until and op.valid_until < dt:
if force: if force:
force_used = True force_used = True
else: else:
@@ -886,9 +886,9 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
if isinstance(auth, Device): if isinstance(auth, Device):
device = auth device = auth
last_cis = list(op.checkins.order_by('-datetime').filter(list=clist).only('type', 'nonce')) last_cis = list(op.checkins.order_by('-datetime').filter(list=clist, type__in=(Checkin.TYPE_ENTRY, Checkin.TYPE_EXIT)).only('type', 'nonce'))
entry_allowed = ( entry_allowed = (
type == Checkin.TYPE_EXIT or type in (Checkin.TYPE_EXIT, Checkin.TYPE_PRINT) or
clist.allow_multiple_entries or clist.allow_multiple_entries or
not last_cis or not last_cis or
all(c.type == Checkin.TYPE_EXIT for c in last_cis) or all(c.type == Checkin.TYPE_EXIT for c in last_cis) or

View File

@@ -295,6 +295,20 @@ def _display_checkin(event, logentry):
posid=data.get('positionid'), posid=data.get('positionid'),
list=checkin_list list=checkin_list
) )
if data.get('type') == Checkin.TYPE_PRINT:
if show_dt:
return _('Position #{posid} has been printed out at {datetime} for list "{list}".').format(
posid=data.get('positionid'),
datetime=dt_formatted,
list=checkin_list
)
else:
return _('Position #{posid} has been printed out for list "{list}".').format(
posid=data.get('positionid'),
list=checkin_list
)
if data.get('first'): if data.get('first'):
if show_dt: if show_dt:
return _('Position #{posid} has been checked in at {datetime} for list "{list}".').format( return _('Position #{posid} has been checked in at {datetime} for list "{list}".').format(

View File

@@ -95,6 +95,7 @@
<td> <td>
{% if c.type == "exit" %}<span class="fa fa-fw fa-sign-out"></span>{% endif %} {% if c.type == "exit" %}<span class="fa fa-fw fa-sign-out"></span>{% endif %}
{% if c.type == "entry" %}<span class="fa fa-fw fa-sign-in"></span>{% endif %} {% if c.type == "entry" %}<span class="fa fa-fw fa-sign-in"></span>{% endif %}
{% if c.type == "print" %}<span class="fa fa-fw fa-print"></span>{% endif %}
{{ c.get_type_display }} {{ c.get_type_display }}
<br> <br>
<small> <small>

View File

@@ -385,6 +385,8 @@
{% else %} {% else %}
<span class="fa fa-fw text-success fa-sign-out" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Exit scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw text-success fa-sign-out" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Exit scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% endif %} {% endif %}
{% elif c.type == "print" %}
<span class="fa fa-fw text-success fa-print" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Print scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% elif c.forced %} {% elif c.forced %}
<span class="fa fa-fw fa-warning text-warning" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw fa-warning text-warning" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% elif c.auto_checked_in %} {% elif c.auto_checked_in %}