Fix issues introduced in rebase

This commit is contained in:
Raphael Michel
2016-11-27 17:13:26 +01:00
parent ed31f31c04
commit dc0b73bf19
5 changed files with 68 additions and 30 deletions
+11 -11
View File
@@ -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
+24 -10
View File
@@ -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))
+5 -6
View File
@@ -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,
+23 -2
View File
@@ -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):
+5 -1
View File
@@ -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',
}