forked from CGM_Public/pretix_original
Complete test suite for cart actions
This commit is contained in:
@@ -6,4 +6,10 @@ from pretix.base.signals import determine_availability
|
|||||||
@receiver(determine_availability)
|
@receiver(determine_availability)
|
||||||
def availability_handler(sender, **kwargs):
|
def availability_handler(sender, **kwargs):
|
||||||
kwargs['sender'] = sender
|
kwargs['sender'] = sender
|
||||||
return kwargs
|
variations = kwargs['variations']
|
||||||
|
if sender.settings.testdummy_available is not None:
|
||||||
|
variations = [d.copy() for d in variations]
|
||||||
|
for v in variations:
|
||||||
|
v['available'] = (sender.settings.testdummy_available == 'yes')
|
||||||
|
return variations
|
||||||
|
return []
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import datetime
|
|||||||
import time
|
import time
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from pretix.base.models import Item, Organizer, Event, ItemCategory, Quota, Property, PropertyValue, ItemVariation, User, \
|
from pretix.base.models import Item, Organizer, Event, ItemCategory, Quota, Property, PropertyValue, ItemVariation, User, \
|
||||||
CartPosition
|
CartPosition
|
||||||
@@ -219,23 +221,27 @@ class CartTest(CartTestMixin, TestCase):
|
|||||||
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
||||||
self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists())
|
self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists())
|
||||||
|
|
||||||
def test_quota_max_items(self):
|
def test_max_items(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
self.event.settings.max_items_per_order = 5
|
self.event.settings.max_items_per_order = 5
|
||||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
'item_' + self.ticket.identity: '6',
|
'item_' + self.ticket.identity: '5',
|
||||||
}, follow=True)
|
}, follow=True)
|
||||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||||
target_status_code=200)
|
target_status_code=200)
|
||||||
doc = BeautifulSoup(response.rendered_content)
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
self.assertIn('more than', doc.select('.alert-danger')[0].text)
|
self.assertIn('more than', doc.select('.alert-danger')[0].text)
|
||||||
self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists())
|
self.assertEqual(CartPosition.objects.filter(user=self.user, event=self.event).count(), 1)
|
||||||
|
|
||||||
def test_quota_full(self):
|
def test_quota_full(self):
|
||||||
self.quota_tickets.size = 0
|
self.quota_tickets.size = 0
|
||||||
self.quota_tickets.save()
|
self.quota_tickets.save()
|
||||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
'item_' + self.ticket.identity: '1',
|
'item_' + self.ticket.identity: '1',
|
||||||
}, follow=True)
|
}, follow=True)
|
||||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||||
target_status_code=200)
|
target_status_code=200)
|
||||||
doc = BeautifulSoup(response.rendered_content)
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
@@ -246,8 +252,8 @@ class CartTest(CartTestMixin, TestCase):
|
|||||||
self.quota_tickets.size = 1
|
self.quota_tickets.size = 1
|
||||||
self.quota_tickets.save()
|
self.quota_tickets.save()
|
||||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
'item_' + self.ticket.identity: '2',
|
'item_' + self.ticket.identity: '2'
|
||||||
}, follow=True)
|
}, follow=True)
|
||||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||||
target_status_code=200)
|
target_status_code=200)
|
||||||
doc = BeautifulSoup(response.rendered_content)
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
@@ -261,3 +267,144 @@ class CartTest(CartTestMixin, TestCase):
|
|||||||
self.assertEqual(objs[0].item, self.ticket)
|
self.assertEqual(objs[0].item, self.ticket)
|
||||||
self.assertIsNone(objs[0].variation)
|
self.assertIsNone(objs[0].variation)
|
||||||
self.assertEqual(objs[0].price, 23)
|
self.assertEqual(objs[0].price, 23)
|
||||||
|
|
||||||
|
def test_renew_in_time(self):
|
||||||
|
cp = CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
|
}, follow=True)
|
||||||
|
cp = CartPosition.objects.current.get(identity=cp.identity)
|
||||||
|
self.assertGreater(cp.expires, now())
|
||||||
|
|
||||||
|
def test_renew_expired_successfully(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() - timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
|
}, follow=True)
|
||||||
|
objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event))
|
||||||
|
self.assertEqual(len(objs), 1)
|
||||||
|
self.assertEqual(objs[0].item, self.ticket)
|
||||||
|
self.assertIsNone(objs[0].variation)
|
||||||
|
self.assertEqual(objs[0].price, 23)
|
||||||
|
self.assertGreater(objs[0].expires, now())
|
||||||
|
|
||||||
|
def test_renew_expired_failed(self):
|
||||||
|
self.quota_tickets.size = 0
|
||||||
|
self.quota_tickets.save()
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() - timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
|
}, follow=True)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
||||||
|
self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists())
|
||||||
|
|
||||||
|
def test_restriction_failed(self):
|
||||||
|
self.event.plugins = 'pretix.plugins.testdummy'
|
||||||
|
self.event.save()
|
||||||
|
self.event.settings.testdummy_available = 'yes'
|
||||||
|
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
|
'item_' + self.ticket.identity: '1',
|
||||||
|
}, follow=True)
|
||||||
|
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||||
|
target_status_code=200)
|
||||||
|
objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event))
|
||||||
|
self.assertEqual(len(objs), 1)
|
||||||
|
self.assertEqual(objs[0].item, self.ticket)
|
||||||
|
self.assertIsNone(objs[0].variation)
|
||||||
|
self.assertEqual(objs[0].price, 23)
|
||||||
|
|
||||||
|
def test_restriction_ok(self):
|
||||||
|
self.event.plugins = 'pretix.plugins.testdummy'
|
||||||
|
self.event.save()
|
||||||
|
self.event.settings.testdummy_available = 'no'
|
||||||
|
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||||
|
'item_' + self.ticket.identity: '1',
|
||||||
|
}, follow=True)
|
||||||
|
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||||
|
target_status_code=200)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
||||||
|
self.assertFalse(CartPosition.objects.filter(user=self.user, event=self.event).exists())
|
||||||
|
|
||||||
|
def test_remove_simple(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
|
||||||
|
'item_' + self.ticket.identity: '1',
|
||||||
|
}, follow=True)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('updated', doc.select('.alert-success')[0].text)
|
||||||
|
self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists())
|
||||||
|
|
||||||
|
def test_remove_variation(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.shirt, variation=self.shirt_red,
|
||||||
|
price=14, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
|
||||||
|
'variation_' + self.shirt.identity + '_' + self.shirt_red.identity: '1',
|
||||||
|
}, follow=True)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('updated', doc.select('.alert-success')[0].text)
|
||||||
|
self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists())
|
||||||
|
|
||||||
|
def test_remove_one_of_multiple(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
|
||||||
|
'item_' + self.ticket.identity: '1',
|
||||||
|
}, follow=True)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('updated', doc.select('.alert-success')[0].text)
|
||||||
|
self.assertEqual(CartPosition.objects.current.filter(user=self.user, event=self.event).count(), 1)
|
||||||
|
|
||||||
|
def test_remove_multiple(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
|
||||||
|
'item_' + self.ticket.identity: '2',
|
||||||
|
}, follow=True)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('updated', doc.select('.alert-success')[0].text)
|
||||||
|
self.assertFalse(CartPosition.objects.current.filter(user=self.user, event=self.event).exists())
|
||||||
|
|
||||||
|
def test_remove_most_expensive(self):
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, user=self.user, item=self.ticket,
|
||||||
|
price=20, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
|
||||||
|
'item_' + self.ticket.identity: '1',
|
||||||
|
}, follow=True)
|
||||||
|
doc = BeautifulSoup(response.rendered_content)
|
||||||
|
self.assertIn('updated', doc.select('.alert-success')[0].text)
|
||||||
|
objs = list(CartPosition.objects.current.filter(user=self.user, event=self.event))
|
||||||
|
self.assertEqual(len(objs), 1)
|
||||||
|
self.assertEqual(objs[0].item, self.ticket)
|
||||||
|
self.assertIsNone(objs[0].variation)
|
||||||
|
self.assertEqual(objs[0].price, 20)
|
||||||
|
|||||||
@@ -47,16 +47,16 @@ class CartActionMixin:
|
|||||||
items.append((key.split("_")[1], None, int(value)))
|
items.append((key.split("_")[1], None, int(value)))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
messages.error(self.request, _('Please enter numbers only.'))
|
messages.error(self.request, _('Please enter numbers only.'))
|
||||||
return False
|
return []
|
||||||
elif key.startswith('variation_'):
|
elif key.startswith('variation_'):
|
||||||
try:
|
try:
|
||||||
items.append((key.split("_")[1], key.split("_")[2], int(value)))
|
items.append((key.split("_")[1], key.split("_")[2], int(value)))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
messages.error(self.request, _('Please enter numbers only.'))
|
messages.error(self.request, _('Please enter numbers only.'))
|
||||||
return False
|
return []
|
||||||
if len(items) == 0:
|
if len(items) == 0:
|
||||||
messages.warning(self.request, _('You did not select any items.'))
|
messages.warning(self.request, _('You did not select any items.'))
|
||||||
return False
|
return []
|
||||||
return items
|
return items
|
||||||
|
|
||||||
def _re_add_position(self, items, position):
|
def _re_add_position(self, items, position):
|
||||||
@@ -91,6 +91,21 @@ class CartRemove(EventViewMixin, CartActionMixin, EventLoginRequiredMixin, View)
|
|||||||
|
|
||||||
class CartAdd(EventViewMixin, CartActionMixin, View):
|
class CartAdd(EventViewMixin, CartActionMixin, View):
|
||||||
|
|
||||||
|
error_messages = {
|
||||||
|
'unavailable': _('Some of the items you selected were no longer available. '
|
||||||
|
'Please see below for details.'),
|
||||||
|
'in_part': _('Some of the items you selected were no longer available in '
|
||||||
|
'the quantity you selected. Please see below for details.'),
|
||||||
|
'busy': _('We were not able to process your request completely as the '
|
||||||
|
'server was too busy. Please try again.'),
|
||||||
|
'not_for_sale': _('You selected an item which is not available for sale.'),
|
||||||
|
'max_items': _("You cannot select more than %s items per order"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.msg_some_unavailable = False
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
items = self._items_from_post_data()
|
items = self._items_from_post_data()
|
||||||
|
|
||||||
@@ -107,20 +122,15 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
|||||||
)
|
)
|
||||||
return self.process(items)
|
return self.process(items)
|
||||||
|
|
||||||
def process(self, items):
|
def error_message(self, msg, important=False):
|
||||||
if not items:
|
if not self.msg_some_unavailable or important:
|
||||||
return redirect(self.get_failure_url())
|
self.msg_some_unavailable = True
|
||||||
existing = CartPosition.objects.current.filter(user=self.request.user, event=self.request.event).count()
|
messages.error(self.request, msg)
|
||||||
if sum(i[2] for i in items) + existing > int(self.request.event.settings.max_items_per_order):
|
|
||||||
# TODO: i18n plurals
|
|
||||||
messages.error(self.request,
|
|
||||||
_("You cannot select more than %s items per order") % self.request.event.settings.max_items_per_order)
|
|
||||||
return redirect(self.get_failure_url())
|
|
||||||
|
|
||||||
|
def process(self, items):
|
||||||
# Extend this user's cart session to 30 minutes from now to ensure all items in the
|
# Extend this user's cart session to 30 minutes from now to ensure all items in the
|
||||||
# cart expire at the same
|
# cart expire at the same time
|
||||||
# We can extend the reservation of items which are not yet expired without
|
# We can extend the reservation of items which are not yet expired without risk
|
||||||
# risk
|
|
||||||
CartPosition.objects.current.filter(
|
CartPosition.objects.current.filter(
|
||||||
Q(user=self.request.user) & Q(event=self.request.event) & Q(expires__gt=now())
|
Q(user=self.request.user) & Q(event=self.request.event) & Q(expires__gt=now())
|
||||||
).update(expires=now() + timedelta(minutes=30))
|
).update(expires=now() + timedelta(minutes=30))
|
||||||
@@ -132,6 +142,15 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
|||||||
items = self._re_add_position(items, cp)
|
items = self._re_add_position(items, cp)
|
||||||
cp.delete()
|
cp.delete()
|
||||||
|
|
||||||
|
if not items:
|
||||||
|
return redirect(self.get_failure_url())
|
||||||
|
|
||||||
|
existing = CartPosition.objects.current.filter(user=self.request.user, event=self.request.event).count()
|
||||||
|
if sum(i[2] for i in items) + existing > int(self.request.event.settings.max_items_per_order):
|
||||||
|
# TODO: i18n plurals
|
||||||
|
self.error_message(self.error_messages['max_items'] % self.request.event.settings.max_items_per_order)
|
||||||
|
return redirect(self.get_failure_url())
|
||||||
|
|
||||||
# Fetch items from the database
|
# Fetch items from the database
|
||||||
items_cache = {
|
items_cache = {
|
||||||
i.identity: i for i
|
i.identity: i for i
|
||||||
@@ -149,13 +168,12 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Process the request itself
|
# Process the request itself
|
||||||
msg_some_unavailable = False
|
|
||||||
for i in items:
|
for i in items:
|
||||||
# Check whether the specified items are part of what we just fetched from the database
|
# Check whether the specified items are part of what we just fetched from the database
|
||||||
# If they are not, the user supplied item IDs which either do not exist or belong to
|
# If they are not, the user supplied item IDs which either do not exist or belong to
|
||||||
# a different event
|
# a different event
|
||||||
if i[0] not in items_cache or (i[1] is not None and i[1] not in variations_cache):
|
if i[0] not in items_cache or (i[1] is not None and i[1] not in variations_cache):
|
||||||
messages.error(self.request, _('You selected an item which is not available for sale.'))
|
self.error_message(self.error_messages['not_for_sale'])
|
||||||
return redirect(self.get_failure_url())
|
return redirect(self.get_failure_url())
|
||||||
|
|
||||||
item = items_cache[i[0]]
|
item = items_cache[i[0]]
|
||||||
@@ -166,21 +184,13 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
|||||||
# will correctly return the default price
|
# will correctly return the default price
|
||||||
price = item.check_restrictions() if variation is None else variation.check_restrictions()
|
price = item.check_restrictions() if variation is None else variation.check_restrictions()
|
||||||
if price is False:
|
if price is False:
|
||||||
if not msg_some_unavailable:
|
self.error_message(self.error_messages['unavailable'])
|
||||||
msg_some_unavailable = True
|
|
||||||
messages.error(self.request,
|
|
||||||
_('Some of the items you selected were no longer available. '
|
|
||||||
'Please see below for details.'))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Fetch all quotas. If there are no quotas, this item is not allowed to be sold.
|
# Fetch all quotas. If there are no quotas, this item is not allowed to be sold.
|
||||||
quotas = list(item.quotas.all()) if variation is None else list(variation.quotas.all())
|
quotas = list(item.quotas.all()) if variation is None else list(variation.quotas.all())
|
||||||
if len(quotas) == 0:
|
if len(quotas) == 0:
|
||||||
if not msg_some_unavailable:
|
self.error_message(self.error_messages['unavailable'])
|
||||||
msg_some_unavailable = True
|
|
||||||
messages.error(self.request,
|
|
||||||
_('Some of the items you selected were no longer available. '
|
|
||||||
'Please see below for details.'))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Assume that all quotas allow us to buy i[2] instances of the object
|
# Assume that all quotas allow us to buy i[2] instances of the object
|
||||||
@@ -193,21 +203,13 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
|||||||
avail = quota.availability()
|
avail = quota.availability()
|
||||||
if avail[0] != Quota.AVAILABILITY_OK:
|
if avail[0] != Quota.AVAILABILITY_OK:
|
||||||
# This quota is sold out/currently unavailable, so do not sell this at all
|
# This quota is sold out/currently unavailable, so do not sell this at all
|
||||||
if not msg_some_unavailable:
|
self.error_message(self.error_messages['unavailable'])
|
||||||
msg_some_unavailable = True
|
|
||||||
messages.error(self.request,
|
|
||||||
_('Some of the items you selected were no longer available. '
|
|
||||||
'Please see below for details.'))
|
|
||||||
quota_ok = 0
|
quota_ok = 0
|
||||||
break
|
break
|
||||||
elif avail[1] < i[2]:
|
elif avail[1] < i[2]:
|
||||||
# This quota is available, but with less than i[2] items left, so we have to
|
# This quota is available, but with less than i[2] items left, so we have to
|
||||||
# reduce the number of bought items
|
# reduce the number of bought items
|
||||||
if not msg_some_unavailable:
|
self.error_message(self.error_messages['in_part'])
|
||||||
msg_some_unavailable = True
|
|
||||||
messages.error(self.request,
|
|
||||||
_('Some of the items you selected were no longer available in '
|
|
||||||
'the quantity you selected. Please see below for details.'))
|
|
||||||
quota_ok = min(quota_ok, avail[1])
|
quota_ok = min(quota_ok, avail[1])
|
||||||
|
|
||||||
# Create a CartPosition for as much items as we can
|
# Create a CartPosition for as much items as we can
|
||||||
@@ -223,20 +225,13 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
|||||||
except Quota.LockTimeoutException:
|
except Quota.LockTimeoutException:
|
||||||
# Is raised when there are too many threads asking for quota locks and we were
|
# Is raised when there are too many threads asking for quota locks and we were
|
||||||
# unaible to get one
|
# unaible to get one
|
||||||
if not msg_some_unavailable:
|
self.error_message(self.error_messages['busy'], important=True)
|
||||||
msg_some_unavailable = True
|
|
||||||
messages.error(self.request,
|
|
||||||
_('We were not able to process your request completely as the '
|
|
||||||
'server was too busy. Please try again.'))
|
|
||||||
finally:
|
finally:
|
||||||
# Release the locks. This is important ;)
|
# Release the locks. This is important ;)
|
||||||
for quota in quotas:
|
for quota in quotas:
|
||||||
quota.release()
|
quota.release()
|
||||||
|
|
||||||
if not msg_some_unavailable:
|
if not self.msg_some_unavailable:
|
||||||
messages.success(self.request, _('The items have been successfully added to your cart.'))
|
messages.success(self.request, _('The items have been successfully added to your cart.'))
|
||||||
|
|
||||||
return redirect(self.get_success_url())
|
return redirect(self.get_success_url())
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
return redirect(self.get_failure_url())
|
|
||||||
|
|||||||
Reference in New Issue
Block a user