text: #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  from calendar import monthrange
  from datetime import date
  
  from django.db import models
  from django import forms
  from django.utils.translation import ugettext as _
  
  from paypal.pro.creditcard import verify_credit_card
  
  
  class CreditCardField(forms.CharField):
      """Form field for checking out a credit card."""
      def __init__(self, *args, **kwargs):
          kwargs.setdefault('max_length', 20)
          super(CreditCardField, self).__init__(*args, **kwargs)
          
      def clean(self, value):
          """Raises a ValidationError if the card is not valid and stashes card type."""
          if value:
              value = value.replace('-', '').replace(' ', '')
              self.card_type = verify_credit_card(value)
              if self.card_type is None:
                  raise forms.ValidationError("Invalid credit card number.")
          return value
  
  
  # Credit Card Expiry Fields from:
  # http://www.djangosnippets.org/snippets/907/
  class CreditCardExpiryWidget(forms.MultiWidget):
      """MultiWidget for representing credit card expiry date."""
      def decompress(self, value):
          if isinstance(value, date):
              return [value.month, value.year]
          elif isinstance(value, basestring):
              return [value[0:2], value[2:]]
          else:
              return [None, None]
  
      def format_output(self, rendered_widgets):
          html = u' / '.join(rendered_widgets)
          return u'<span style="white-space: nowrap">%s</span>' % html
  
  class CreditCardExpiryField(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(CreditCardExpiryField, self).__init__(fields, *args, **kwargs)
          self.widget = CreditCardExpiryWidget(widgets=[fields[0].widget, fields[1].widget])
  
      def clean(self, value):
          exp = super(CreditCardExpiryField, 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 CreditCardCVV2Field(forms.CharField):
      def __init__(self, *args, **kwargs):
          kwargs.setdefault('max_length', 4)
          super(CreditCardCVV2Field, self).__init__(*args, **kwargs)
          
  
  # Country Field from:
  # http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.htm
  # From revision on 2011‑11‑08 
  COUNTRIES = (
      ('US', _('United States')),
      ('CA', _('Canada')),
      ('AF', _('Afghanistan')),
      ('AX', _('Aland Islands')),
      ('AL', _('Albania')),
      ('DZ', _('Algeria')),
      ('AS', _('American Samoa')),
      ('AD', _('Andorra')),
      ('AO', _('Angola')),
      ('AI', _('Anguilla')),
      ('AQ', _('Antarctica')),
      ('AG', _('Antigua and Barbuda')),
      ('AR', _('Argentina')),
      ('AM', _('Armenia')),
      ('AW', _('Aruba')),
      ('AU', _('Australia')),
      ('AT', _('Austria')),
      ('AZ', _('Azerbaijan')),
      ('BS', _('Bahamas')),
      ('BH', _('Bahrain')),
      ('BD', _('Bangladesh')),
      ('BB', _('Barbados')),
      ('BY', _('Belarus')),
      ('BE', _('Belgium')),
      ('BZ', _('Belize')),
      ('BJ', _('Benin')),
      ('BM', _('Bermuda')),
      ('BT', _('Bhutan')),
      ('BO', _('Bolivia, Plurinational State of')),
      ('BQ', _('Bonaire, Sint Eustatius and Saba')),
      ('BA', _('Bosnia and Herzegovina')),
      ('BW', _('Botswana')),
      ('BV', _('Bouvet Island')),
      ('BR', _('Brazil')),
      ('IO', _('British Indian Ocean Territory')),
      ('BN', _('Brunei Darussalam')),
      ('BG', _('Bulgaria')),
      ('BF', _('Burkina Faso')),
      ('BI', _('Burundi')),
      ('KH', _('Cambodia')),
      ('CM', _('Cameroon')),
      ('CV', _('Cape Verde')),
      ('KY', _('Cayman Islands')),
      ('CF', _('Central African Republic')),
      ('TD', _('Chad')),
      ('CL', _('Chile')),
      ('CN', _('China')),
      ('CX', _('Christmas Island')),
      ('CC', _('Cocos (Keeling) Islands')),
      ('CO', _('Colombia')),
      ('KM', _('Comoros')),
      ('CG', _('Congo')),
      ('CD', _('Congo, the Democratic Republic of the')),
      ('CK', _('Cook Islands')),
      ('CR', _('Costa Rica')),
      ('CI', _('Cote D\'ivoire')),
      ('HR', _('Croatia')),
      ('CU', _('Cuba')),
      ('CW', _('Curacao')),
      ('CY', _('Cyprus')),
      ('CZ', _('Czech Republic')),
      ('DK', _('Denmark')),
      ('DJ', _('Djibouti')),
      ('DM', _('Dominica')),
      ('DO', _('Dominican Republic')),
      ('EC', _('Ecuador')),
      ('EG', _('Egypt')),
      ('SV', _('El Salvador')),
      ('GQ', _('Equatorial Guinea')),
      ('ER', _('Eritrea')),
      ('EE', _('Estonia')),
      ('ET', _('Ethiopia')),
      ('FK', _('Falkland Islands (Malvinas)')),
      ('FO', _('Faroe Islands')),
      ('FJ', _('Fiji')),
      ('FI', _('Finland')),
      ('FR', _('France')),
      ('GF', _('French Guiana')),
      ('PF', _('French Polynesia')),
      ('TF', _('French Southern Territories')),
      ('GA', _('Gabon')),
      ('GM', _('Gambia')),
      ('GE', _('Georgia')),
      ('DE', _('Germany')),
      ('GH', _('Ghana')),
      ('GI', _('Gibraltar')),
      ('GR', _('Greece')),
      ('GL', _('Greenland')),
      ('GD', _('Grenada')),
      ('GP', _('Guadeloupe')),
      ('GU', _('Guam')),
      ('GT', _('Guatemala')),
      ('GG', _('Guernsey')),
      ('GN', _('Guinea')),
      ('GW', _('Guinea-Bissau')),
      ('GY', _('Guyana')),
      ('HT', _('Haiti')),
      ('HM', _('Heard Island and Mcdonald Islands')),
      ('VA', _('Holy See (Vatican City State)')),
      ('HN', _('Honduras')),
      ('HK', _('Hong Kong')),
      ('HU', _('Hungary')),
      ('IS', _('Iceland')),
      ('IN', _('India')),
      ('ID', _('Indonesia')),
      ('IR', _('Iran, Islamic Republic of')),
      ('IQ', _('Iraq')),
      ('IE', _('Ireland')),
      ('IM', _('Isle of Man')),
      ('IL', _('Israel')),
      ('IT', _('Italy')),
      ('JM', _('Jamaica')),
      ('JP', _('Japan')),
      ('JE', _('Jersey')),
      ('JO', _('Jordan')),
      ('KZ', _('Kazakhstan')),
      ('KE', _('Kenya')),
      ('KI', _('Kiribati')),
      ('KP', _('Korea, Democratic People\'s Republic of')),
      ('KR', _('Korea, Republic of')),
      ('KW', _('Kuwait')),
      ('KG', _('Kyrgyzstan')),
      ('LA', _('Lao People\'s Democratic Republic')),
      ('LV', _('Latvia')),
      ('LB', _('Lebanon')),
      ('LS', _('Lesotho')),
      ('LR', _('Liberia')),
      ('LY', _('Libya')),
      ('LI', _('Liechtenstein')),
      ('LT', _('Lithuania')),
      ('LU', _('Luxembourg')),
      ('MO', _('Macao')),
      ('MK', _('Macedonia, the Former Yugoslav Republic of')),
      ('MG', _('Madagascar')),
      ('MW', _('Malawi')),
      ('MY', _('Malaysia')),
      ('MV', _('Maldives')),
      ('ML', _('Mali')),
      ('MT', _('Malta')),
      ('MH', _('Marshall Islands')),
      ('MQ', _('Martinique')),
      ('MR', _('Mauritania')),
      ('MU', _('Mauritius')),
      ('YT', _('Mayotte')),
      ('MX', _('Mexico')),
      ('FM', _('Micronesia, Federated States of')),
      ('MD', _('Moldova, Republic of')),
      ('MC', _('Monaco')),
      ('MN', _('Mongolia')),
      ('ME', _('Montenegro')),
      ('MS', _('Montserrat')),
      ('MA', _('Morocco')),
      ('MZ', _('Mozambique')),
      ('MM', _('Myanmar')),
      ('NA', _('Namibia')),
      ('NR', _('Nauru')),
      ('NP', _('Nepal')),
      ('NL', _('Netherlands')),
      ('NC', _('New Caledonia')),
      ('NZ', _('New Zealand')),
      ('NI', _('Nicaragua')),
      ('NE', _('Niger')),
      ('NG', _('Nigeria')),
      ('NU', _('Niue')),
      ('NF', _('Norfolk Island')),
      ('MP', _('Northern Mariana Islands')),
      ('NO', _('Norway')),
      ('OM', _('Oman')),
      ('PK', _('Pakistan')),
      ('PW', _('Palau')),
      ('PS', _('Palestinian Territory, Occupied')),
      ('PA', _('Panama')),
      ('PG', _('Papua New Guinea')),
      ('PY', _('Paraguay')),
      ('PE', _('Peru')),
      ('PH', _('Philippines')),
      ('PN', _('Pitcairn')),
      ('PL', _('Poland')),
      ('PT', _('Portugal')),
      ('PR', _('Puerto Rico')),
      ('QA', _('Qatar')),
      ('RE', _('Reunion')),
      ('RO', _('Romania')),
      ('RU', _('Russian Federation')),
      ('RW', _('Rwanda')),
      ('BL', _('Saint Barthelemy')),
      ('SH', _('Saint Helena, Ascension and Tristan Da Cunha')),
      ('KN', _('Saint Kitts and Nevis')),
      ('LC', _('Saint Lucia')),
      ('MF', _('Saint Martin (French Part)')),
      ('PM', _('Saint Pierre and Miquelon')),
      ('VC', _('Saint Vincent and the Grenadines')),
      ('WS', _('Samoa')),
      ('SM', _('San Marino')),
      ('ST', _('Sao Tome and Principe')),
      ('SA', _('Saudi Arabia')),
      ('SN', _('Senegal')),
      ('RS', _('Serbia')),
      ('SC', _('Seychelles')),
      ('SL', _('Sierra Leone')),
      ('SG', _('Singapore')),
      ('SX', _('Sint Maarten (Dutch Part)')),
      ('SK', _('Slovakia')),
      ('SI', _('Slovenia')),
      ('SB', _('Solomon Islands')),
      ('SO', _('Somalia')),
      ('ZA', _('South Africa')),
      ('GS', _('South Georgia and the South Sandwich Islands')),
      ('SS', _('South Sudan')),
      ('ES', _('Spain')),
      ('LK', _('Sri Lanka')),
      ('SD', _('Sudan')),
      ('SR', _('Suriname')),
      ('SJ', _('Svalbard and Jan Mayen')),
      ('SZ', _('Swaziland')),
      ('SE', _('Sweden')),
      ('CH', _('Switzerland')),
      ('SY', _('Syrian Arab Republic')),
      ('TW', _('Taiwan, Province of China')),
      ('TJ', _('Tajikistan')),
      ('TZ', _('Tanzania, United Republic of')),
      ('TH', _('Thailand')),
      ('TL', _('Timor-Leste')),
      ('TG', _('Togo')),
      ('TK', _('Tokelau')),
      ('TO', _('Tonga')),
      ('TT', _('Trinidad and Tobago')),
      ('TN', _('Tunisia')),
      ('TR', _('Turkey')),
      ('TM', _('Turkmenistan')),
      ('TC', _('Turks and Caicos Islands')),
      ('TV', _('Tuvalu')),
      ('UG', _('Uganda')),
      ('UA', _('Ukraine')),
      ('AE', _('United Arab Emirates')),
      ('GB', _('United Kingdom')),
      ('UM', _('United States Minor Outlying Islands')),
      ('UY', _('Uruguay')),
      ('UZ', _('Uzbekistan')),
      ('VU', _('Vanuatu')),
      ('VE', _('Venezuela, Bolivarian Republic of')),
      ('VN', _('Viet Nam')),
      ('VG', _('Virgin Islands, British')),
      ('VI', _('Virgin Islands, U.S.')),
      ('WF', _('Wallis and Futuna')),
      ('EH', _('Western Sahara')),
      ('YE', _('Yemen')),
      ('ZM', _('Zambia')),
      ('ZW', _('Zimbabwe')),
      ('ZZ', _('Unknown or Unspecified Country')),
  )
  
  class CountryField(forms.ChoiceField):
      def __init__(self, *args, **kwargs):
          kwargs.setdefault('choices', COUNTRIES)
          super(CountryField, self).__init__(*args, **kwargs)