Skip to content

Commit 956fd7d

Browse files
Igor Támarabenkonrath
authored andcommitted
Added verification digit for Colombian NIT.
1 parent 9455830 commit 956fd7d

2 files changed

Lines changed: 86 additions & 0 deletions

File tree

localflavor/co/forms.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
"""Colombian-specific form helpers."""
22

33
from django.forms.fields import Select
4+
from django.forms import ValidationError
5+
from django.forms.fields import RegexField
6+
from django.core.validators import EMPTY_VALUES
7+
from django.utils.translation import ugettext_lazy as _
48

59
from .co_departments import DEPARTMENT_CHOICES
610

@@ -10,3 +14,62 @@ class CODepartmentSelect(Select):
1014

1115
def __init__(self, attrs=None):
1216
super(CODepartmentSelect, self).__init__(attrs, choices=DEPARTMENT_CHOICES)
17+
18+
19+
class RUTField(RegexField):
20+
"""
21+
This field validates a NIT (NUmero de IdentificaciOn Tributaria). A
22+
NIT is of the form XXXXXXXXXX-V. The last digit is a check digit. Applies
23+
to people and companies.
24+
25+
More info:
26+
http://es.wikipedia.org/wiki/N%C3%BAmero_de_Identificaci%C3%B3n_Tributaria
27+
"""
28+
default_error_messages = {
29+
'invalid': _('Enter a valid RUT in XXXXXXXXXXX-Y or XXXXXXXXXXXY format.'),
30+
'checksum': _('Invalid RUT.'),
31+
}
32+
33+
PRIME_PLACES = [3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71]
34+
35+
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
36+
super(RUTField, self).__init__(
37+
r'^\d{5,12}-?\d$',
38+
max_length,
39+
min_length,
40+
*args,
41+
**kwargs
42+
)
43+
44+
def clean(self, value):
45+
"""
46+
Value can be either a string in the format XXXXXXXXXX-Y or
47+
XXXXXXXXXXY.
48+
"""
49+
value = super(RUTField, self).clean(value)
50+
if value in EMPTY_VALUES:
51+
return ''
52+
value, cd = self._canon(value)
53+
if self._calc_cd(value) != cd:
54+
raise ValidationError(self.error_messages['checksum'])
55+
return self._format(value, cd)
56+
57+
def _canon(self, nit):
58+
nit = nit.replace('-', '')
59+
return nit[:-1], nit[-1]
60+
61+
def _calc_cd(self, nit):
62+
# Calculation code based on:
63+
# http://es.wikipedia.org/wiki/N%C3%BAmero_de_Identificaci%C3%B3n_Tributaria
64+
tmp = sum([
65+
self.PRIME_PLACES[idx] * int(value)
66+
for idx, value in enumerate(reversed(nit))
67+
]) % 11
68+
if tmp > 1:
69+
dv = 11 - tmp
70+
else:
71+
dv = 0
72+
return str(dv)
73+
74+
def _format(self, nit, check_digit):
75+
return '{0}-{1}'.format(nit, check_digit)

tests/test_co.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.test import SimpleTestCase
44

55
from localflavor.co.forms import CODepartmentSelect
6+
from localflavor.co.forms import RUTField
67

78

89
class COLocalFlavorTests(SimpleTestCase):
@@ -44,3 +45,25 @@ def test_CODepartmentSelect(self):
4445
<option value="VID">Vichada</option>
4546
</select>"""
4647
self.assertHTMLEqual(d.render('department', 'COR'), out)
48+
49+
def test_ARCUITField(self):
50+
error_format = ['Enter a valid RUT in XXXXXXXXXXX-Y or XXXXXXXXXXXY format.']
51+
error_invalid = ['Invalid RUT.']
52+
valid = {
53+
'37547837-0': '37547837-0',
54+
'900227140-3': '900227140-3',
55+
'79626331-8': '79626331-8',
56+
'375478370': '37547837-0',
57+
'796273731': '79627373-1',
58+
'9002271403': '900227140-3',
59+
}
60+
invalid = {
61+
'2-375478370-9': error_format,
62+
'20-10123456-': error_format,
63+
'3-375478370': error_format,
64+
'375478370-': error_format,
65+
'37547837-5': error_invalid,
66+
'37547837-2': error_invalid,
67+
'9002271401': error_invalid,
68+
}
69+
self.assertFieldOutput(RUTField, valid, invalid)

0 commit comments

Comments
 (0)