Refs #118 -- Asynchronous order cancelling

This commit is contained in:
Raphael Michel
2016-03-20 10:40:18 +01:00
parent 0044078ec5
commit 0355d22114
4 changed files with 73 additions and 23 deletions

View File

@@ -94,39 +94,51 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
@transaction.atomic
def mark_order_refunded(order: Order, user: User=None):
def mark_order_refunded(order, user=None):
"""
Mark this order as refunded. This sets the payment status and returns the order object.
:param order: The order to change
:param user: The user that performed the change
"""
order.status = Order.STATUS_REFUNDED
order.save()
order.log_action('pretix.event.order.refunded', user=user)
if isinstance(order, int):
order = Order.objects.get(pk=order)
if isinstance(user, int):
user = User.objects.get(pk=user)
with order.event.lock():
order.status = Order.STATUS_REFUNDED
order.save()
order.log_action('pretix.event.order.refunded', user=user)
i = order.invoices.filter(is_cancellation=False).last()
if i:
generate_cancellation(i)
i = order.invoices.filter(is_cancellation=False).last()
if i:
generate_cancellation(i)
return order
return order
@transaction.atomic
def cancel_order(order: Order, user: User=None):
def cancel_order(order, user=None):
"""
Mark this order as canceled
:param order: The order to change
:param user: The user that performed the change
"""
order.status = Order.STATUS_CANCELLED
order.save()
order.log_action('pretix.event.order.cancelled', user=user)
if isinstance(order, int):
order = Order.objects.get(pk=order)
if isinstance(user, int):
user = User.objects.get(pk=user)
with order.event.lock():
if order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED):
raise OrderError(_('You cannot cancel this order'))
order.status = Order.STATUS_CANCELLED
order.save()
order.log_action('pretix.event.order.cancelled', user=user)
i = order.invoices.filter(is_cancellation=False).last()
if i:
generate_cancellation(i)
i = order.invoices.filter(is_cancellation=False).last()
if i:
generate_cancellation(i)
return order
return order
class OrderError(Exception):
@@ -310,4 +322,12 @@ if settings.HAS_CELERY:
except EventLock.LockTimeoutException:
self.retry(exc=OrderError(error_messages['busy']))
@app.task(bind=True, max_retries=5, default_retry_delay=2)
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']))
perform_order.task = perform_order_task
cancel_order.task = cancel_order_task

View File

@@ -12,7 +12,7 @@
Do you really want to cancel this order? You cannot revert this action.
{% endblocktrans %}</p>
<form method="post" href="">
<form method="post" action="{% eventurl request.event "presale:event.order.cancel.do" secret=order.secret order=order.code %}" data-asynctask>
{% csrf_token %}
<div class="row checkout-button-row">
<div class="col-md-4">

View File

@@ -21,6 +21,9 @@ event_patterns = [
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/cancel$',
pretix.presale.views.order.OrderCancel.as_view(),
name='event.order.cancel'),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/cancel/do$',
pretix.presale.views.order.OrderCancelDo.as_view(),
name='event.order.cancel.do'),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/modify$',
pretix.presale.views.order.OrderModify.as_view(),
name='event.order.modify'),

View File

@@ -6,7 +6,7 @@ from django.http import Http404
from django.shortcuts import redirect
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, gettext
from django.views.generic import TemplateView, View
from pretix.base.models import (
@@ -14,7 +14,7 @@ from pretix.base.models import (
)
from pretix.base.models.orders import InvoiceAddress
from pretix.base.services.invoices import invoice_pdf
from pretix.base.services.orders import cancel_order
from pretix.base.services.orders import cancel_order, OrderError
from pretix.base.services.tickets import generate
from pretix.base.signals import (
register_payment_providers, register_ticket_outputs,
@@ -22,6 +22,7 @@ from pretix.base.signals import (
from pretix.multidomain.urlreverse import eventreverse
from pretix.presale.forms.checkout import InvoiceAddressForm
from pretix.presale.views import CartMixin, EventViewMixin
from pretix.presale.views.async import AsyncAction
from pretix.presale.views.questions import QuestionsViewMixin
@@ -270,10 +271,6 @@ class OrderCancel(EventViewMixin, OrderDetailMixin, TemplateView):
return redirect(self.get_order_url())
return super().dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
cancel_order(self.order)
return redirect(self.get_order_url())
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
@@ -283,6 +280,36 @@ class OrderCancel(EventViewMixin, OrderDetailMixin, TemplateView):
return ctx
class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
task = cancel_order
def get_success_url(self, value):
return self.get_order_url()
def get_error_url(self):
return self.get_order_url()
def post(self, request, *args, **kwargs):
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
return self.do(self.order)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['order'] = self.order
return ctx
def get_success_message(self, value):
return _('The order has been cancelled.')
def get_error_message(self, exception):
if isinstance(exception, dict) and exception['exc_type'] == 'OrderError':
return gettext(exception['exc_message'])
elif isinstance(exception, OrderError):
return str(exception)
return super().get_error_message(exception)
class OrderDownload(EventViewMixin, OrderDetailMixin, View):
@cached_property
def output(self):