From 3dfdfdf5d0550c9dee1462d39792410e0210e3e1 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 15 Aug 2016 16:10:38 +0200 Subject: [PATCH] Check required vouchers at checkout --- src/pretix/base/services/orders.py | 10 +++++++ src/tests/presale/test_checkout.py | 44 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 4f58c9bf89..8f40dc93d5 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -43,6 +43,7 @@ error_messages = { 'voucher_redeemed': _('This voucher code has already been used an can only be used once.'), 'voucher_expired': _('This voucher is expired.'), 'voucher_invalid_item': _('This voucher is not valid for this item.'), + 'voucher_required': _('You need a valid voucher code to order one of the products in your cart.'), } @@ -184,6 +185,15 @@ def _check_positions(event: Event, dt: datetime, positions: List[CartPosition]): continue voucherids.add(cp.voucher_id) + if cp.item.require_voucher and cp.voucher is None: + cp.delete() + return error_messages['voucher_required'] + + if cp.item.hide_without_voucher and (cp.voucher is None or cp.voucher.item is None + or cp.voucher.item.pk != cp.item.pk): + cp.delete() + return error_messages['voucher_required'] + if cp.expires >= dt and not cp.voucher: # Other checks are not necessary continue diff --git a/src/tests/presale/test_checkout.py b/src/tests/presale/test_checkout.py index 671b2c4aac..9831eaa8c7 100644 --- a/src/tests/presale/test_checkout.py +++ b/src/tests/presale/test_checkout.py @@ -311,6 +311,22 @@ class CheckoutTestCase(TestCase): self.assertEqual(OrderPosition.objects.first().voucher, v) self.assertTrue(Voucher.objects.get(pk=v.pk).redeemed) + def test_voucher_required(self): + v = Voucher.objects.create(item=self.ticket, price=Decimal('12.00'), event=self.event, + valid_until=now() + timedelta(days=2)) + self.ticket.require_voucher = True + self.ticket.save() + CartPosition.objects.create( + event=self.event, cart_id=self.session_key, item=self.ticket, + price=12, expires=now() + timedelta(minutes=10), voucher=v + ) + self._set_session('payment', 'banktransfer') + + response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True) + doc = BeautifulSoup(response.rendered_content) + self.assertEqual(len(doc.select(".thank-you")), 1) + self.assertTrue(Voucher.objects.get(pk=v.pk).redeemed) + def test_voucher_price_changed(self): v = Voucher.objects.create(item=self.ticket, price=Decimal('12.00'), event=self.event, valid_until=now() + timedelta(days=2)) @@ -452,6 +468,34 @@ class CheckoutTestCase(TestCase): doc = BeautifulSoup(response.rendered_content) self.assertGreaterEqual(len(doc.select(".alert-danger")), 1) + def test_confirm_require_voucher(self): + self.ticket.require_voucher = True + self.ticket.save() + cr1 = CartPosition.objects.create( + event=self.event, cart_id=self.session_key, item=self.ticket, + price=23, expires=now() + timedelta(minutes=10) + ) + self._set_session('payment', 'banktransfer') + + response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True) + doc = BeautifulSoup(response.rendered_content) + self.assertGreaterEqual(len(doc.select(".alert-danger")), 1) + self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists()) + + def test_confirm_require_hide_without_voucher(self): + self.ticket.require_voucher = True + self.ticket.save() + cr1 = CartPosition.objects.create( + event=self.event, cart_id=self.session_key, item=self.ticket, + price=23, expires=now() + timedelta(minutes=10) + ) + self._set_session('payment', 'banktransfer') + + response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True) + doc = BeautifulSoup(response.rendered_content) + self.assertGreaterEqual(len(doc.select(".alert-danger")), 1) + self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists()) + def test_confirm_inactive(self): self.ticket.active = False self.ticket.save()