Refs #33 -- Added UI and Stripe support for retrying failed payments

This commit is contained in:
Raphael Michel
2015-06-25 15:49:14 +02:00
parent 224eaeee48
commit f04c43abdc
14 changed files with 287 additions and 57 deletions

View File

@@ -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:

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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>