Stripe: Optional support for Stripe checkout

This commit is contained in:
Raphael Michel
2016-09-09 10:20:30 +02:00
parent e0f0a3a87f
commit 84d264d626
7 changed files with 131 additions and 7 deletions

View File

@@ -155,10 +155,11 @@ class SecurityMiddleware:
resp['X-XSS-Protection'] = '1'
h = {
'default-src': "{static}",
'script-src': '{static} https://js.stripe.com',
'script-src': '{static} https://checkout.stripe.com https://js.stripe.com',
'object-src': "'none'",
'frame-src': '{static} https://js.stripe.com',
'frame-src': '{static} https://checkout.stripe.com https://js.stripe.com',
'style-src': "{static}",
'connect-src': "{dynamic} https://checkout.stripe.com",
'img-src': "{static} data: https://*.stripe.com",
# form-action is not only used to match on form actions, but also on URLs
# form-ations redirect to. In the context of e.g. payment providers or

View File

@@ -32,6 +32,14 @@ class Stripe(BasePaymentProvider):
('publishable_key',
forms.CharField(
label=_('Publishable key'),
)),
('ui',
forms.ChoiceField(
label=_('User interface'),
choices=(
('pretix', _('Simple (pretix design)')),
('checkout', _('Stripe Checkout')),
)
))
]
)
@@ -60,7 +68,11 @@ class Stripe(BasePaymentProvider):
return True
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form.html')
ui = self.settings.get('ui', default='pretix')
if ui == 'checkout':
template = get_template('pretixplugins/stripe/checkout_payment_form_stripe_checkout.html')
else:
template = get_template('pretixplugins/stripe/checkout_payment_form.html')
ctx = {'request': request, 'event': self.event, 'settings': self.settings}
return template.render(ctx)

View File

@@ -0,0 +1,75 @@
/*global $, stripe_pubkey, stripe_loadingmessage, gettext */
'use strict';
var Stripe = null;
var pretixstripe = {
'load': function () {
$.ajax(
{
url: 'https://checkout.stripe.com/checkout.js',
dataType: 'script',
success: function () {
pretixstripe.handler = StripeCheckout.configure({
key: $.trim($("#stripe_pubkey").html()),
locale: 'auto',
token: function(token) {
var $form = $("#stripe-checkout").parents("form");
$("#stripe_token").val(token.id);
$("#stripe_card_brand").val(token.card.brand);
$("#stripe_card_last4").val(token.card.last4);
$form.get(0).submit();
},
shippingAddress: false,
allowRememberMe: false,
billingAddress: false
});
}
}
);
},
handler: null
};
$(function () {
if (!$("#stripe-checkout").length) { // Not on the checkout page
return;
}
if ($("input[name=payment][value=stripe]").is(':checked') || $(".payment-redo-form").length) {
pretixstripe.load();
} else {
$("input[name=payment]").change(function() {
if ($(this).val() == 'stripe') {
pretixstripe.load();
}
})
}
$(".checkout-button-row .btn-primary").click(
function (e) {
if (($("input[name=payment][value=stripe]").prop('checked') || $("input[name=payment]").length === 0)
&& $("#stripe_token").val() == "") {
var amount = Math.round(
parseFloat(
$("#stripe-checkout").parents("[data-total]").attr("data-total").replace(",", ".")
) * 100
);
pretixstripe.handler.open({
name: $("#organizer_name").val(),
description: $("#event_name").val(),
currency: $("#stripe_currency").val(),
email: $("#stripe_email").val(),
amount: amount,
});
e.preventDefault();
return false;
}
}
);
$(window).on('popstate', function () {
if (pretixstripe.handler) {
pretixstripe.handler.close();
}
});
});

View File

@@ -0,0 +1,29 @@
{% load i18n %}
<div class="form-horizontal" id="stripe-checkout">
<noscript>
<div class="alert alert-warning">
{% trans "For a credit card payment, please turn on JavaScript." %}
</div>
</noscript>
<p>
{% blocktrans trimmed %}
Please continue below to start the credit card payment.
{% endblocktrans %}
</p>
<p>
<em>{% blocktrans trimmed %}
Your payment will be processed by Stripe, Inc. Your credit card data will be transmitted directly to
Stripe and never touches our servers.
{% endblocktrans %}</em>
</p>
<input type="hidden" name="stripe_token" value="" id="stripe_token" />
<input type="hidden" name="stripe_card_last4" value="" id="stripe_card_last4" />
<input type="hidden" name="stripe_card_brand" value="" id="stripe_card_brand" />
<input type="hidden" id="organizer_name" value="{{ event.organizer.name }}" />
<input type="hidden" id="event_name" value="{{ event.name }}" />
<input type="hidden" id="stripe_currency" value="{{ event.currency }}" />
<input type="hidden" id="event_name" value="{{ event.name }}" />
<input type="hidden" id="stripe_email" value="{{ request.session.email }}" />
</div>

View File

@@ -2,8 +2,14 @@
{% load compress %}
{% load i18n %}
{% compress js %}
<script type="text/javascript" src="{% static "pretixplugins/stripe/pretix-stripe.js" %}"></script>
{% endcompress %}
{% if settings.ui == "checkout" %}
{% compress js %}
<script type="text/javascript" src="{% static "pretixplugins/stripe/pretix-stripe-checkout.js" %}"></script>
{% endcompress %}
{% else %}
{% compress js %}
<script type="text/javascript" src="{% static "pretixplugins/stripe/pretix-stripe.js" %}"></script>
{% endcompress %}
{% endif %}
<script type="text/plain" id="stripe_pubkey">{{ settings.publishable_key }}</script>

View File

@@ -234,6 +234,7 @@ class PaymentStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
providers.append({
'provider': provider,
'fee': fee,
'total': self._total_order_value + fee,
'form': provider.payment_form_render(self.request)
})
return providers

View File

@@ -9,7 +9,7 @@
{% csrf_token %}
<div class="panel-group" id="payment_accordion">
{% for p in providers %}
<div class="panel panel-default">
<div class="panel panel-default" data-total="{{ p.total|floatformat:2 }}">
<div class="panel-heading">
<h4 class="panel-title">
<label class="radio">