Refs #118 -- Asynchronous cart position removal

This commit is contained in:
Raphael Michel
2016-01-13 11:51:25 +01:00
parent dc0852f54f
commit 55a501cb93
3 changed files with 48 additions and 18 deletions

View File

@@ -167,6 +167,18 @@ def add_items_to_cart(event: int, items: List[Tuple[int, Optional[int], int]], c
raise CartError(error_messages['busy'])
def _remove_items_from_cart(event: int, items: List[Tuple[int, Optional[int], int]], cart_id: int) -> None:
with event.lock():
for item, variation, cnt in items:
cw = Q(cart_id=cart_id) & Q(item_id=item) & Q(event=event)
if variation:
cw &= Q(variation_id=variation)
else:
cw &= Q(variation__isnull=True)
for cp in CartPosition.objects.filter(cw).order_by("-price")[:cnt]:
cp.delete()
def remove_items_from_cart(event: int, items: List[Tuple[int, Optional[int], int]], cart_id: int=None) -> None:
"""
Removes a list of items from a user's cart.
@@ -175,15 +187,10 @@ def remove_items_from_cart(event: int, items: List[Tuple[int, Optional[int], int
:param session: Session ID of a guest
"""
event = Event.objects.get(id=event)
for item, variation, cnt in items:
cw = Q(cart_id=cart_id) & Q(item_id=item) & Q(event=event)
if variation:
cw &= Q(variation_id=variation)
else:
cw &= Q(variation__isnull=True)
for cp in CartPosition.objects.filter(cw).order_by("-price")[:cnt]:
cp.delete()
try:
_remove_items_from_cart(event, items, cart_id)
except EventLock.LockTimeoutException:
raise CartError(error_messages['busy'])
if settings.HAS_CELERY:
@@ -197,4 +204,13 @@ if settings.HAS_CELERY:
except EventLock.LockTimeoutException:
self.retry(exc=CartError(error_messages['busy']))
@app.task(bind=True, max_retries=5, default_retry_delay=2)
def remove_items_from_cart_task(self, event: int, items: List[Tuple[int, Optional[int], int]], cart_id: str):
event = Event.objects.get(id=event)
try:
_remove_items_from_cart(event, items, cart_id)
except EventLock.LockTimeoutException:
self.retry(exc=CartError(error_messages['busy']))
add_items_to_cart.task = add_items_to_cart_task
remove_items_from_cart.task = remove_items_from_cart_task

View File

@@ -23,7 +23,7 @@
<div class="col-md-2 col-xs-6 count">
{% if editable %}
<form action="{% eventurl event "presale:event.cart.remove" %}"
method="post">
method="post" data-asynctask>
{% csrf_token %}
{% if line.variation %}
<input type="hidden" name="variation_{{ line.item.id }}_{{ line.variation.id }}"

View File

@@ -53,16 +53,30 @@ class CartActionMixin:
return items
class CartRemove(EventViewMixin, CartActionMixin, View):
class CartRemove(EventViewMixin, CartActionMixin, AsyncAction, View):
task = remove_items_from_cart
def post(self, *args, **kwargs):
def get_success_message(self, value):
return _('Your cart has been updated.')
def get_error_message(self, exception):
if isinstance(exception, dict) and exception['exc_type'] == 'CartError':
return exception['exc_message']
elif isinstance(exception, CartError):
return str(exception)
return super().get_error_message(exception)
def post(self, request, *args, **kwargs):
items = self._items_from_post_data()
if not items:
return redirect(self.get_error_url())
remove_items_from_cart(self.request.event.id, items, self.request.session.session_key)
messages.success(self.request, _('Your cart has been updated.'))
return redirect(self.get_success_url())
if items:
return self.do(self.request.event.id, items, self.request.session.session_key)
else:
if 'ajax' in self.request.GET or 'ajax' in self.request.POST:
return JsonResponse({
'redirect': self.get_error_url()
})
else:
return redirect(self.get_error_url())
class CartAdd(EventViewMixin, CartActionMixin, AsyncAction, View):