PageRenderTime 145ms CodeModel.GetById 113ms app.highlight 11ms RepoModel.GetById 19ms app.codeStats 0ms

/django/contrib/localflavor/ch/forms.py

https://code.google.com/p/mango-py/
Python | 118 lines | 108 code | 5 blank | 5 comment | 4 complexity | 495e93873445ba38fdedf3bf7cf706c2 MD5 | raw file
  1"""
  2Swiss-specific Form helpers
  3"""
  4
  5from django.core.validators import EMPTY_VALUES
  6from django.forms import ValidationError
  7from django.forms.fields import Field, RegexField, Select
  8from django.utils.encoding import smart_unicode
  9from django.utils.translation import ugettext_lazy as _
 10import re
 11
 12id_re = re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$")
 13phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
 14
 15class CHZipCodeField(RegexField):
 16    default_error_messages = {
 17        'invalid': _('Enter a zip code in the format XXXX.'),
 18    }
 19
 20    def __init__(self, *args, **kwargs):
 21        super(CHZipCodeField, self).__init__(r'^\d{4}$',
 22        max_length=None, min_length=None, *args, **kwargs)
 23
 24class CHPhoneNumberField(Field):
 25    """
 26    Validate local Swiss phone number (not international ones)
 27    The correct format is '0XX XXX XX XX'.
 28    '0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
 29    '0XX XXX XX XX'.
 30    """
 31    default_error_messages = {
 32        'invalid': 'Phone numbers must be in 0XX XXX XX XX format.',
 33    }
 34
 35    def clean(self, value):
 36        super(CHPhoneNumberField, self).clean(value)
 37        if value in EMPTY_VALUES:
 38            return u''
 39        value = re.sub('(\.|\s|/|-)', '', smart_unicode(value))
 40        m = phone_digits_re.search(value)
 41        if m:
 42            return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
 43        raise ValidationError(self.error_messages['invalid'])
 44
 45class CHStateSelect(Select):
 46    """
 47    A Select widget that uses a list of CH states as its choices.
 48    """
 49    def __init__(self, attrs=None):
 50        from ch_states import STATE_CHOICES # relative import
 51        super(CHStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
 52
 53class CHIdentityCardNumberField(Field):
 54    """
 55    A Swiss identity card number.
 56
 57    Checks the following rules to determine whether the number is valid:
 58
 59        * Conforms to the X1234567<0 or 1234567890 format.
 60        * Included checksums match calculated checksums
 61
 62    """
 63    default_error_messages = {
 64        'invalid': _('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.'),
 65    }
 66
 67    def has_valid_checksum(self, number):
 68        given_number, given_checksum = number[:-1], number[-1]
 69        new_number = given_number
 70        calculated_checksum = 0
 71        fragment = ""
 72        parameter = 7
 73
 74        first = str(number[:1])
 75        if first.isalpha():
 76            num = ord(first.upper()) - 65
 77            if num < 0 or num > 8:
 78                return False
 79            new_number = str(num) + new_number[1:]
 80            new_number = new_number[:8] + '0'
 81
 82        if not new_number.isdigit():
 83            return False
 84
 85        for i in range(len(new_number)):
 86          fragment = int(new_number[i])*parameter
 87          calculated_checksum += fragment
 88
 89          if parameter == 1:
 90            parameter = 7
 91          elif parameter == 3:
 92            parameter = 1
 93          elif parameter ==7:
 94            parameter = 3
 95
 96        return str(calculated_checksum)[-1] == given_checksum
 97
 98    def clean(self, value):
 99        super(CHIdentityCardNumberField, self).clean(value)
100        if value in EMPTY_VALUES:
101            return u''
102
103        match = re.match(id_re, value)
104        if not match:
105            raise ValidationError(self.error_messages['invalid'])
106
107        idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum']
108
109        if idnumber == '00000000' or \
110           idnumber == 'A0000000':
111            raise ValidationError(self.error_messages['invalid'])
112
113        all_digits = "%s%s%s" % (idnumber, pos9, checksum)
114        if not self.has_valid_checksum(all_digits):
115            raise ValidationError(self.error_messages['invalid'])
116
117        return u'%s%s%s' % (idnumber, pos9, checksum)
118