diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index e55383439e..27f6012f30 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -314,7 +314,7 @@ class Order(LoggedModel): ), tz) return term_last - def _can_be_paid(self) -> Union[bool, str]: + def _can_be_paid(self, count_waitinglist=True) -> Union[bool, str]: error_messages = { 'late_lastdate': _("The payment can not be accepted as the last date of payments configured in the " "payment settings is over."), @@ -331,7 +331,7 @@ class Order(LoggedModel): if not self.event.settings.get('payment_term_accept_late'): return error_messages['late'] - return self._is_still_available() + return self._is_still_available(count_waitinglist=count_waitinglist) def _is_still_available(self, now_dt: datetime=None, count_waitinglist=True) -> Union[bool, str]: error_messages = { diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 6e3edddd7f..41b9bab155 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -75,7 +75,8 @@ logger = logging.getLogger(__name__) def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None, - force: bool=False, send_mail: bool=True, user: User=None, mail_text='') -> Order: + force: bool=False, send_mail: bool=True, user: User=None, mail_text='', + count_waitinglist=True) -> Order: """ Marks an order as paid. This sets the payment provider, info and date and returns the order object. @@ -101,7 +102,7 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date return order with order.event.lock() as now_dt: - can_be_paid = order._can_be_paid() + can_be_paid = order._can_be_paid(count_waitinglist=count_waitinglist) if not force and can_be_paid is not True: raise Quota.QuotaExceededException(can_be_paid) order.payment_provider = provider or order.payment_provider @@ -756,7 +757,7 @@ class OrderChangeManager: def _check_paid_to_free(self): if self.order.total == 0: try: - mark_order_paid(self.order, 'free', send_mail=False) + mark_order_paid(self.order, 'free', send_mail=False, count_waitinglist=False) except Quota.QuotaExceededException: raise OrderError(self.error_messages['paid_to_free_exceeded']) diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index 9660f2cf75..d7b77f90e6 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -210,7 +210,8 @@ class OrderTransition(OrderView): to = self.request.POST.get('status', '') if self.order.status in (Order.STATUS_PENDING, Order.STATUS_EXPIRED) and to == 'p': try: - mark_order_paid(self.order, manual=True, user=self.request.user) + mark_order_paid(self.order, manual=True, user=self.request.user, + count_waitinglist=False) except Quota.QuotaExceededException as e: messages.error(self.request, str(e)) except SendMailException: diff --git a/src/pretix/plugins/banktransfer/views.py b/src/pretix/plugins/banktransfer/views.py index d8e7fbbe8f..87b070a03c 100644 --- a/src/pretix/plugins/banktransfer/views.py +++ b/src/pretix/plugins/banktransfer/views.py @@ -71,7 +71,7 @@ class ActionView(View): 'date': trans.date, 'payer': trans.payer, 'trans_id': trans.pk - })) + }), count_waitinglist=False) trans.state = BankTransaction.STATE_VALID trans.save() except Quota.QuotaExceededException as e: diff --git a/src/tests/base/test_models.py b/src/tests/base/test_models.py index 45fa541b9f..43abc084b6 100644 --- a/src/tests/base/test_models.py +++ b/src/tests/base/test_models.py @@ -682,6 +682,26 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_PAID) + def test_paid_expired_unavailable_waiting_list(self): + self.event.waitinglistentries.create(item=self.item1, email='foo@bar.com') + self.order.expires = now() - timedelta(days=2) + self.order.save() + self.quota.size = 1 + self.quota.save() + mark_order_paid(self.order, force=True) + self.order = Order.objects.get(id=self.order.id) + self.assertEqual(self.order.status, Order.STATUS_EXPIRED) + + def test_paid_expired_unavailable_waiting_list_ignore(self): + self.event.waitinglistentries.create(item=self.item1, email='foo@bar.com') + self.order.expires = now() - timedelta(days=2) + self.order.save() + self.quota.size = 1 + self.quota.save() + mark_order_paid(self.order, force=True, count_waitinglist=False) + self.order = Order.objects.get(id=self.order.id) + self.assertEqual(self.order.status, Order.STATUS_PAID) + def test_can_modify_answers(self): self.event.settings.set('invoice_address_asked', False) self.event.settings.set('attendee_names_asked', True) diff --git a/src/tests/control/test_orders.py b/src/tests/control/test_orders.py index e0e00a4e22..48eaec9fba 100644 --- a/src/tests/control/test_orders.py +++ b/src/tests/control/test_orders.py @@ -466,6 +466,25 @@ def test_order_extend_expired_quota_partial(client, env): assert o.status == Order.STATUS_EXPIRED +@pytest.mark.django_db +def test_order_mark_paid_overdue_quota_blocked_by_waiting_list(client, env): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.expires = now() - timedelta(days=5) + o.save() + q = Quota.objects.create(event=env[0], size=1) + q.items.add(env[3]) + env[0].waitinglistentries.create(item=env[3], email='foo@bar.com') + + client.login(email='dummy@dummy.dummy', password='dummy') + response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { + 'status': 'p' + }, follow=True) + assert 'alert-success' in response.rendered_content + o = Order.objects.get(id=env[2].id) + assert o.status == Order.STATUS_PAID + + @pytest.mark.django_db def test_order_go_lowercase(client, env): client.login(email='dummy@dummy.dummy', password='dummy')