2016-09-21 09:36:57 +00:00
|
|
|
import copy
|
2017-04-17 12:56:21 +00:00
|
|
|
from registripe import models
|
2016-09-21 09:07:10 +00:00
|
|
|
|
2016-09-21 03:16:59 +00:00
|
|
|
from django import forms
|
|
|
|
from django.core.urlresolvers import reverse
|
2016-09-22 01:04:43 +00:00
|
|
|
from django.db.models import F, Q
|
2016-09-21 03:16:59 +00:00
|
|
|
from django.forms import widgets
|
2016-09-21 09:07:10 +00:00
|
|
|
from django.utils import timezone
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
from django_countries import countries
|
|
|
|
from django_countries.fields import LazyTypedChoiceField
|
|
|
|
from django_countries.widgets import CountrySelectWidget
|
|
|
|
|
|
|
|
|
|
|
|
class NoRenderWidget(forms.widgets.HiddenInput):
|
|
|
|
|
|
|
|
def render(self, name, value, attrs=None):
|
|
|
|
return "<!-- no widget: " + name + " -->"
|
|
|
|
|
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
def secure_striped(field):
|
2016-09-21 03:16:59 +00:00
|
|
|
''' Calls stripe() with secure=True. '''
|
2016-09-21 09:36:57 +00:00
|
|
|
return striped(field, True)
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
def striped(field, secure=False):
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
oldwidget = field.widget
|
|
|
|
field.widget = StripeWidgetProxy(oldwidget, secure)
|
|
|
|
return field
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
class StripeWidgetProxy(widgets.Widget):
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
def __init__(self, underlying, secure=False):
|
|
|
|
self.underlying = underlying
|
|
|
|
self.secure = secure
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
def __deepcopy__(self, memo):
|
|
|
|
copy_underlying = copy.deepcopy(self.underlying, memo)
|
2016-09-22 10:30:03 +00:00
|
|
|
return type(self)(copy_underlying, self.secure)
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
def __getattribute__(self, attr):
|
|
|
|
spr = super(StripeWidgetProxy, self).__getattribute__
|
|
|
|
if attr in ("underlying", "render", "secure", "__deepcopy__"):
|
|
|
|
return spr(attr)
|
|
|
|
else:
|
|
|
|
return getattr(self.underlying, attr)
|
|
|
|
|
|
|
|
def render(self, name, value, attrs=None):
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
if not attrs:
|
|
|
|
attrs = {}
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
attrs["data-stripe"] = name
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
if self.secure:
|
|
|
|
name = ""
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
return self.underlying.render(name, value, attrs=attrs)
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CreditCardForm(forms.Form):
|
|
|
|
|
|
|
|
def _media(self):
|
|
|
|
js = (
|
|
|
|
'https://js.stripe.com/v2/',
|
|
|
|
reverse("registripe_pubkey"),
|
|
|
|
)
|
|
|
|
|
|
|
|
return forms.Media(js=js)
|
|
|
|
|
|
|
|
media = property(_media)
|
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
number = secure_striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=False,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Credit card Number",
|
|
|
|
help_text="Your credit card number, with or without spaces.",
|
2016-09-21 03:16:59 +00:00
|
|
|
max_length=255,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
exp_month = secure_striped(forms.IntegerField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=False,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Card expiry month",
|
|
|
|
min_value=1,
|
|
|
|
max_value=12,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
exp_year = secure_striped(forms.IntegerField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=False,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Card expiry year",
|
|
|
|
help_text="The expiry year for your card in 4-digit form",
|
2016-09-22 01:38:12 +00:00
|
|
|
min_value=timezone.now().year,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
cvc = secure_striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=False,
|
2016-09-21 09:07:10 +00:00
|
|
|
min_length=3,
|
2016-09-21 03:16:59 +00:00
|
|
|
max_length=4,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
stripe_token = forms.CharField(
|
|
|
|
max_length=255,
|
2017-04-22 09:06:30 +00:00
|
|
|
# required=True,
|
2016-09-21 03:16:59 +00:00
|
|
|
widget=NoRenderWidget(),
|
|
|
|
)
|
|
|
|
|
2016-09-21 09:36:57 +00:00
|
|
|
name = striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=True,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Cardholder name",
|
|
|
|
help_text="The cardholder's name, as it appears on the credit card",
|
2016-09-21 03:16:59 +00:00
|
|
|
max_length=255,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
address_line1 = striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=True,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Cardholder account address, line 1",
|
2016-09-21 03:16:59 +00:00
|
|
|
max_length=255,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
address_line2 = striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=False,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Cardholder account address, line 2",
|
2016-09-21 03:16:59 +00:00
|
|
|
max_length=255,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
address_city = striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=True,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Cardholder account city",
|
2016-09-21 03:16:59 +00:00
|
|
|
max_length=255,
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
address_state = striped(forms.CharField(
|
2016-09-21 09:07:10 +00:00
|
|
|
required=True,
|
|
|
|
max_length=255,
|
|
|
|
label="Cardholder account state or province",
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
address_zip = striped(forms.CharField(
|
2016-09-21 03:16:59 +00:00
|
|
|
required=True,
|
|
|
|
max_length=255,
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Cardholder account postal code",
|
2016-09-21 09:36:57 +00:00
|
|
|
))
|
|
|
|
address_country = striped(LazyTypedChoiceField(
|
2016-09-21 09:07:10 +00:00
|
|
|
label="Cardholder account country",
|
2016-09-21 03:16:59 +00:00
|
|
|
choices=countries,
|
2016-09-21 09:36:57 +00:00
|
|
|
widget=CountrySelectWidget,
|
|
|
|
))
|
2016-09-22 01:04:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
class StripeRefundForm(forms.Form):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
'''
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
user (User): The user whose charges we should filter to.
|
|
|
|
min_value (Decimal): The minimum value of the charges we should
|
|
|
|
show (currently, credit notes can only be cashed out in full.)
|
|
|
|
|
|
|
|
'''
|
|
|
|
user = kwargs.pop('user', None)
|
|
|
|
min_value = kwargs.pop('min_value', None)
|
|
|
|
super(StripeRefundForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
payment_field = self.fields['payment']
|
|
|
|
qs = payment_field.queryset
|
|
|
|
|
|
|
|
if user:
|
|
|
|
qs = qs.filter(
|
|
|
|
charge__customer__user=user,
|
|
|
|
)
|
|
|
|
|
|
|
|
if min_value is not None:
|
|
|
|
# amount >= amount_to_refund + amount_refunded
|
|
|
|
# No refunds yet
|
|
|
|
q1 = (
|
|
|
|
Q(charge__amount_refunded__isnull=True) &
|
|
|
|
Q(charge__amount__gte=min_value)
|
|
|
|
)
|
|
|
|
# There are some refunds
|
|
|
|
q2 = (
|
|
|
|
Q(charge__amount_refunded__isnull=False) &
|
|
|
|
Q(charge__amount__gte=(
|
2017-04-22 09:06:30 +00:00
|
|
|
F("charge__amount_refunded") + min_value))
|
2016-09-22 01:04:43 +00:00
|
|
|
)
|
|
|
|
qs = qs.filter(q1 | q2)
|
|
|
|
|
|
|
|
payment_field.queryset = qs
|
|
|
|
|
|
|
|
payment = forms.ModelChoiceField(
|
|
|
|
required=True,
|
|
|
|
queryset=models.StripePayment.objects.all(),
|
|
|
|
)
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
'''{
|
|
|
|
From stripe.js details:
|
|
|
|
|
|
|
|
Card details:
|
|
|
|
|
2017-04-22 09:06:30 +00:00
|
|
|
The first argument to createToken is a JavaScript object containing credit
|
|
|
|
card data entered by the user. It should contain the following required
|
|
|
|
members:
|
2016-09-21 03:16:59 +00:00
|
|
|
|
2017-04-22 09:06:30 +00:00
|
|
|
number: card number as a string without any separators
|
|
|
|
(e.g., "4242424242424242")
|
|
|
|
exp_month: two digit number representing the card's expiration month
|
|
|
|
(e.g., 12)
|
|
|
|
exp_year: two or four digit number representing the card's expiration year
|
|
|
|
(e.g., 2017)
|
2016-09-21 03:16:59 +00:00
|
|
|
(The expiration date can also be passed as a single string.)
|
|
|
|
|
2017-04-22 09:06:30 +00:00
|
|
|
cvc: optional, but we highly recommend you provide it to help prevent fraud.
|
|
|
|
This is the card's security code, as a string (e.g., "123").
|
|
|
|
The following fields are entirely optional and cannot result in a token
|
|
|
|
creation failure:
|
2016-09-21 03:16:59 +00:00
|
|
|
|
|
|
|
name: cardholder name
|
|
|
|
address_line1: billing address line 1
|
|
|
|
address_line2: billing address line 2
|
|
|
|
address_city: billing address city
|
|
|
|
address_state: billing address state
|
|
|
|
address_zip: billing postal code as a string (e.g., "94301")
|
|
|
|
address_country: billing address country
|
|
|
|
}
|
|
|
|
'''
|