1 # -*- coding: utf-8 -*- |
1 # -*- coding: utf-8 -*- |
2 """ |
2 """ |
3 Spanish-specific Form helpers |
3 Spanish-specific Form helpers |
4 """ |
4 """ |
5 |
5 |
6 from django.newforms import ValidationError |
6 from django.forms import ValidationError |
7 from django.newforms.fields import RegexField, Select, EMPTY_VALUES |
7 from django.forms.fields import RegexField, Select, EMPTY_VALUES |
8 from django.utils.translation import ugettext as _ |
8 from django.utils.translation import ugettext_lazy as _ |
9 import re |
9 import re |
10 |
10 |
11 class ESPostalCodeField(RegexField): |
11 class ESPostalCodeField(RegexField): |
12 """ |
12 """ |
13 A form field that validates its input as a spanish postal code. |
13 A form field that validates its input as a spanish postal code. |
74 self.only_nif = only_nif |
74 self.only_nif = only_nif |
75 self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE' |
75 self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE' |
76 self.cif_control = 'JABCDEFGHI' |
76 self.cif_control = 'JABCDEFGHI' |
77 self.cif_types = 'ABCDEFGHKLMNPQS' |
77 self.cif_types = 'ABCDEFGHKLMNPQS' |
78 self.nie_types = 'XT' |
78 self.nie_types = 'XT' |
79 super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()), |
79 id_card_re = re.compile(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types, self.nif_control + self.cif_control), re.IGNORECASE) |
80 max_length=None, min_length=None, |
80 super(ESIdentityCardNumberField, self).__init__(id_card_re, max_length=None, min_length=None, |
81 error_message=self.default_error_messages['invalid%s' % (self.only_nif and '_only_nif' or '')], |
81 error_message=self.default_error_messages['invalid%s' % (self.only_nif and '_only_nif' or '')], |
82 *args, **kwargs) |
82 *args, **kwargs) |
83 |
83 |
84 def clean(self, value): |
84 def clean(self, value): |
85 super(ESIdentityCardNumberField, self).clean(value) |
85 super(ESIdentityCardNumberField, self).clean(value) |
86 if value in EMPTY_VALUES: |
86 if value in EMPTY_VALUES: |
87 return u'' |
87 return u'' |
88 nif_get_checksum = lambda d: self.nif_control[int(d)%23] |
88 nif_get_checksum = lambda d: self.nif_control[int(d)%23] |
89 |
89 |
90 value = value.upper().replace(' ', '').replace('-', '') |
90 value = value.upper().replace(' ', '').replace('-', '') |
91 m = re.match(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types, self.nif_control), value) |
91 m = re.match(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types, self.nif_control + self.cif_control), value) |
92 letter1, number, letter2 = m.groups() |
92 letter1, number, letter2 = m.groups() |
93 |
93 |
94 if not letter1 and letter2: |
94 if not letter1 and letter2: |
95 # NIF |
95 # NIF |
96 if letter2 == nif_get_checksum(number): |
96 if letter2 == nif_get_checksum(number): |
106 elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]: |
106 elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]: |
107 # CIF |
107 # CIF |
108 if not letter2: |
108 if not letter2: |
109 number, letter2 = number[:-1], int(number[-1]) |
109 number, letter2 = number[:-1], int(number[-1]) |
110 checksum = cif_get_checksum(number) |
110 checksum = cif_get_checksum(number) |
111 if letter2 in [checksum, self.cif_control[checksum]]: |
111 if letter2 in (checksum, self.cif_control[checksum]): |
112 return value |
112 return value |
113 else: |
113 else: |
114 raise ValidationError, self.error_messages['invalid_cif'] |
114 raise ValidationError, self.error_messages['invalid_cif'] |
115 else: |
115 else: |
116 raise ValidationError, self.error_messages['invalid'] |
116 raise ValidationError, self.error_messages['invalid'] |
178 |
178 |
179 |
179 |
180 def cif_get_checksum(number): |
180 def cif_get_checksum(number): |
181 s1 = sum([int(digit) for pos, digit in enumerate(number) if int(pos) % 2]) |
181 s1 = sum([int(digit) for pos, digit in enumerate(number) if int(pos) % 2]) |
182 s2 = sum([sum([int(unit) for unit in str(int(digit) * 2)]) for pos, digit in enumerate(number) if not int(pos) % 2]) |
182 s2 = sum([sum([int(unit) for unit in str(int(digit) * 2)]) for pos, digit in enumerate(number) if not int(pos) % 2]) |
183 return 10 - ((s1 + s2) % 10) |
183 return (10 - ((s1 + s2) % 10)) % 10 |
184 |
184 |