From 3703fbcacfa5336290888deb19531720d7c59078 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 21 Jan 2019 09:04:06 +0100 Subject: [PATCH] Do not allow customers to cancel checked-in orders --- src/pretix/base/models/orders.py | 10 ++++++++-- src/tests/base/test_models.py | 14 +++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index e54c510f2..cb6b5247a 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -395,8 +395,14 @@ class Order(LockModel, LoggedModel): """ Returns whether or not this order can be canceled by the user. """ - positions = list(self.positions.all().select_related('item')) - cancelable = all([op.item.allow_cancel for op in positions]) + from .checkin import Checkin + + positions = list( + self.positions.all().annotate( + has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk'))) + ).select_related('item') + ) + cancelable = all([op.item.allow_cancel and not op.has_checkin for op in positions]) if not cancelable or not positions: return False if self.user_cancel_deadline and now() > self.user_cancel_deadline: diff --git a/src/tests/base/test_models.py b/src/tests/base/test_models.py index e75be73d6..3e290e844 100644 --- a/src/tests/base/test_models.py +++ b/src/tests/base/test_models.py @@ -15,7 +15,7 @@ from django.utils.timezone import now from pretix.base.i18n import language from pretix.base.models import ( - CachedFile, CartPosition, CheckinList, Event, Item, ItemCategory, + CachedFile, CartPosition, Checkin, CheckinList, Event, Item, ItemCategory, ItemVariation, Order, OrderFee, OrderPayment, OrderPosition, OrderRefund, Organizer, Question, Quota, User, Voucher, WaitingListEntry, ) @@ -865,6 +865,18 @@ class OrderTestCase(BaseQuotaTestCase): self.event.settings.cancel_allow_user_paid = True assert self.order.user_cancel_allowed + def test_can_cancel_checked_in(self): + self.order.status = Order.STATUS_PAID + self.order.save() + self.event.settings.cancel_allow_user = False + self.event.settings.cancel_allow_user_paid = True + assert self.order.user_cancel_allowed + Checkin.objects.create( + position=self.order.positions.first(), + list=CheckinList.objects.create(event=self.event, name='Default') + ) + assert not self.order.user_cancel_allowed + def test_can_cancel_order_multiple(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=True)