|
1 """ |
|
2 Norwegian-specific Form helpers |
|
3 """ |
|
4 |
|
5 import re, datetime |
|
6 from django.newforms import ValidationError |
|
7 from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES |
|
8 from django.utils.translation import ugettext |
|
9 |
|
10 class NOZipCodeField(RegexField): |
|
11 default_error_messages = { |
|
12 'invalid': ugettext('Enter a zip code in the format XXXX.'), |
|
13 } |
|
14 |
|
15 def __init__(self, *args, **kwargs): |
|
16 super(NOZipCodeField, self).__init__(r'^\d{4}$', |
|
17 max_length=None, min_length=None, *args, **kwargs) |
|
18 |
|
19 class NOMunicipalitySelect(Select): |
|
20 """ |
|
21 A Select widget that uses a list of Norwegian municipalities (fylker) |
|
22 as its choices. |
|
23 """ |
|
24 def __init__(self, attrs=None): |
|
25 from no_municipalities import MUNICIPALITY_CHOICES |
|
26 super(NOMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES) |
|
27 |
|
28 class NOSocialSecurityNumber(Field): |
|
29 """ |
|
30 Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer |
|
31 """ |
|
32 default_error_messages = { |
|
33 'invalid': ugettext(u'Enter a valid Norwegian social security number.'), |
|
34 } |
|
35 |
|
36 def clean(self, value): |
|
37 super(NOSocialSecurityNumber, self).clean(value) |
|
38 if value in EMPTY_VALUES: |
|
39 return u'' |
|
40 |
|
41 if not re.match(r'^\d{11}$', value): |
|
42 raise ValidationError(self.error_messages['invalid']) |
|
43 |
|
44 day = int(value[:2]) |
|
45 month = int(value[2:4]) |
|
46 year2 = int(value[4:6]) |
|
47 |
|
48 inum = int(value[6:9]) |
|
49 self.birthday = None |
|
50 try: |
|
51 if 000 <= inum < 500: |
|
52 self.birthday = datetime.date(1900+year2, month, day) |
|
53 if 500 <= inum < 750 and year2 > 54: |
|
54 self.birthday = datetime.date(1800+year2, month, day) |
|
55 if 500 <= inum < 1000 and year2 < 40: |
|
56 self.birthday = datetime.date(2000+year2, month, day) |
|
57 if 900 <= inum < 1000 and year2 > 39: |
|
58 self.birthday = datetime.date(1900+year2, month, day) |
|
59 except ValueError: |
|
60 raise ValidationError(self.error_messages['invalid']) |
|
61 |
|
62 sexnum = int(value[8]) |
|
63 if sexnum % 2 == 0: |
|
64 self.gender = 'F' |
|
65 else: |
|
66 self.gender = 'M' |
|
67 |
|
68 digits = map(int, list(value)) |
|
69 weight_1 = [3, 7, 6, 1, 8, 9, 4, 5, 2, 1, 0] |
|
70 weight_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1] |
|
71 |
|
72 def multiply_reduce(aval, bval): |
|
73 return sum([(a * b) for (a, b) in zip(aval, bval)]) |
|
74 |
|
75 if multiply_reduce(digits, weight_1) % 11 != 0: |
|
76 raise ValidationError(self.error_messages['invalid']) |
|
77 if multiply_reduce(digits, weight_2) % 11 != 0: |
|
78 raise ValidationError(self.error_messages['invalid']) |
|
79 |
|
80 return value |
|
81 |