| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- from datetime import date, datetime
- from calendar import monthrange
- import re
-
- from django import forms
-
- from oscar.core.loading import import_module
-
- address_models = import_module('address.models', ['Country'])
- order_models = import_module('order.models', ['BillingAddress'])
- payment_models = import_module('payment.models', ['Bankcard'])
-
- VISA, MASTERCARD, AMEX, MAESTRO, DISCOVER = ('Visa', 'Mastercard', 'American Express', 'Maestro', 'Discover')
-
- def bankcard_type(number):
- u"""
- Returns the type of a bankcard based on its number.
- """
- number = str(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 AMEX
- 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 None
-
- def luhn(card_number):
- u"""
- Tests whether a bankcard number passes the Luhn algorithm.
- """
- card_number = str(card_number)
- sum = 0
- num_digits = len(card_number)
- odd_even = num_digits & 1
-
- for i in range(0, num_digits):
- digit = int(card_number[i])
- if not (( i & 1 ) ^ odd_even ):
- digit = digit * 2
- if digit > 9:
- digit = digit - 9
- sum = sum + digit
-
- return (sum % 10) == 0
-
-
- class BankcardNumberField(forms.CharField):
-
- def clean(self, value):
- """Check if given CC number is valid and one of the
- card types we accept"""
- non_decimal = re.compile(r'\D+')
- value = non_decimal.sub('', value.strip())
-
- if value and not luhn(value):
- raise forms.ValidationError("Please enter a valid credit card number.")
- return super(BankcardNumberField, self).clean(value)
-
-
- class BankcardMonthWidget(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 BankcardMonthField(forms.MultiValueField):
- """
- A modified version of the snippet: http://djangosnippets.org/snippets/907/
- """
- 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.month_choices(),
- error_messages={'invalid': errors['invalid_month']}),
- forms.ChoiceField(choices=self.year_choices(),
- error_messages={'invalid': errors['invalid_year']}),
- )
- super(BankcardMonthField, self).__init__(fields, *args, **kwargs)
- self.widget = BankcardMonthWidget(widgets = [fields[0].widget, fields[1].widget])
-
- def month_choices(self):
- return []
-
- def year_choices(self):
- return []
-
-
- class BankcardExpiryMonthField(BankcardMonthField):
- """
- Expiry month
- """
- def month_choices(self):
- return [("%.2d" % x, "%.2d" % x) for x in xrange(1, 13)]
-
- def year_choices(self):
- return [(x, x) for x in xrange( date.today().year, date.today().year+5)]
-
- def clean(self, value):
- expiry_date = super(BankcardExpiryMonthField, self).clean(value)
- if date.today() > expiry_date:
- raise forms.ValidationError("The expiration date you entered is in the past.")
- return expiry_date
-
- 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 BankcardStartingMonthField(BankcardMonthField):
- """
- Starting month
- """
- def month_choices(self):
- months = [("%.2d" % x, "%.2d" % x) for x in xrange(1, 13)]
- months.insert(0, ("", "--"))
- return months
-
- def year_choices(self):
- years = [(x, x) for x in xrange( date.today().year - 5, date.today().year)]
- years.insert(0, ("", "--"))
- return years
-
- def clean(self, value):
- starting_date = super(BankcardMonthField, self).clean(value)
- if starting_date and date.today() < starting_date:
- raise forms.ValidationError("The starting date you entered is in the future.")
- return starting_date
-
- 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])
- return date(year, month, 1)
- return None
-
-
- class BankcardForm(forms.ModelForm):
-
- number = BankcardNumberField(max_length=20, widget=forms.TextInput(attrs={'autocomplete':'off'}), label="Card number")
- name = forms.CharField(max_length=128, label="Name on card")
- ccv_number = forms.IntegerField(required=True, label="CCV Number",
- max_value = 99999, widget=forms.TextInput(attrs={'size': '5'}))
- start_month = BankcardStartingMonthField(label="Valid from", required=False)
- expiry_month = BankcardExpiryMonthField(required=True, label = "Valid to")
-
- class Meta:
- model = payment_models.Bankcard
- exclude = ('user', 'partner_reference')
- fields = ('number', 'name', 'start_month', 'expiry_month', 'ccv_number')
-
-
- class BillingAddressForm(forms.ModelForm):
-
- def __init__(self, *args, **kwargs):
- super(BillingAddressForm,self ).__init__(*args, **kwargs)
- self.set_country_queryset()
-
- def set_country_queryset(self):
- self.fields['country'].queryset = address_models.Country._default_manager.all()
-
- class Meta:
- model = order_models.BillingAddress
-
|