mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Refs #33 -- Added UI and Stripe support for retrying failed payments
This commit is contained in:
@@ -129,7 +129,7 @@ class BasePaymentProvider:
|
||||
pass
|
||||
|
||||
@property
|
||||
def checkout_form_fields(self) -> dict:
|
||||
def payment_form_fields(self) -> dict:
|
||||
"""
|
||||
This is used by the default implementation of :py:meth:`checkout_form`.
|
||||
It should return an object similar to :py:attr:`settings_form_fields`.
|
||||
@@ -138,7 +138,7 @@ class BasePaymentProvider:
|
||||
"""
|
||||
return {}
|
||||
|
||||
def checkout_form(self, request: HttpRequest) -> Form:
|
||||
def payment_form(self, request: HttpRequest) -> Form:
|
||||
"""
|
||||
This is called by the default implementation of :py:meth:`checkout_form_render`
|
||||
to obtain the form that is displayed to the user during the checkout
|
||||
@@ -155,7 +155,7 @@ class BasePaymentProvider:
|
||||
if k.startswith('payment_%s_' % self.identifier)
|
||||
}
|
||||
)
|
||||
form.fields = self.checkout_form_fields
|
||||
form.fields = self.payment_form_fields
|
||||
return form
|
||||
|
||||
def is_allowed(self, request: HttpRequest) -> bool:
|
||||
@@ -168,7 +168,7 @@ class BasePaymentProvider:
|
||||
"""
|
||||
return True
|
||||
|
||||
def checkout_form_render(self, request: HttpRequest) -> str:
|
||||
def payment_form_render(self, request: HttpRequest) -> str:
|
||||
"""
|
||||
When the user selects this provider as his prefered payment method,
|
||||
he will be shown the HTML you return from this method.
|
||||
@@ -178,7 +178,7 @@ class BasePaymentProvider:
|
||||
the user to fill out form fields, you should just return a paragraph
|
||||
of explainatory text.
|
||||
"""
|
||||
form = self.checkout_form(request)
|
||||
form = self.payment_form(request)
|
||||
template = get_template('pretixpresale/event/checkout_payment_form_default.html')
|
||||
ctx = {'request': request, 'form': form}
|
||||
return template.render(ctx)
|
||||
@@ -209,7 +209,7 @@ class BasePaymentProvider:
|
||||
to the user (or the normal form validation error messages).
|
||||
|
||||
The default implementation stores the input into the form returned by
|
||||
:py:meth:`checkout_form` in the user's session.
|
||||
:py:meth:`payment_form` in the user's session.
|
||||
|
||||
If your payment method requires you to redirect the user to an external provider,
|
||||
this might be the place to do so.
|
||||
@@ -233,7 +233,7 @@ class BasePaymentProvider:
|
||||
payment_fee:
|
||||
The fee for the payment method.
|
||||
"""
|
||||
form = self.checkout_form(request)
|
||||
form = self.payment_form(request)
|
||||
if form.is_valid():
|
||||
for k, v in form.cleaned_data.items():
|
||||
request.session['payment_%s_%s' % (self.identifier, k)] = v
|
||||
@@ -241,7 +241,7 @@ class BasePaymentProvider:
|
||||
else:
|
||||
return False
|
||||
|
||||
def checkout_is_valid_session(self, request: HttpRequest) -> bool:
|
||||
def payment_is_valid_session(self, request: HttpRequest) -> bool:
|
||||
"""
|
||||
This is called at the time the user tries to place the order. It should return
|
||||
``True``, if the user's session is valid and all data your payment provider requires
|
||||
@@ -249,7 +249,7 @@ class BasePaymentProvider:
|
||||
"""
|
||||
raise NotImplementedError() # NOQA
|
||||
|
||||
def checkout_perform(self, request: HttpRequest, order: Order) -> str:
|
||||
def payment_perform(self, request: HttpRequest, order: Order) -> str:
|
||||
"""
|
||||
After the user confirmed his purchase, this method will be called to complete
|
||||
the payment process. This is the place to actually move the money, if applicable.
|
||||
@@ -299,6 +299,32 @@ class BasePaymentProvider:
|
||||
"""
|
||||
raise NotImplementedError() # NOQA
|
||||
|
||||
def order_can_retry(self, order: Order) -> bool:
|
||||
"""
|
||||
Will be called if the user views the detail page of an unpaid order to determine
|
||||
whether the user should be presented with an option to retry the payment. The default
|
||||
implementation always returns False.
|
||||
|
||||
:param order: The order object
|
||||
"""
|
||||
return False
|
||||
|
||||
def retry_prepare(self, request: HttpRequest, order: Order) -> "bool|str":
|
||||
"""
|
||||
Will be called if the user retries to pay an unpaid order (after the user filled in
|
||||
e.g. the form returned by :py:meth:`payment_form`).
|
||||
|
||||
It should return and report errors the same way as :py:meth:`checkout_prepare`, but
|
||||
receives an ``Order`` object instead of a cart object.
|
||||
"""
|
||||
form = self.payment_form(request)
|
||||
if form.is_valid():
|
||||
for k, v in form.cleaned_data.items():
|
||||
request.session['payment_%s_%s' % (self.identifier, k)] = v
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def order_paid_render(self, request: HttpRequest, order: Order) -> str:
|
||||
"""
|
||||
Will be called if the user views the detail page of an paid order which is
|
||||
@@ -377,14 +403,14 @@ class FreeOrderProvider(BasePaymentProvider):
|
||||
def order_pending_render(self, request: HttpRequest, order: Order) -> str:
|
||||
pass
|
||||
|
||||
def checkout_is_valid_session(self, request: HttpRequest) -> bool:
|
||||
def payment_is_valid_session(self, request: HttpRequest) -> bool:
|
||||
return True
|
||||
|
||||
@property
|
||||
def verbose_name(self) -> str:
|
||||
return _("Free of charge")
|
||||
|
||||
def checkout_perform(self, request: HttpRequest, order: Order):
|
||||
def payment_perform(self, request: HttpRequest, order: Order):
|
||||
mark_order_paid(order, 'free')
|
||||
|
||||
@property
|
||||
|
||||
@@ -23,7 +23,7 @@ class BankTransfer(BasePaymentProvider):
|
||||
]
|
||||
)
|
||||
|
||||
def checkout_form_render(self, request) -> str:
|
||||
def payment_form_render(self, request) -> str:
|
||||
template = get_template('pretixplugins/banktransfer/checkout_payment_form.html')
|
||||
ctx = {'request': request, 'event': self.event, 'settings': self.settings}
|
||||
return template.render(ctx)
|
||||
@@ -31,11 +31,11 @@ class BankTransfer(BasePaymentProvider):
|
||||
def checkout_prepare(self, request, total):
|
||||
return True
|
||||
|
||||
def checkout_is_valid_session(self, request):
|
||||
def payment_is_valid_session(self, request):
|
||||
return True
|
||||
|
||||
def checkout_confirm_render(self, request):
|
||||
form = self.checkout_form(request)
|
||||
form = self.payment_form(request)
|
||||
template = get_template('pretixplugins/banktransfer/checkout_payment_confirm.html')
|
||||
ctx = {'request': request, 'form': form, 'settings': self.settings}
|
||||
return template.render(ctx)
|
||||
|
||||
@@ -22,7 +22,7 @@ class Paypal(BasePaymentProvider):
|
||||
|
||||
identifier = 'paypal'
|
||||
verbose_name = _('PayPal')
|
||||
checkout_form_fields = OrderedDict([
|
||||
payment_form_fields = OrderedDict([
|
||||
])
|
||||
|
||||
@property
|
||||
@@ -55,11 +55,11 @@ class Paypal(BasePaymentProvider):
|
||||
client_id=self.settings.get('client_id'),
|
||||
client_secret=self.settings.get('secret'))
|
||||
|
||||
def checkout_is_valid_session(self, request):
|
||||
def payment_is_valid_session(self, request):
|
||||
return (request.session.get('payment_paypal_id', '') != ''
|
||||
and request.session.get('payment_paypal_payer', '') != '')
|
||||
|
||||
def checkout_form_render(self, request) -> str:
|
||||
def payment_form_render(self, request) -> str:
|
||||
template = get_template('pretixplugins/paypal/checkout_payment_form.html')
|
||||
ctx = {'request': request, 'event': self.event, 'settings': self.settings}
|
||||
return template.render(ctx)
|
||||
@@ -135,7 +135,7 @@ class Paypal(BasePaymentProvider):
|
||||
ctx = {'request': request, 'event': self.event, 'settings': self.settings}
|
||||
return template.render(ctx)
|
||||
|
||||
def checkout_perform(self, request, order) -> str:
|
||||
def payment_perform(self, request, order) -> str:
|
||||
"""
|
||||
Will be called if the user submitted his order successfully to initiate the
|
||||
payment process.
|
||||
|
||||
@@ -3,7 +3,6 @@ import json
|
||||
import logging
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template.loader import get_template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django import forms
|
||||
@@ -43,9 +42,12 @@ class Stripe(BasePaymentProvider):
|
||||
build_absolute_uri('plugins:stripe:webhook')
|
||||
)
|
||||
|
||||
def checkout_is_valid_session(self, request):
|
||||
def payment_is_valid_session(self, request):
|
||||
return request.session.get('payment_stripe_token') != ''
|
||||
|
||||
def retry_prepare(self, request, order):
|
||||
return self.checkout_prepare(request, None)
|
||||
|
||||
def checkout_prepare(self, request, cart):
|
||||
token = request.POST.get('stripe_token', '')
|
||||
request.session['payment_stripe_token'] = token
|
||||
@@ -56,7 +58,7 @@ class Stripe(BasePaymentProvider):
|
||||
return False
|
||||
return True
|
||||
|
||||
def checkout_form_render(self, request) -> str:
|
||||
def payment_form_render(self, request) -> str:
|
||||
template = get_template('pretixplugins/stripe/checkout_payment_form.html')
|
||||
ctx = {'request': request, 'event': self.event, 'settings': self.settings}
|
||||
return template.render(ctx)
|
||||
@@ -70,7 +72,10 @@ class Stripe(BasePaymentProvider):
|
||||
ctx = {'request': request, 'event': self.event, 'settings': self.settings}
|
||||
return template.render(ctx)
|
||||
|
||||
def checkout_perform(self, request, order) -> str:
|
||||
def order_can_retry(self, order):
|
||||
return True
|
||||
|
||||
def payment_perform(self, request, order) -> str:
|
||||
self._init_api()
|
||||
try:
|
||||
charge = stripe.Charge.create(
|
||||
@@ -82,23 +87,31 @@ class Stripe(BasePaymentProvider):
|
||||
'event': self.event.identity,
|
||||
'code': order.code
|
||||
},
|
||||
idempotency_key=self.event.identity + order.code # TODO: Use something better
|
||||
# TODO: Is this sufficient?
|
||||
idempotency_key=self.event.identity + order.code + request.session['payment_stripe_token']
|
||||
)
|
||||
except stripe.error.CardError as e:
|
||||
err = e.json_body['error']
|
||||
messages.error(request, _('Stripe reported an error with your card: %s' % err['message']))
|
||||
logger.info('Stripe card error: %s' % str(err))
|
||||
order = order.clone()
|
||||
order.payment_info = json.dumps({
|
||||
'error': True,
|
||||
'message': err['message'],
|
||||
})
|
||||
order.save()
|
||||
except stripe.error.InvalidRequestError or stripe.error.AuthenticationError or stripe.error.APIConnectionError \
|
||||
as e:
|
||||
or stripe.error.StripeError as e:
|
||||
err = e.json_body['error']
|
||||
messages.error(request, _('We had trouble communicating with Stripe. Please try again and get in touch '
|
||||
'with us if this problem persists.'))
|
||||
logger.error('Stripe error: %s' % str(err))
|
||||
except stripe.error.StripeError as e:
|
||||
err = e.json_body['error']
|
||||
messages.error(request, _('We had trouble processing the payment. Please try again and get '
|
||||
'in touch with us if this problem persists.'))
|
||||
logger.error('Stripe error: %s' % str(err))
|
||||
order = order.clone()
|
||||
order.payment_info = json.dumps({
|
||||
'error': True,
|
||||
'message': err['message'],
|
||||
})
|
||||
order.save()
|
||||
else:
|
||||
if charge.status == 'succeeded' and charge.paid:
|
||||
try:
|
||||
@@ -112,11 +125,16 @@ class Stripe(BasePaymentProvider):
|
||||
order = order.clone()
|
||||
order.payment_info = str(charge)
|
||||
order.save()
|
||||
del request.session['payment_stripe_token']
|
||||
|
||||
def order_pending_render(self, request, order) -> str:
|
||||
if order.payment_info:
|
||||
payment_info = json.loads(order.payment_info)
|
||||
else:
|
||||
payment_info = None
|
||||
template = get_template('pretixplugins/stripe/pending.html')
|
||||
ctx = {'request': request, 'event': self.event, 'settings': self.settings,
|
||||
'order': order}
|
||||
'order': order, 'payment_info': payment_info}
|
||||
return template.render(ctx)
|
||||
|
||||
def order_control_render(self, request, order) -> str:
|
||||
|
||||
@@ -11,15 +11,17 @@ from pretix.presale.signals import html_head
|
||||
@receiver(register_payment_providers)
|
||||
def register_payment_provider(sender, **kwargs):
|
||||
from .payment import Stripe
|
||||
|
||||
return Stripe
|
||||
|
||||
|
||||
@receiver(html_head)
|
||||
def html_head_presale(sender, request=None, **kwargs):
|
||||
from .payment import Stripe
|
||||
|
||||
provider = Stripe(sender)
|
||||
url = resolve(request.path_info)
|
||||
if provider.is_enabled and "checkout.payment" in url.url_name:
|
||||
if provider.is_enabled and ("checkout.payment" in url.url_name or "order.pay" in url.url_name):
|
||||
template = get_template('pretixplugins/stripe/presale_head.html')
|
||||
ctx = Context({'event': sender, 'settings': provider.settings})
|
||||
return template.render(ctx)
|
||||
|
||||
@@ -85,7 +85,8 @@ $(function() {
|
||||
.keyup(pretixstripe.validate_cvc)
|
||||
$("#stripe_number").parents("form").submit(
|
||||
function () {
|
||||
if ($("input[name=payment][value=stripe]").prop('checked') && $("#stripe_token").val() == "") {
|
||||
if (($("input[name=payment][value=stripe]").prop('checked') || $("input[name=payment]").length === 0)
|
||||
&& $("#stripe_token").val() == "") {
|
||||
pretixstripe.request();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{% load i18n %}
|
||||
|
||||
<p>{% blocktrans trimmed %}
|
||||
The credit card transaction could not be completed. Please contact us.
|
||||
{% endblocktrans %}</p>
|
||||
The credit card transaction could not be completed for the following reason:
|
||||
{% endblocktrans %}
|
||||
<br />
|
||||
{% if payment_info and payment_info.error %}
|
||||
{{ payment_info.message }}
|
||||
{% else %}
|
||||
{% trans "Unknown reason" %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if can_retry %}
|
||||
<a href="{% url "presale:event.order.pay" organizer=request.event.organizer.slug event=request.event.slug order=order.code %}"
|
||||
class="btn btn-primary pull-right"><i class="fa fa-money"></i> {% trans "Complete payment" %}</a>
|
||||
{% endif %}
|
||||
{{ payment }}
|
||||
<strong>{% blocktrans trimmed with date=order.expires|date:"SHORT_DATE_FORMAT" %}
|
||||
Please complete your payment before {{ date }}
|
||||
{% endblocktrans %}</strong>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
{% extends "pretixpresale/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Cancel order" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% blocktrans trimmed with code=order.code %}
|
||||
Pay order: {{ code }}
|
||||
{% endblocktrans %}
|
||||
</h2>
|
||||
|
||||
<form method="post" class="form-horizontal" href="">
|
||||
{% csrf_token %}
|
||||
<div class="form-horizontal">
|
||||
{{ form }}
|
||||
</div>
|
||||
<div class="row checkout-button-row">
|
||||
<div class="col-md-4">
|
||||
<a class="btn btn-block btn-default btn-lg"
|
||||
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<button class="btn btn-block btn-primary btn-lg" type="submit">
|
||||
{% trans "Continue" %}
|
||||
</button>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,43 @@
|
||||
{% extends "pretixpresale/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Cancel order" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% blocktrans trimmed with code=order.code %}
|
||||
Pay order: {{ code }}
|
||||
{% endblocktrans %}
|
||||
</h2>
|
||||
|
||||
<form method="post" class="form-horizontal" href="">
|
||||
{% csrf_token %}
|
||||
|
||||
<p>{% trans "Please confirm the following payment details." %}</p>
|
||||
<div class="row-fluid">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{{ payment_provider.verbose_name }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ payment }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row checkout-button-row">
|
||||
<div class="col-md-4">
|
||||
<a class="btn btn-block btn-default btn-lg"
|
||||
href="{% url "presale:event.order" event=request.event.slug organizer=request.event.organizer.slug order=order.code %}">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<button class="btn btn-block btn-primary btn-lg" type="submit">
|
||||
{% trans "Pay now" %}
|
||||
</button>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@@ -23,6 +23,10 @@ urlpatterns = [
|
||||
name='event.order.cancel'),
|
||||
url(r'^order/(?P<order>[^/]+)/modify$', pretix.presale.views.order.OrderModify.as_view(),
|
||||
name='event.order.modify'),
|
||||
url(r'^order/(?P<order>[^/]+)/pay$', pretix.presale.views.order.OrderPay.as_view(),
|
||||
name='event.order.pay'),
|
||||
url(r'^order/(?P<order>[^/]+)/pay/confirm$', pretix.presale.views.order.OrderPayDo.as_view(),
|
||||
name='event.order.pay.confirm'),
|
||||
url(r'^order/(?P<order>[^/]+)/download/(?P<output>[^/]+)$', pretix.presale.views.order.OrderDownload.as_view(),
|
||||
name='event.order.download'),
|
||||
url(r'^login$', pretix.presale.views.event.EventLogin.as_view(), name='event.checkout.login'),
|
||||
|
||||
@@ -156,7 +156,7 @@ class PaymentDetails(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin,
|
||||
providers.append({
|
||||
'provider': provider,
|
||||
'fee': fee,
|
||||
'form': provider.checkout_form_render(self.request),
|
||||
'form': provider.payment_form_render(self.request),
|
||||
})
|
||||
return providers
|
||||
|
||||
@@ -220,7 +220,7 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch
|
||||
if 'payment' not in request.session or not self.payment_provider:
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
return redirect(self.get_payment_url())
|
||||
if not self.payment_provider.checkout_is_valid_session(request) or \
|
||||
if not self.payment_provider.payment_is_valid_session(request) or \
|
||||
not self.payment_provider.is_enabled or \
|
||||
not self.payment_provider.is_allowed(request):
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
@@ -259,7 +259,7 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch
|
||||
return redirect(self.get_confirm_url())
|
||||
else:
|
||||
messages.success(request, _('Your order has been placed.'))
|
||||
resp = self.payment_provider.checkout_perform(request, order)
|
||||
resp = self.payment_provider.payment_perform(request, order)
|
||||
return redirect(resp or self.get_order_url(order))
|
||||
|
||||
def get_previous_url(self):
|
||||
|
||||
@@ -13,6 +13,7 @@ from pretix.presale.views.checkout import QuestionsViewMixin
|
||||
|
||||
|
||||
class OrderDetailMixin:
|
||||
|
||||
@cached_property
|
||||
def order(self):
|
||||
try:
|
||||
@@ -24,6 +25,21 @@ class OrderDetailMixin:
|
||||
except Order.DoesNotExist:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def payment_provider(self):
|
||||
responses = register_payment_providers.send(self.request.event)
|
||||
for receiver, response in responses:
|
||||
provider = response(self.request.event)
|
||||
if provider.identifier == self.order.payment_provider:
|
||||
return provider
|
||||
|
||||
def get_order_url(self):
|
||||
return reverse('presale:event.order', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'order': self.order.code,
|
||||
})
|
||||
|
||||
|
||||
class OrderDetails(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin,
|
||||
CartDisplayMixin, TemplateView):
|
||||
@@ -35,14 +51,6 @@ class OrderDetails(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin,
|
||||
return HttpResponseNotFound(_('Unknown order code or order does belong to another user.'))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
@cached_property
|
||||
def payment_provider(self):
|
||||
responses = register_payment_providers.send(self.request.event)
|
||||
for receiver, response in responses:
|
||||
provider = response(self.request.event)
|
||||
if provider.identifier == self.order.payment_provider:
|
||||
return provider
|
||||
|
||||
@cached_property
|
||||
def download_buttons(self):
|
||||
buttons = []
|
||||
@@ -75,11 +83,94 @@ class OrderDetails(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin,
|
||||
)
|
||||
if self.order.status == Order.STATUS_PENDING:
|
||||
ctx['payment'] = self.payment_provider.order_pending_render(self.request, self.order)
|
||||
ctx['can_retry'] = self.payment_provider.order_can_retry(self.order) and self.payment_provider.is_enabled
|
||||
elif self.order.status == Order.STATUS_PAID:
|
||||
ctx['payment'] = self.payment_provider.order_paid_render(self.request, self.order)
|
||||
ctx['can_retry'] = False
|
||||
return ctx
|
||||
|
||||
|
||||
class OrderPay(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, TemplateView):
|
||||
template_name = "pretixpresale/event/order_pay.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
if not self.order:
|
||||
return HttpResponseNotFound(_('Unknown order code or order does belong to another user.'))
|
||||
if not self.payment_provider.order_can_retry(self.order) or not self.payment_provider.is_enabled:
|
||||
messages.error(request, _('The payment for this order cannot be continued.'))
|
||||
return redirect(self.get_order_url())
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
resp = self.payment_provider.retry_prepare(
|
||||
request, self.order
|
||||
)
|
||||
if isinstance(resp, str):
|
||||
return redirect(resp)
|
||||
elif resp is True:
|
||||
return redirect(self.get_confirm_url())
|
||||
else:
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['order'] = self.order
|
||||
ctx['form'] = self.form
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def form(self):
|
||||
return self.payment_provider.payment_form_render(self.request)
|
||||
|
||||
def get_confirm_url(self):
|
||||
return reverse('presale:event.order.pay.confirm', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'order': self.order.code,
|
||||
})
|
||||
|
||||
|
||||
class OrderPayDo(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin, TemplateView):
|
||||
template_name = "pretixpresale/event/order_pay_confirm.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
if not self.order:
|
||||
return HttpResponseNotFound(_('Unknown order code or order does belong to another user.'))
|
||||
if not self.payment_provider.order_can_retry(self.order) or not self.payment_provider.is_enabled:
|
||||
messages.error(request, _('The payment for this order cannot be continued.'))
|
||||
return redirect(self.get_order_url())
|
||||
if not self.payment_provider.payment_is_valid_session(request) or \
|
||||
not self.payment_provider.is_enabled or \
|
||||
not self.payment_provider.is_allowed(request):
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
return redirect(self.get_payment_url())
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
resp = self.payment_provider.payment_perform(request, self.order)
|
||||
return redirect(resp or self.get_order_url())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['order'] = self.order
|
||||
ctx['payment'] = self.payment_provider.checkout_confirm_render(self.request)
|
||||
ctx['payment_provider'] = self.payment_provider
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def form(self):
|
||||
return self.payment_provider.payment_form_render(self.request)
|
||||
|
||||
def get_payment_url(self):
|
||||
return reverse('presale:event.order.pay', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'order': self.order.code,
|
||||
})
|
||||
|
||||
|
||||
class OrderModify(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin,
|
||||
QuestionsViewMixin, TemplateView):
|
||||
template_name = "pretixpresale/event/order_modify.html"
|
||||
@@ -96,12 +187,6 @@ class OrderModify(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin,
|
||||
))
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.kwargs = kwargs
|
||||
if not self.order:
|
||||
return HttpResponseNotFound(_('Unknown order code or order does belong to another user.'))
|
||||
if not self.order.can_modify_answers:
|
||||
return HttpResponseForbidden(_('You cannot modify this order'))
|
||||
failed = not self.save()
|
||||
if failed:
|
||||
messages.error(self.request,
|
||||
@@ -113,13 +198,16 @@ class OrderModify(EventViewMixin, EventLoginRequiredMixin, OrderDetailMixin,
|
||||
order=self.order.code)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.kwargs = kwargs
|
||||
if not self.order:
|
||||
return HttpResponseNotFound(_('Unknown order code or order does belong to another user.'))
|
||||
if not self.order.can_modify_answers:
|
||||
return HttpResponseForbidden(_('You cannot modify this order'))
|
||||
return super().get(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
Reference in New Issue
Block a user