mirror of
https://github.com/pretix/pretix.git
synced 2026-08-08 10:27:49 +00:00
Fix issues introduced in rebase
This commit is contained in:
@@ -37,8 +37,6 @@ error_messages = {
|
||||
'voucher_invalid': _('This voucher code is not known in our database.'),
|
||||
'voucher_redeemed': _('This voucher code has already been used the maximum number of times allowed.'),
|
||||
'voucher_redeemed_partial': _('This voucher code can only be redeemed %d more times.'),
|
||||
'voucher_double': _('You already used this voucher code. Remove the associated line from your '
|
||||
'cart if you want to use it for a different product.'),
|
||||
'voucher_expired': _('This voucher is expired.'),
|
||||
'voucher_invalid_item': _('This voucher is not valid for this product.'),
|
||||
'voucher_required': _('You need a valid voucher code to order this product.'),
|
||||
@@ -111,6 +109,7 @@ def _parse_items_and_check_constraints(event: Event, items: List[dict], cart_id:
|
||||
variations_cache = {v.id: v for v in variations_query}
|
||||
|
||||
quotadiff = Counter()
|
||||
vouchers = Counter()
|
||||
|
||||
for i in items:
|
||||
# Check whether the specified items are part of what we just fetched from the database
|
||||
@@ -129,24 +128,25 @@ def _parse_items_and_check_constraints(event: Event, items: List[dict], cart_id:
|
||||
try:
|
||||
voucher = Voucher.objects.get(code=i.get('voucher').strip(), event=event)
|
||||
if voucher.redeemed >= voucher.max_usages:
|
||||
return error_messages['voucher_redeemed']
|
||||
raise CartError(error_messages['voucher_redeemed'])
|
||||
if voucher.valid_until is not None and voucher.valid_until < now_dt:
|
||||
raise CartError(error_messages['voucher_expired'])
|
||||
if not voucher.applies_to(item, variation):
|
||||
return error_messages['voucher_invalid_item']
|
||||
raise CartError(error_messages['voucher_invalid_item'])
|
||||
|
||||
redeemed_in_carts = CartPosition.objects.filter(
|
||||
Q(voucher=voucher) & Q(event=event) &
|
||||
(Q(expires__gte=now_dt) | Q(cart_id=cart_id))
|
||||
Q(voucher=voucher) & Q(event=event) & Q(expires__gte=now_dt)
|
||||
)
|
||||
if 'cp' in i:
|
||||
redeemed_in_carts = redeemed_in_carts.exclude(pk=i['cp'].pk)
|
||||
redeemed_in_carts = redeemed_in_carts.exclude(pk=i['_cp'].pk)
|
||||
v_avail = voucher.max_usages - voucher.redeemed - redeemed_in_carts.count()
|
||||
|
||||
if v_avail < 1:
|
||||
return error_messages['voucher_redeemed']
|
||||
if i['count'] > v_avail:
|
||||
return error_messages['voucher_redeemed_partial'] % v_avail
|
||||
raise CartError(error_messages['voucher_redeemed'])
|
||||
if i['count'] > v_avail - vouchers[voucher]:
|
||||
raise CartError(error_messages['voucher_redeemed_partial'] % v_avail)
|
||||
|
||||
vouchers[voucher] += i['count']
|
||||
except Voucher.DoesNotExist:
|
||||
raise CartError(error_messages['voucher_invalid'])
|
||||
|
||||
@@ -200,7 +200,7 @@ def _parse_items_and_check_constraints(event: Event, items: List[dict], cart_id:
|
||||
|
||||
|
||||
def _check_quota_and_create_positions(event: Event, items: List[dict], cart_id: str, now_dt: datetime,
|
||||
expiry: datetime, quotadiff: Counter,):
|
||||
expiry: datetime, quotadiff: Counter):
|
||||
"""
|
||||
This method takes the modified items and the quotadiff from _parse_items_and_check_constraints
|
||||
and then
|
||||
|
||||
@@ -51,6 +51,8 @@ error_messages = {
|
||||
'voucher_invalid': _('The voucher code used for one of the items in your cart is not known in our database.'),
|
||||
'voucher_redeemed': _('The voucher code used for one of the items in your cart has already been used the maximum '
|
||||
'number of times allowed. We removed this item from your cart.'),
|
||||
'voucher_redeemed_partial': _('The voucher code used for one of the items in your cart can only be redeemed %d '
|
||||
'more times. We removed this item from your cart.'),
|
||||
'voucher_expired': _('The voucher code used for one of the items in your cart is expired. We removed this item '
|
||||
'from your cart.'),
|
||||
'voucher_invalid_item': _('The voucher code used for one of the items in your cart is not valid for this item. We '
|
||||
@@ -207,16 +209,6 @@ def _check_positions(event: Event, now_dt: datetime, positions: List[CartPositio
|
||||
continue
|
||||
cp._quotas = list(cp.item.quotas.all()) if cp.variation is None else list(cp.variation.quotas.all())
|
||||
|
||||
if cp.voucher:
|
||||
redeemed_in_carts = CartPosition.objects.filter(
|
||||
Q(voucher=cp.voucher) & Q(event=event) & Q(expires__gte=now_dt)
|
||||
).exclude(pk=cp.pk)
|
||||
v_avail = cp.voucher.max_usages - cp.voucher.redeemed - redeemed_in_carts.count()
|
||||
if v_avail < 1:
|
||||
err = err or error_messages['voucher_redeemed']
|
||||
cp.delete() # Sorry!
|
||||
continue
|
||||
|
||||
if cp.item.require_voucher and cp.voucher is None:
|
||||
cp.delete()
|
||||
err = error_messages['voucher_required']
|
||||
@@ -301,7 +293,11 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
||||
def _check_quota_on_expired_positions(event: Event, positions: List[CartPosition], now_dt: datetime):
|
||||
err = None
|
||||
quotadiff = Counter()
|
||||
vouchers = Counter()
|
||||
for cp in positions:
|
||||
if not cp.id:
|
||||
continue
|
||||
|
||||
ignore_all_quotas = cp.expires >= now_dt or (
|
||||
cp.voucher and (cp.voucher.allow_ignore_quota or (cp.voucher.block_quota and cp.voucher.quota is None)))
|
||||
|
||||
@@ -328,6 +324,24 @@ def _check_quota_on_expired_positions(event: Event, positions: List[CartPosition
|
||||
quotas_ok[quota] = count
|
||||
|
||||
for cp in positions:
|
||||
if not cp.id:
|
||||
continue
|
||||
|
||||
if cp.voucher:
|
||||
redeemed_in_carts = CartPosition.objects.filter(
|
||||
Q(voucher=cp.voucher) & Q(event=event) & Q(expires__gte=now_dt)
|
||||
).exclude(pk__in=[cp2.pk for cp2 in positions])
|
||||
v_avail = cp.voucher.max_usages - cp.voucher.redeemed - redeemed_in_carts.count()
|
||||
if v_avail < 1:
|
||||
err = err or error_messages['voucher_redeemed']
|
||||
cp.delete() # Sorry!
|
||||
continue
|
||||
if v_avail - vouchers[cp.voucher] < 1:
|
||||
err = err or (error_messages['voucher_redeemed_partial'] % v_avail)
|
||||
cp.delete() # Sorry!
|
||||
continue
|
||||
vouchers[cp.voucher] += 1
|
||||
|
||||
if cp._quotas:
|
||||
if min(quotas_ok[q] for q in cp._quotas) > 0:
|
||||
cp.expires = now_dt + timedelta(minutes=event.settings.get('reservation_time', as_type=int))
|
||||
|
||||
@@ -553,10 +553,10 @@ class CartTest(CartTestMixin, TestCase):
|
||||
)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1',
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
obj = CartPosition.objects.get(id=cp1.id)
|
||||
self.assertGreater(obj.expires, now())
|
||||
self.assertEqual(obj.voucher, v)
|
||||
|
||||
def test_voucher_variation(self):
|
||||
v = Voucher.objects.create(item=self.shirt, variation=self.shirt_red, event=self.event)
|
||||
@@ -815,10 +815,9 @@ class CartTest(CartTestMixin, TestCase):
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertIn('already been used', doc.select('.alert-danger')[0].text)
|
||||
self.assertIn('only be redeemed 1 more time', doc.select('.alert-danger')[0].text)
|
||||
positions = CartPosition.objects.filter(cart_id=self.session_key, event=self.event)
|
||||
assert positions.count() == 1
|
||||
assert all(cp.voucher == v for cp in positions)
|
||||
assert positions.count() == 0
|
||||
|
||||
def test_voucher_multiuse_redeemed(self):
|
||||
v = Voucher.objects.create(item=self.ticket, price=Decimal('12.00'), event=self.event,
|
||||
@@ -857,9 +856,9 @@ class CartTest(CartTestMixin, TestCase):
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertIn('already been used', doc.select('.alert-danger')[0].text)
|
||||
self.assertIn('only be redeemed 1 more time', doc.select('.alert-danger')[0].text)
|
||||
positions = CartPosition.objects.filter(cart_id=self.session_key, event=self.event)
|
||||
assert positions.count() == 1
|
||||
assert positions.count() == 0
|
||||
|
||||
def test_voucher_multiuse_redeemed_in_other_cart(self):
|
||||
v = Voucher.objects.create(item=self.ticket, price=Decimal('12.00'), event=self.event,
|
||||
|
||||
@@ -405,10 +405,31 @@ class CheckoutTestCase(TestCase):
|
||||
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, "lxml")
|
||||
self.assertIn("has already been", doc.select(".alert-danger")[0].text)
|
||||
self.assertIn("only be redeemed 1 more time", doc.select(".alert-danger")[0].text)
|
||||
assert CartPosition.objects.filter(cart_id=self.session_key).count() == 1
|
||||
|
||||
def test_voucher_multiuse_ok(self):
|
||||
v = Voucher.objects.create(item=self.ticket, price=Decimal('12.00'), event=self.event,
|
||||
valid_until=now() + timedelta(days=2), max_usages=3, redeemed=1)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=12, expires=now() + timedelta(minutes=10), voucher=v
|
||||
)
|
||||
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, "lxml")
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
self.assertFalse(CartPosition.objects.filter(cart_id=self.session_key).exists())
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 2)
|
||||
v.refresh_from_db()
|
||||
assert v.redeemed == 3
|
||||
|
||||
def test_voucher_multiuse_ok_expired(self):
|
||||
v = Voucher.objects.create(item=self.ticket, price=Decimal('12.00'), event=self.event,
|
||||
valid_until=now() + timedelta(days=2), max_usages=3, redeemed=1)
|
||||
CartPosition.objects.create(
|
||||
@@ -472,7 +493,7 @@ class CheckoutTestCase(TestCase):
|
||||
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, "lxml")
|
||||
self.assertIn("has already been", doc.select(".alert-danger")[0].text)
|
||||
self.assertIn("only be redeemed 1 more time", doc.select(".alert-danger")[0].text)
|
||||
assert CartPosition.objects.filter(cart_id=self.session_key).count() == 1
|
||||
|
||||
def test_voucher_ignore_quota(self):
|
||||
|
||||
@@ -9,4 +9,8 @@ TEMPLATES[0]['DIRS'].append(os.path.join(TEST_DIR, 'templates')) # NOQA
|
||||
INSTALLED_APPS.append('tests.testdummy') # NOQA
|
||||
|
||||
for a in PLUGINS:
|
||||
INSTALLED_APPS.remove(a)
|
||||
INSTALLED_APPS.remove(a)
|
||||
|
||||
DATABASES['default'] = {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user