Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3866 -- Added Italian Social Security and VAT input fields to …

…localflavor. Thanks, Massimiliano Ravelli.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5018 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e9b66ce1d3b6964fb05874c3f86541b54c1f1adf 1 parent c5f0895
Russell Keith-Magee authored April 17, 2007
1  AUTHORS
@@ -174,6 +174,7 @@ answer newbie questions, and generally made Django that much better:
174 174
     J. Rademaker
175 175
     Michael Radziej <mir@noris.de>
176 176
     ramiro
  177
+    Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
177 178
     Brian Ray <http://brianray.chipy.org/>
178 179
     remco@diji.biz
179 180
     rhettg@gmail.com
48  django/contrib/localflavor/it/forms.py
@@ -5,13 +5,15 @@
5 5
 from django.newforms import ValidationError
6 6
 from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
7 7
 from django.utils.translation import gettext
  8
+from django.utils.encoding import smart_unicode
  9
+from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit
8 10
 import re
9 11
 
10 12
 class ITZipCodeField(RegexField):
11 13
     def __init__(self, *args, **kwargs):
12 14
         super(ITZipCodeField, self).__init__(r'^\d{5}$',
13 15
         max_length=None, min_length=None,
14  
-        error_message=gettext(u'Enter a zip code in the format XXXXX.'),
  16
+        error_message=gettext(u'Enter a valid zip code.'),
15 17
         *args, **kwargs)
16 18
 
17 19
 class ITRegionSelect(Select):
@@ -29,3 +31,47 @@ class ITProvinceSelect(Select):
29 31
     def __init__(self, attrs=None):
30 32
         from it_province import PROVINCE_CHOICES # relative import
31 33
         super(ITProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
  34
+
  35
+class ITSocialSecurityNumberField(RegexField):
  36
+    """
  37
+    A form field that validates Italian Social Security numbers (codice fiscale).
  38
+    For reference see http://www.agenziaentrate.it/ and search for
  39
+    'Informazioni sulla codificazione delle persone fisiche'.
  40
+    """
  41
+    err_msg = gettext(u'Enter a valid Social Security number.')
  42
+    def __init__(self, *args, **kwargs):
  43
+        super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
  44
+        max_length=None, min_length=None, error_message=self.err_msg,
  45
+        *args, **kwargs)
  46
+
  47
+    def clean(self, value):
  48
+        value = super(ITSocialSecurityNumberField, self).clean(value)
  49
+        if value == u'':
  50
+            return value
  51
+        value = re.sub('\s', u'', value).upper()
  52
+        try:
  53
+            check_digit = ssn_check_digit(value)
  54
+        except ValueError:
  55
+            raise ValidationError(self.err_msg)
  56
+        if not value[15] == check_digit:
  57
+            raise ValidationError(self.err_msg)
  58
+        return value
  59
+
  60
+class ITVatNumberField(Field):
  61
+    """
  62
+    A form field that validates Italian VAT numbers (partita IVA).
  63
+    """
  64
+    def clean(self, value):
  65
+        value = super(ITVatNumberField, self).clean(value)
  66
+        if value == u'':
  67
+            return value
  68
+        err_msg = gettext(u'Enter a valid VAT number.')
  69
+        try:
  70
+            vat_number = int(value)
  71
+        except ValueError:
  72
+            raise ValidationError(err_msg)
  73
+        vat_number = str(vat_number).zfill(11)
  74
+        check_digit = vat_number_check_digit(vat_number[0:10])
  75
+        if not vat_number[10] == check_digit:
  76
+            raise ValidationError(err_msg)
  77
+        return smart_unicode(vat_number)
40  django/contrib/localflavor/it/util.py
... ...
@@ -0,0 +1,40 @@
  1
+def ssn_check_digit(value):
  2
+    "Calculate Italian social security number check digit."
  3
+    ssn_even_chars = {
  4
+        '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
  5
+        'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9,
  6
+        'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18,
  7
+        'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25
  8
+    }
  9
+    ssn_odd_chars = {
  10
+        '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 19, '9': 21,
  11
+        'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 'H': 17, 'I': 19, 'J': 21,
  12
+        'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 'P': 3, 'Q': 6, 'R': 8, 'S': 12,
  13
+        'T': 14, 'U': 16, 'V': 10, 'W': 22, 'X': 25, 'Y': 24, 'Z': 23
  14
+    }
  15
+    # Chars from 'A' to 'Z'
  16
+    ssn_check_digits = [chr(x) for x in range(65, 91)]
  17
+
  18
+    ssn = value.upper()
  19
+    total = 0
  20
+    for i in range(0,15):
  21
+        try:
  22
+            if i % 2 == 0:
  23
+                total += ssn_odd_chars[ssn[i]]
  24
+            else:
  25
+                total += ssn_even_chars[ssn[i]]
  26
+        except KeyError:
  27
+            msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]}
  28
+            raise ValueError(msg)
  29
+    return ssn_check_digits[total % 26]
  30
+
  31
+def vat_number_check_digit(vat_number):
  32
+    "Calculate Italian VAT number check digit."
  33
+    normalized_vat_number = str(vat_number).zfill(10)
  34
+    total = 0
  35
+    for i in range(0, 10, 2):
  36
+        total += int(normalized_vat_number[i])
  37
+    for i in range(1, 11, 2):
  38
+        quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10)
  39
+        total += quotient + remainder
  40
+    return str((10 - total % 10) % 10)
42  tests/regressiontests/forms/localflavor.py
@@ -633,7 +633,7 @@
633 633
 >>> f.clean(' 00100')
634 634
 Traceback (most recent call last):
635 635
 ...
636  
-ValidationError: [u'Enter a zip code in the format XXXXX.']
  636
+ValidationError: [u'Enter a valid zip code.']
637 637
 
638 638
 # ITRegionSelect #############################################################
639 639
 
@@ -642,6 +642,46 @@
642 642
 >>> w.render('regions', 'PMN')
643 643
 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>'
644 644
 
  645
+# ITSocialSecurityNumberField #################################################
  646
+
  647
+>>> from django.contrib.localflavor.it.forms import ITSocialSecurityNumberField
  648
+>>> f = ITSocialSecurityNumberField()
  649
+>>> f.clean('LVSGDU99T71H501L')
  650
+u'LVSGDU99T71H501L'
  651
+>>> f.clean('LBRRME11A01L736W')
  652
+u'LBRRME11A01L736W'
  653
+>>> f.clean('lbrrme11a01l736w')
  654
+u'LBRRME11A01L736W'
  655
+>>> f.clean('LBR RME 11A01 L736W')
  656
+u'LBRRME11A01L736W'
  657
+>>> f.clean('LBRRME11A01L736A')
  658
+Traceback (most recent call last):
  659
+...
  660
+ValidationError: [u'Enter a valid Social Security number.']
  661
+>>> f.clean('%BRRME11A01L736W')
  662
+Traceback (most recent call last):
  663
+...
  664
+ValidationError: [u'Enter a valid Social Security number.']
  665
+
  666
+# ITVatNumberField ###########################################################
  667
+
  668
+>>> from django.contrib.localflavor.it.forms import ITVatNumberField
  669
+>>> f = ITVatNumberField()
  670
+>>> f.clean('07973780013')
  671
+u'07973780013'
  672
+>>> f.clean('7973780013')
  673
+u'07973780013'
  674
+>>> f.clean(7973780013)
  675
+u'07973780013'
  676
+>>> f.clean('07973780014')
  677
+Traceback (most recent call last):
  678
+...
  679
+ValidationError: [u'Enter a valid VAT number.']
  680
+>>> f.clean('A7973780013')
  681
+Traceback (most recent call last):
  682
+...
  683
+ValidationError: [u'Enter a valid VAT number.']
  684
+
645 685
 # FIZipCodeField #############################################################
646 686
 
647 687
 FIZipCodeField validates that the data is a valid FI zipcode.

0 notes on commit e9b66ce

Please sign in to comment.
Something went wrong with that request. Please try again.