diff --git a/src/pretix/base/i18n.py b/src/pretix/base/i18n.py index 4cfbf141e..b183a1d97 100644 --- a/src/pretix/base/i18n.py +++ b/src/pretix/base/i18n.py @@ -342,3 +342,16 @@ def language(lng): yield finally: translation.activate(_lng) + + +class LazyLocaleException(Exception): + def __init__(self, msg, msgargs=None): + self.msg = msg + self.msgargs = msgargs + super().__init__(msg, msgargs) + + def __str__(self): + if self.msgargs: + return ugettext(self.msg) % self.msgargs + else: + return ugettext(self.msg) diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index cd29d4652..4c9299cb6 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -1,18 +1,18 @@ from datetime import datetime, timedelta from django.conf import settings -from django.db import transaction from django.db.models import Q from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from typing import List, Optional, Tuple +from pretix.base.i18n import LazyLocaleException from pretix.base.models import ( CartPosition, Event, EventLock, Item, ItemVariation, Quota, Voucher, ) -class CartError(Exception): +class CartError(LazyLocaleException): pass @@ -168,7 +168,7 @@ def _add_items_to_cart(event: Event, items: List[Tuple[int, Optional[int], int]] existing = CartPosition.objects.filter(Q(cart_id=cart_id) & Q(event=event)).count() if sum(i[2] for i in items) + existing > int(event.settings.max_items_per_order): # TODO: i18n plurals - raise CartError(error_messages['max_items'] % event.settings.max_items_per_order) + raise CartError(error_messages['max_items'], (event.settings.max_items_per_order,)) expiry = now() + timedelta(minutes=event.settings.get('reservation_time', as_type=int)) _extend_existing(event, cart_id, expiry) @@ -232,22 +232,28 @@ def remove_items_from_cart(event: int, items: List[Tuple[int, Optional[int], int if settings.HAS_CELERY: from pretix.celery import app - @app.task(bind=True, max_retries=5, default_retry_delay=2) + @app.task(bind=True, max_retries=5, default_retry_delay=1) def add_items_to_cart_task(self, event: int, items: List[Tuple[int, Optional[int], int]], cart_id: str, voucher: str=None): event = Event.objects.get(id=event) try: - _add_items_to_cart(event, items, cart_id, voucher) - except EventLock.LockTimeoutException: - self.retry(exc=CartError(error_messages['busy'])) + try: + _add_items_to_cart(event, items, cart_id, voucher) + except EventLock.LockTimeoutException: + self.retry(exc=CartError(error_messages['busy'])) + except CartError as e: + return e - @app.task(bind=True, max_retries=5, default_retry_delay=2) + @app.task(bind=True, max_retries=5, default_retry_delay=1) 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'])) + try: + _remove_items_from_cart(event, items, cart_id) + except EventLock.LockTimeoutException: + self.retry(exc=CartError(error_messages['busy'])) + except CartError as e: + return e add_items_to_cart.task = add_items_to_cart_task remove_items_from_cart.task = remove_items_from_cart_task diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index e588fd1a4..24ad47ace 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -7,7 +7,9 @@ from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from typing import List -from pretix.base.i18n import LazyDate, LazyNumber, language +from pretix.base.i18n import ( + LazyDate, LazyLocaleException, LazyNumber, language, +) from pretix.base.models import ( CartPosition, Event, EventLock, Order, OrderPosition, Quota, User, ) @@ -29,7 +31,6 @@ error_messages = { 'the quantity you selected. Please see below for details.'), 'price_changed': _('The price of some of the items in your cart has changed in the ' 'meantime. Please see below for details.'), - 'max_items': _("You cannot select more than %s items per order"), 'internal': _("An internal error occured, please try again."), 'busy': _('We were not able to process your request completely as the ' 'server was too busy. Please try again.'), @@ -142,7 +143,7 @@ def cancel_order(order, user=None): return order -class OrderError(Exception): +class OrderError(LazyLocaleException): pass @@ -315,20 +316,26 @@ def perform_order(event: str, payment_provider: str, positions: List[str], if settings.HAS_CELERY: from pretix.celery import app - @app.task(bind=True, max_retries=5, default_retry_delay=2) + @app.task(bind=True, max_retries=5, default_retry_delay=1) def perform_order_task(self, event: str, payment_provider: str, positions: List[str], email: str=None, locale: str=None, address: int=None): try: - return _perform_order(event, payment_provider, positions, email, locale, address) - except EventLock.LockTimeoutException: - self.retry(exc=OrderError(error_messages['busy'])) + try: + return _perform_order(event, payment_provider, positions, email, locale, address) + except EventLock.LockTimeoutException: + self.retry(exc=OrderError(error_messages['busy'])) + except OrderError as e: + return e - @app.task(bind=True, max_retries=5, default_retry_delay=2) + @app.task(bind=True, max_retries=5, default_retry_delay=1) def cancel_order_task(self, order: int, user: int=None): try: - return cancel_order(order, user) - except EventLock.LockTimeoutException: - self.retry(exc=OrderError(error_messages['busy'])) + try: + return cancel_order(order, user) + except EventLock.LockTimeoutException: + self.retry(exc=OrderError(error_messages['busy'])) + except OrderError as e: + return e perform_order.task = perform_order_task cancel_order.task = cancel_order_task diff --git a/src/pretix/presale/views/async.py b/src/pretix/presale/views/async.py index dcdf3ecab..815646710 100644 --- a/src/pretix/presale/views/async.py +++ b/src/pretix/presale/views/async.py @@ -48,7 +48,7 @@ class AsyncAction: 'ready': res.ready() } if res.ready(): - if res.successful(): + if res.successful() and not isinstance(res.info, Exception): smes = self.get_success_message(res.info) if smes: messages.success(self.request, smes)