diff options
author | Michał Ociepka <michal@ociepka.info> | 2015-11-03 18:48:18 +0100 |
---|---|---|
committer | Michał Ociepka <michal@ociepka.info> | 2015-11-10 11:52:08 +0100 |
commit | 77bef1d701cf8bcc7cc5e1839ed3d55e9183c13c (patch) | |
tree | c5fbf9ee2fc5960bb4f098593928cdbabdafb17f | |
parent | e178c0c618857ed4fbb68e2a6606d4c36e58c741 (diff) | |
download | django-payments-taler-77bef1d701cf8bcc7cc5e1839ed3d55e9183c13c.tar.gz django-payments-taler-77bef1d701cf8bcc7cc5e1839ed3d55e9183c13c.tar.bz2 django-payments-taler-77bef1d701cf8bcc7cc5e1839ed3d55e9183c13c.zip |
Add Stripe without modal provider
-rw-r--r-- | payments/forms.py | 4 | ||||
-rw-r--r-- | payments/static/js/payments/stripe.js | 59 | ||||
-rw-r--r-- | payments/stripe/__init__.py | 50 | ||||
-rw-r--r-- | payments/stripe/forms.py | 41 | ||||
-rw-r--r-- | payments/stripe/widgets.py | 13 |
5 files changed, 109 insertions, 58 deletions
diff --git a/payments/forms.py b/payments/forms.py index 0f1bfd5..cb19465 100644 --- a/payments/forms.py +++ b/payments/forms.py @@ -51,8 +51,8 @@ class CreditCardPaymentForm(PaymentForm): ' For American Express the four digits found on the front side.')) def __init__(self, *args, **kwargs): - super(CreditCardPaymentForm, self).__init__( - hidden_inputs=False, *args, **kwargs) + kwargs['hidden_inputs'] = False + super(CreditCardPaymentForm, self).__init__(*args, **kwargs) if hasattr(self, 'VALID_TYPES'): self.fields['number'].valid_types = self.VALID_TYPES diff --git a/payments/static/js/payments/stripe.js b/payments/static/js/payments/stripe.js index ce29e0d..af9d4c2 100644 --- a/payments/static/js/payments/stripe.js +++ b/payments/static/js/payments/stripe.js @@ -1,31 +1,32 @@ -(function() { - - function purchase() { - var stripe_input = document.getElementById('stripe-id'); - stripe_input.value = ''; - - StripeCheckout.open({ - key: stripe_input.getAttribute('data-key'), - address: false, - amount: stripe_input.getAttribute('data-amount'), - currency: stripe_input.getAttribute('data-currency'), - name: stripe_input.getAttribute('data-name'), - description: stripe_input.getAttribute('data-description'), - panelLabel: 'Checkout', - token: function(result) { - stripe_input.value = result.id; - }, - closed: function() { - stripe_input.form.submit(); +document.addEventListener('DOMContentLoaded', function () { + var stripeInput = document.getElementById('id_stripeToken'); + var form = stripeInput.form; + var publishableKey = stripeInput.attributes['data-publishable-key'].value; + Stripe.setPublishableKey(publishableKey); + form.addEventListener('submit', function (e) { + var button = this.querySelector('[type=submit]'); + button.disabled = true; + Stripe.card.createToken({ + name: this.elements['name'].value, + number: this.elements['number'].value, + cvc: this.elements['cvv2'].value, + exp_month: this.elements['expiration_0'].value, + exp_year: this.elements['expiration_1'].value, + address_line1: stripeInput.attributes['data-address-line1'].value, + address_line2: stripeInput.attributes['data-address-line2'].value, + address_city: stripeInput.attributes['data-address-city'].value, + address_state: stripeInput.attributes['data-address-state'].value, + address_zip: stripeInput.attributes['data-address-zip'].value, + address_country: stripeInput.attributes['data-address-country'].value + }, function (status, response) { + if (400 <= status && status <= 500) { + alert(response.error.message); + button.disabled = false; + } else { + stripeInput.value = response.id; + form.submit(); } }); - } - - $ = this.jQuery || this.Zepto || this.ender || this.$; - - if($) { - $(purchase); - } else { - window.onload = purchase; - } -})(); + e.preventDefault(); + }, false); +}, false); diff --git a/payments/stripe/__init__.py b/payments/stripe/__init__.py index 6a60f06..55be5ee 100644 --- a/payments/stripe/__init__.py +++ b/payments/stripe/__init__.py @@ -1,36 +1,60 @@ from __future__ import unicode_literals +from decimal import Decimal -from django.core.exceptions import ImproperlyConfigured +import stripe - -from .forms import PaymentForm -from .. import RedirectNeeded +from .forms import ModalPaymentForm, PaymentForm +from .. import RedirectNeeded, PaymentError from ..core import BasicProvider class StripeProvider(BasicProvider): + form_class = ModalPaymentForm + def __init__(self, public_key, secret_key, image='', name='', **kwargs): + stripe.api_key = secret_key self.secret_key = secret_key self.public_key = public_key self.image = image self.name = name super(StripeProvider, self).__init__(**kwargs) - if not self._capture: - raise ImproperlyConfigured( - 'Stripe does not support pre-authorization.') def get_form(self, payment, data=None): if payment.status == 'waiting': payment.change_status('input') - kwargs = { - 'data': data, - 'payment': payment, - 'provider': self, - 'hidden_inputs': False} - form = PaymentForm(**kwargs) + form = self.form_class( + data=data, payment=payment, provider=self) if form.is_valid(): form.save() raise RedirectNeeded(payment.get_success_url()) return form + + def capture(self, payment, amount=None): + amount = int((amount or payment.total) * 100) + charge = stripe.Charge.retrieve(payment.transaction_id) + try: + charge.capture(amount=amount) + except stripe.InvalidRequestError as e: + payment.change_status('refunded') + raise PaymentError('Payment already refunded') + payment.attrs.capture = stripe.util.json.dumps(charge) + return Decimal(amount) / 100 + + def release(self, payment): + charge = stripe.Charge.retrieve(payment.transaction_id) + charge.refund() + payment.attrs.release = stripe.util.json.dumps(charge) + + def refund(self, payment, amount=None): + amount = int((amount or payment.total) * 100) + charge = stripe.Charge.retrieve(payment.transaction_id) + charge.refund(amount=amount) + payment.attrs.refund = stripe.util.json.dumps(charge) + return Decimal(amount) / 100 + + +class StripeCardProvider(StripeProvider): + + form_class = PaymentForm diff --git a/payments/stripe/forms.py b/payments/stripe/forms.py index 5f4ea42..eaef15d 100644 --- a/payments/stripe/forms.py +++ b/payments/stripe/forms.py @@ -4,24 +4,16 @@ from django import forms from django.utils.translation import ugettext as _ import stripe -from .widgets import StripeWidget +from .widgets import StripeCheckoutWidget, StripeWidget from .. import RedirectNeeded -from ..forms import PaymentForm as BasePaymentForm +from ..forms import PaymentForm as BasePaymentForm, CreditCardPaymentFormWithName from ..models import FRAUD_CHOICES -class PaymentForm(BasePaymentForm): +class StripeFormMixin(object): charge = None - def __init__(self, *args, **kwargs): - super(PaymentForm, self).__init__(*args, **kwargs) - widget = StripeWidget(provider=self.provider, payment=self.payment) - self.fields['stripeToken'] = forms.CharField(widget=widget) - if self.is_bound and not self.data.get('stripeToken'): - self.payment.change_status('rejected') - raise RedirectNeeded(self.payment.get_failure_url()) - def _handle_potentially_fraudulent_charge(self, charge, commit=True): fraud_details = charge['fraud_details'] if fraud_details.get('stripe_report', None) == 'fraudulent': @@ -72,3 +64,30 @@ class PaymentForm(BasePaymentForm): self.payment.transaction_id = self.charge.id self.payment.captured_amount = self.payment.total self.payment.change_status('confirmed') + + +class ModalPaymentForm(StripeFormMixin, BasePaymentForm): + + def __init__(self, *args, **kwargs): + super(StripeFormMixin, self).__init__(hidden_inputs=False, *args, **kwargs) + widget = StripeCheckoutWidget(provider=self.provider, payment=self.payment) + self.fields['stripeToken'] = forms.CharField(widget=widget) + if self.is_bound and not self.data.get('stripeToken'): + self.payment.change_status('rejected') + raise RedirectNeeded(self.payment.get_failure_url()) + + +class PaymentForm(StripeFormMixin, CreditCardPaymentFormWithName): + + stripeToken = forms.CharField(widget=StripeWidget()) + + def __init__(self, *args, **kwargs): + super(PaymentForm, self).__init__(*args, **kwargs) + stripe_attrs = self.fields['stripeToken'].widget.attrs + stripe_attrs['data-publishable-key'] = self.provider.public_key + stripe_attrs['data-address-line1'] = self.payment.billing_address_1 + stripe_attrs['data-address-line2'] = self.payment.billing_address_2 + stripe_attrs['data-address-city'] = self.payment.billing_city + stripe_attrs['data-address-state'] = self.payment.billing_country_area + stripe_attrs['data-address-zip'] = self.payment.billing_postcode + stripe_attrs['data-address-country'] = self.payment.billing_country_code diff --git a/payments/stripe/widgets.py b/payments/stripe/widgets.py index e7d5071..bc7fd44 100644 --- a/payments/stripe/widgets.py +++ b/payments/stripe/widgets.py @@ -4,13 +4,13 @@ try: from django.forms.utils import flatatt except ImportError: from django.forms.util import flatatt -from django.forms.widgets import Input +from django.forms.widgets import Input, HiddenInput from django.utils.html import format_html from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ -class StripeWidget(Input): +class StripeCheckoutWidget(Input): is_hidden = True def __init__(self, provider, payment, *args, **kwargs): @@ -26,7 +26,7 @@ class StripeWidget(Input): 'data-currency': payment.currency } kwargs['attrs'].update(attrs) - super(StripeWidget, self).__init__(*args, **kwargs) + super(StripeCheckoutWidget, self).__init__(*args, **kwargs) def render(self, name, value, attrs=None): if value is None: @@ -38,3 +38,10 @@ class StripeWidget(Input): # Only add the 'value' attribute if a value is non-empty. final_attrs['value'] = force_text(self._format_value(value)) return format_html('<script{0}></script>', flatatt(final_attrs)) + + +class StripeWidget(HiddenInput): + + class Media: + js = ['https://js.stripe.com/v2/', + 'js/payments/stripe.js'] |