diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py
index f142256861..0df4d9b888 100644
--- a/src/pretix/control/logdisplay.py
+++ b/src/pretix/control/logdisplay.py
@@ -334,6 +334,20 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
list=checkin_list
)
+ if logentry.action_type == 'pretix.control.views.checkin.reverted':
+ if 'list' in data:
+ try:
+ checkin_list = sender.checkin_lists.get(pk=data.get('list')).name
+ except CheckinList.DoesNotExist:
+ checkin_list = _("(unknown)")
+ else:
+ checkin_list = _("(unknown)")
+
+ return _('The check-in of position #{posid} on list "{list}" has been reverted.').format(
+ posid=data.get('positionid'),
+ list=checkin_list,
+ )
+
if logentry.action_type == 'pretix.team.member.added':
return _('{user} has been added to the team.').format(user=data.get('email'))
diff --git a/src/pretix/control/templates/pretixcontrol/checkin/index.html b/src/pretix/control/templates/pretixcontrol/checkin/index.html
index 032b1c07dd..a2ca3c0460 100644
--- a/src/pretix/control/templates/pretixcontrol/checkin/index.html
+++ b/src/pretix/control/templates/pretixcontrol/checkin/index.html
@@ -120,6 +120,9 @@
+
{% endif %}
{% include "pretixcontrol/pagination.html" %}
diff --git a/src/pretix/control/views/checkin.py b/src/pretix/control/views/checkin.py
index d5d41e9b2d..e35a60e288 100644
--- a/src/pretix/control/views/checkin.py
+++ b/src/pretix/control/views/checkin.py
@@ -90,21 +90,34 @@ class CheckInListShow(EventPermissionRequiredMixin, PaginationMixin, ListView):
pk__in=request.POST.getlist('checkin')
)
- for op in positions:
- created = False
- if op.order.status == Order.STATUS_PAID or (self.list.include_pending and op.order.status == Order.STATUS_PENDING):
- ci, created = Checkin.objects.get_or_create(position=op, list=self.list, defaults={
- 'datetime': now(),
- })
- op.order.log_action('pretix.control.views.checkin', data={
- 'position': op.id,
- 'positionid': op.positionid,
- 'first': created,
- 'datetime': now(),
- 'list': self.list.pk
- }, user=request.user)
+ if request.POST.get('revert') == 'true':
+ for op in positions:
+ if op.order.status == Order.STATUS_PAID or (self.list.include_pending and op.order.status == Order.STATUS_PENDING):
+ Checkin.objects.filter(position=op, list=self.list).delete()
+ op.order.log_action('pretix.control.views.checkin.reverted', data={
+ 'position': op.id,
+ 'positionid': op.positionid,
+ 'list': self.list.pk
+ }, user=request.user)
+
+ messages.success(request, _('The selected check-ins have been reverted.'))
+ else:
+ for op in positions:
+ created = False
+ if op.order.status == Order.STATUS_PAID or (self.list.include_pending and op.order.status == Order.STATUS_PENDING):
+ ci, created = Checkin.objects.get_or_create(position=op, list=self.list, defaults={
+ 'datetime': now(),
+ })
+ op.order.log_action('pretix.control.views.checkin', data={
+ 'position': op.id,
+ 'positionid': op.positionid,
+ 'first': created,
+ 'datetime': now(),
+ 'list': self.list.pk
+ }, user=request.user)
+
+ messages.success(request, _('The selected tickets have been marked as checked in.'))
- messages.success(request, _('The selected tickets have been marked as checked in.'))
return redirect(reverse('control:event.orders.checkinlists.show', kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
diff --git a/src/tests/control/test_checkins.py b/src/tests/control/test_checkins.py
index fcb74a2cf6..5ef62e34ef 100644
--- a/src/tests/control/test_checkins.py
+++ b/src/tests/control/test_checkins.py
@@ -266,6 +266,26 @@ def test_manual_checkins(client, checkin_list_env):
).exists()
+@pytest.mark.django_db
+def test_manual_checkins_revert(client, checkin_list_env):
+ client.login(email='dummy@dummy.dummy', password='dummy')
+ assert not checkin_list_env[5][3].checkins.exists()
+ client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), {
+ 'checkin': [checkin_list_env[5][3].pk]
+ })
+ client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), {
+ 'checkin': [checkin_list_env[5][3].pk],
+ 'revert': 'true'
+ })
+ assert not checkin_list_env[5][3].checkins.exists()
+ assert LogEntry.objects.filter(
+ action_type='pretix.control.views.checkin', object_id=checkin_list_env[5][3].order.pk
+ ).exists()
+ assert LogEntry.objects.filter(
+ action_type='pretix.control.views.checkin.reverted', object_id=checkin_list_env[5][3].order.pk
+ ).exists()
+
+
@pytest.fixture
def checkin_list_with_addon_env():
# permission