1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 | from datetime import date, datetime
from calendar import monthrange
class CreditCardField(forms.IntegerField):
@staticmethod
def get_cc_type(number):
"""
Gets credit card type given number. Based on values from Wikipedia page
"Credit card number".
http://en.wikipedia.org/w/index.php?title=Credit_card_number
"""
number = str(number)
#group checking by ascending length of number
if len(number) == 13:
if number[0] == "4":
return "Visa"
elif len(number) == 14:
if number[:2] == "36":
return "MasterCard"
elif len(number) == 15:
if number[:2] in ("34", "37"):
return "American Express"
elif len(number) == 16:
if number[:4] == "6011":
return "Discover"
if number[:2] in ("51", "52", "53", "54", "55"):
return "MasterCard"
if number[0] == "4":
return "Visa"
return "Unknown"
def clean(self, value):
"""Check if given CC number is valid and one of the
card types we accept"""
if value and (len(value) < 13 or len(value) > 16):
raise forms.ValidationError("Please enter in a valid "+\
"credit card number.")
elif self.get_cc_type(value) not in ("Visa", "MasterCard",
"American Express"):
raise forms.ValidationError("Please enter in a Visa, "+\
"Master Card, or American Express credit card number.")
return super(CreditCardField, self).clean(value)
class CCExpWidget(forms.MultiWidget):
""" Widget containing two select boxes for selecting the month and year"""
def decompress(self, value):
return [value.month, value.year] if value else [None, None]
def format_output(self, rendered_widgets):
html = u' / '.join(rendered_widgets)
return u'<span style="white-space: nowrap">%s</span>' % html
class CCExpField(forms.MultiValueField):
EXP_MONTH = [(x, x) for x in xrange(1, 13)]
EXP_YEAR = [(x, x) for x in xrange(date.today().year,
date.today().year + 15)]
default_error_messages = {
'invalid_month': u'Enter a valid month.',
'invalid_year': u'Enter a valid year.',
}
def __init__(self, *args, **kwargs):
errors = self.default_error_messages.copy()
if 'error_messages' in kwargs:
errors.update(kwargs['error_messages'])
fields = (
forms.ChoiceField(choices=self.EXP_MONTH,
error_messages={'invalid': errors['invalid_month']}),
forms.ChoiceField(choices=self.EXP_YEAR,
error_messages={'invalid': errors['invalid_year']}),
)
super(CCExpField, self).__init__(fields, *args, **kwargs)
self.widget = CCExpWidget(widgets =
[fields[0].widget, fields[1].widget])
def clean(self, value):
exp = super(CCExpField, self).clean(value)
if date.today() > exp:
raise forms.ValidationError(
"The expiration date you entered is in the past.")
return exp
def compress(self, data_list):
if data_list:
if data_list[1] in forms.fields.EMPTY_VALUES:
error = self.error_messages['invalid_year']
raise forms.ValidationError(error)
if data_list[0] in forms.fields.EMPTY_VALUES:
error = self.error_messages['invalid_month']
raise forms.ValidationError(error)
year = int(data_list[1])
month = int(data_list[0])
# find last day of the month
day = monthrange(year, month)[1]
return date(year, month, day)
return None
class PaymentForm(forms.Form):
number = CreditCardField(required = True, label = "Card Number")
holder = forms.CharField(required = True, label = "Card Holder Name",
max_length = 60)
expiration = CCExpField(required = True, label = "Expiration")
ccv_number = forms.IntegerField(required = True, label = "CCV Number",
max_value = 9999, widget = forms.TextInput(attrs={'size': '4'}))
def __init__(self, *args, **kwargs):
self.payment_data = kwargs.pop('payment_data', None)
super(PaymentForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned = super(PaymentForm, self).clean()
if not self.errors:
result = self.process_payment()
if result and result[0] == 'Card declined':
raise forms.ValidationError('Your credit card was declined.')
elif result and result[0] == 'Processing error':
raise forms.ValidationError(
'We encountered the following error while processing '+\
'your credit card: '+result[1])
return cleaned
def process_payment(self):
if self.payment_data:
# don't process payment if payment_data wasn't set
datadict = self.cleaned_data
datadict.update(self.payment_data)
from virtualmerchant import VirtualMerchant
vmerchant = VirtualMerchant(datadict)
return vmerchant.process_virtualmerchant_payment()
|
Comments