Django

Code

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

Revision 7971, 3.8 kB (checked in by jacob, 3 months ago)

Fixed #7741: django.newforms is now django.forms. This is obviously a backwards-incompatible change. There's a warning upon import of django.newforms itself, but deeper imports will raise errors.

  • Property svn:eol-style set to native
Line 
1 """
2 Swiss-specific Form helpers
3 """
4
5 from django.forms import ValidationError
6 from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
7 from django.utils.encoding import smart_unicode
8 from django.utils.translation import ugettext_lazy as _
9 import re
10
11 id_re = re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$")
12 phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
13
14 class CHZipCodeField(RegexField):
15     default_error_messages = {
16         'invalid': _('Enter a zip code in the format XXXX.'),
17     }
18
19     def __init__(self, *args, **kwargs):
20         super(CHZipCodeField, self).__init__(r'^\d{4}$',
21         max_length=None, min_length=None, *args, **kwargs)
22
23 class CHPhoneNumberField(Field):
24     """
25     Validate local Swiss phone number (not international ones)
26     The correct format is '0XX XXX XX XX'.
27     '0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
28     '0XX XXX XX XX'.
29     """
30     default_error_messages = {
31         'invalid': 'Phone numbers must be in 0XX XXX XX XX format.',
32     }
33
34     def clean(self, value):
35         super(CHPhoneNumberField, self).clean(value)
36         if value in EMPTY_VALUES:
37             return u''
38         value = re.sub('(\.|\s|/|-)', '', smart_unicode(value))
39         m = phone_digits_re.search(value)
40         if m:
41             return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
42         raise ValidationError(self.error_messages['invalid'])
43
44 class CHStateSelect(Select):
45     """
46     A Select widget that uses a list of CH states as its choices.
47     """
48     def __init__(self, attrs=None):
49         from ch_states import STATE_CHOICES # relative import
50         super(CHStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
51
52 class CHIdentityCardNumberField(Field):
53     """
54     A Swiss identity card number.
55
56     Checks the following rules to determine whether the number is valid:
57
58         * Conforms to the X1234567<0 or 1234567890 format.
59         * Included checksums match calculated checksums
60
61     Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
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)
Note: See TracBrowser for help on using the browser.