Code

Ticket #3866: more_it_fields_3.diff

File more_it_fields_3.diff, 7.3 KB (added by Massimiliano Ravelli <massimiliano.ravelli@…>, 7 years ago)

ITFiscalCodeField renamed to ITSocialSecurityNumberField

Line 
1Index: django/contrib/localflavor/it/util.py
2===================================================================
3--- django/contrib/localflavor/it/util.py       (revision 0)
4+++ django/contrib/localflavor/it/util.py       (revision 0)
5@@ -0,0 +1,40 @@
6+def ssn_check_digit(value):
7+    """ Calculate italian social security number check digit. """
8+    ssn_even_chars = {
9+        '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
10+        'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9,
11+        'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18,
12+        'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25
13+    }
14+    ssn_odd_chars = {
15+        '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 19, '9': 21,
16+        'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 'H': 17, 'I': 19, 'J': 21,
17+        'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 'P': 3, 'Q': 6, 'R': 8, 'S': 12,
18+        'T': 14, 'U': 16, 'V': 10, 'W': 22, 'X': 25, 'Y': 24, 'Z': 23
19+    }
20+    # Chars from 'A' to 'Z'
21+    ssn_check_digits = [chr(x) for x in range(65, 91)]
22+
23+    ssn = value.upper()
24+    total = 0
25+    for i in range(0,15):
26+        try:
27+            if i % 2 == 0:
28+                total += ssn_odd_chars[ssn[i]]
29+            else:
30+                total += ssn_even_chars[ssn[i]]
31+        except KeyError:
32+            msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]}
33+            raise ValueError(msg)
34+    return ssn_check_digits[total % 26]
35+
36+def vat_number_check_digit(vat_number):
37+    """ Calculate italian vat number check digit. """
38+    normalized_vat_number = str(vat_number).zfill(10)
39+    total = 0
40+    for i in range(0, 10, 2):
41+        total += int(normalized_vat_number[i])
42+    for i in range(1, 11, 2):
43+        quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10)
44+        total += quotient + remainder
45+    return str((10 - total % 10) % 10)
46Index: django/contrib/localflavor/it/forms.py
47===================================================================
48--- django/contrib/localflavor/it/forms.py      (revision 5007)
49+++ django/contrib/localflavor/it/forms.py      (working copy)
50@@ -5,6 +5,8 @@
51 from django.newforms import ValidationError
52 from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
53 from django.utils.translation import gettext
54+from django.utils.encoding import smart_unicode
55+from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit
56 import re
57 
58 class ITZipCodeField(RegexField):
59@@ -29,3 +31,48 @@
60     def __init__(self, attrs=None):
61         from it_province import PROVINCE_CHOICES # relative import
62         super(ITProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
63+
64+class ITSocialSecurityNumberField(RegexField):
65+    """
66+    A form field  that validates it's input in Italian Social Security number
67+    (codice fiscale).
68+    For reference see http://www.agenziaentrate.it/ and search for
69+    'Informazioni sulla codificazione delle persone fisiche'.
70+    """
71+    err_msg = gettext(u'Enter a valid Social Security number.')
72+    def __init__(self, *args, **kwargs):
73+        super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
74+        max_length=None, min_length=None, error_message=self.err_msg,
75+        *args, **kwargs)
76+
77+    def clean(self, value):
78+        value = super(ITSocialSecurityNumberField, self).clean(value)
79+        if value == u'':
80+            return value
81+        value = re.sub('\s', u'', value).upper()
82+        try:
83+            check_digit = ssn_check_digit(value)
84+        except ValueError:
85+            raise ValidationError(self.err_msg)
86+        if not value[15] == check_digit:
87+            raise ValidationError(self.err_msg)
88+        return value
89+
90+class ITVatNumberField(Field):
91+    """
92+    A form field  that validates it's input in Italian VAT number (partita IVA).
93+    """
94+    def clean(self, value):
95+        value = super(ITVatNumberField, self).clean(value)
96+        if value == u'':
97+            return value
98+        err_msg = gettext(u'Enter a valid VAT number.')
99+        try:
100+            vat_number = int(value)
101+        except ValueError:
102+            raise ValidationError(err_msg)
103+        vat_number = str(vat_number).zfill(11)
104+        check_digit = vat_number_check_digit(vat_number[0:10])
105+        if not vat_number[10] == check_digit:
106+            raise ValidationError(err_msg)
107+        return smart_unicode(vat_number)
108Index: tests/regressiontests/forms/localflavor.py
109===================================================================
110--- tests/regressiontests/forms/localflavor.py  (revision 5010)
111+++ tests/regressiontests/forms/localflavor.py  (working copy)
112@@ -642,6 +642,46 @@
113 >>> w.render('regions', 'PMN')
114 u'<select name="regions">\n<option value="ABR">Abruzzo</option>\n<option value="BAS">Basilicata</option>\n<option value="CAL">Calabria</option>\n<option value="CAM">Campania</option>\n<option value="EMR">Emilia-Romagna</option>\n<option value="FVG">Friuli-Venezia Giulia</option>\n<option value="LAZ">Lazio</option>\n<option value="LIG">Liguria</option>\n<option value="LOM">Lombardia</option>\n<option value="MAR">Marche</option>\n<option value="MOL">Molise</option>\n<option value="PMN" selected="selected">Piemonte</option>\n<option value="PUG">Puglia</option>\n<option value="SAR">Sardegna</option>\n<option value="SIC">Sicilia</option>\n<option value="TOS">Toscana</option>\n<option value="TAA">Trentino-Alto Adige</option>\n<option value="UMB">Umbria</option>\n<option value="VAO">Valle d\u2019Aosta</option>\n<option value="VEN">Veneto</option>\n</select>'
115 
116+# ITSocialSecurityNumberField #################################################
117+
118+>>> from django.contrib.localflavor.it.forms import ITSocialSecurityNumberField
119+>>> f = ITSocialSecurityNumberField()
120+>>> f.clean('LVSGDU99T71H501L')
121+u'LVSGDU99T71H501L'
122+>>> f.clean('LBRRME11A01L736W')
123+u'LBRRME11A01L736W'
124+>>> f.clean('lbrrme11a01l736w')
125+u'LBRRME11A01L736W'
126+>>> f.clean('LBR RME 11A01 L736W')
127+u'LBRRME11A01L736W'
128+>>> f.clean('LBRRME11A01L736A')
129+Traceback (most recent call last):
130+...
131+ValidationError: [u'Enter a valid Social Security number.']
132+>>> f.clean('%BRRME11A01L736W')
133+Traceback (most recent call last):
134+...
135+ValidationError: [u'Enter a valid Social Security number.']
136+
137+# ITVatNumberField ###########################################################
138+
139+>>> from django.contrib.localflavor.it.forms import ITVatNumberField
140+>>> f = ITVatNumberField()
141+>>> f.clean('07973780013')
142+u'07973780013'
143+>>> f.clean('7973780013')
144+u'07973780013'
145+>>> f.clean(7973780013)
146+u'07973780013'
147+>>> f.clean('07973780014')
148+Traceback (most recent call last):
149+...
150+ValidationError: [u'Enter a valid VAT number.']
151+>>> f.clean('A7973780013')
152+Traceback (most recent call last):
153+...
154+ValidationError: [u'Enter a valid VAT number.']
155+
156 # FIZipCodeField #############################################################
157 
158 FIZipCodeField validates that the data is a valid FI zipcode.
159Index: AUTHORS
160===================================================================
161--- AUTHORS     (revision 5007)
162+++ AUTHORS     (working copy)
163@@ -174,6 +174,7 @@
164     J. Rademaker
165     Michael Radziej <mir@noris.de>
166     ramiro
167+    Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
168     Brian Ray <http://brianray.chipy.org/>
169     remco@diji.biz
170     rhettg@gmail.com