diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index 1fac08175..d209102ad 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -12,7 +12,6 @@ from pretix.base.models import ( ) from pretix.base.services.async import ProfiledTask from pretix.base.services.locking import LockTimeoutException -from pretix.base.signals import validate_cart from pretix.celery_app import app @@ -208,11 +207,6 @@ def _add_items_to_cart(event: Event, items: List[dict], cart_id: str=None) -> No # TODO: i18n plurals raise CartError(error_messages['max_items'], (event.settings.max_items_per_order,)) - validate_cart.send( - sender=event, positions=CartPosition.objects.filter(Q(cart_id=cart_id) & Q(event=event)), - requested_add=items, requested_delete=[] - ) - expiry = now_dt + timedelta(minutes=event.settings.get('reservation_time', as_type=int)) _extend_existing(event, cart_id, expiry, now_dt) @@ -246,11 +240,6 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None) -> def _remove_items_from_cart(event: Event, items: List[dict], cart_id: str) -> None: with event.lock(): - validate_cart.send( - sender=event, positions=CartPosition.objects.filter(Q(cart_id=cart_id) & Q(event=event)), - requested_add=[], requested_delete=items - ) - for i in items: cw = Q(cart_id=cart_id) & Q(item_id=i['item']) & Q(event=event) if i['variation']: diff --git a/src/pretix/base/signals.py b/src/pretix/base/signals.py index d9eafd956..8381a9097 100644 --- a/src/pretix/base/signals.py +++ b/src/pretix/base/signals.py @@ -95,14 +95,13 @@ As with all event-plugin signals, the ``sender`` keyword argument will contain t """ validate_cart = EventPluginSignal( - providing_args=["positions", "requested_add", "requested_delete"] + providing_args=["positions"] ) """ -This signal is sent out every time a cart is about to be changed. It includes an iterable -with the current CartPosition objects as well as lists of dictionaries of the cart items -that the user wants to add. Those dictionaries can contain the keys ``item``, ``variation``, -``count``, ``price`` and ``voucher``. The response of receivers will be ignored, but you can -raise an OrderError with an appropriate exception message. +This signal is sent out before the user starts checkout. It includes an iterable +with the current CartPosition objects. +The response of receivers will be ignored, but you can raise a CartError with an +appropriate exception message. As with all event-plugin signals, the ``sender`` keyword argument will contain the event. """ diff --git a/src/pretix/presale/views/checkout.py b/src/pretix/presale/views/checkout.py index fc8782fe7..76c5623ea 100644 --- a/src/pretix/presale/views/checkout.py +++ b/src/pretix/presale/views/checkout.py @@ -5,6 +5,8 @@ from django.utils.translation import ugettext_lazy as _ from django.views.generic import View from pretix.base.models import CartPosition +from pretix.base.services.cart import CartError +from pretix.base.signals import validate_cart from pretix.multidomain.urlreverse import eventreverse from pretix.presale.checkoutflow import get_checkout_flow @@ -12,12 +14,20 @@ from pretix.presale.checkoutflow import get_checkout_flow class CheckoutView(View): def dispatch(self, request, *args, **kwargs): self.request = request - has_cart = CartPosition.objects.filter( - cart_id=self.request.session.session_key, event=self.request.event).exists() - if not has_cart and "async_id" not in request.GET: + cart_pos = CartPosition.objects.filter( + cart_id=self.request.session.session_key, event=self.request.event + ) + + if not cart_pos.exists() and "async_id" not in request.GET: messages.error(request, _("Your cart is empty")) return redirect(eventreverse(self.request.event, 'presale:event.index')) + try: + validate_cart.send(sender=self.request.event, positions=cart_pos) + except CartError as e: + messages.error(request, str(e)) + return redirect(eventreverse(self.request.event, 'presale:event.index')) + flow = get_checkout_flow(self.request.event) for step in flow: if not step.is_applicable(request):