Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #4122 -- Added Chilean localflavor. Thanks, marijn@metronomo.cl.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5087 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit ed60b8645f36b32949b9ed30a8323b49417f7bef 1 parent f85f1d0
Malcolm Tredinnick authored April 26, 2007
1  AUTHORS
@@ -150,6 +150,7 @@ answer newbie questions, and generally made Django that much better:
150 150
     Manuzhai
151 151
     Petar Marić <http://www.petarmaric.com/>
152 152
     Nuno Mariz <nmariz@gmail.com>
  153
+    marijn@metronomo.cl
153 154
     mark@junklight.com
154 155
     Yasushi Masuda <whosaysni@gmail.com>
155 156
     mattycakes@gmail.com
77  django/contrib/localflavor/cl/forms.py
... ...
@@ -0,0 +1,77 @@
  1
+"""
  2
+Chile specific form helpers.
  3
+"""
  4
+from django.newforms import ValidationError
  5
+from django.newforms.fields import RegexField, EMPTY_VALUES
  6
+from django.utils.translation import gettext
  7
+
  8
+class CLRutField(RegexField):
  9
+    """
  10
+    Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national
  11
+    identification number.
  12
+
  13
+    Samples for testing are available from
  14
+    https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
  15
+    """
  16
+    def __init__(self, *args, **kwargs):
  17
+        if 'strict' in kwargs:
  18
+            del kwargs['strict']
  19
+            super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
  20
+                error_message=gettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'),
  21
+                *args, **kwargs)
  22
+        else:
  23
+            # In non-strict mode, accept RUTs that validate but do not exist in
  24
+            # the real world.
  25
+            super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=gettext(u'Enter valid a Chilean RUT'), *args, **kwargs)
  26
+
  27
+    def clean(self, value):
  28
+        """
  29
+        Check and clean the chilean rut.
  30
+        """
  31
+        super(CLRutField, self).clean(value)
  32
+        if value in EMPTY_VALUES:
  33
+            return u''
  34
+        rut, verificador = self._canonify(value)
  35
+        if self._algorithm(rut) == verificador:
  36
+            return self._format(rut, verificador)
  37
+        else:
  38
+            raise ValidationError(u'The Chilean RUT is not valid.')
  39
+
  40
+    def _algorithm(self, rut):
  41
+        """
  42
+        Takes RUT in pure canonical form, calculates the verifier digit.
  43
+        """
  44
+        suma  = 0
  45
+        multi = 2
  46
+        for r in rut[::-1]:
  47
+            suma  += int(r) * multi
  48
+            multi += 1
  49
+            if multi == 8:
  50
+                multi = 2
  51
+        return '0123456789K0'[11 - suma % 11]
  52
+
  53
+    def _canonify(self, rut):
  54
+        """
  55
+        Turns the RUT into one normalized format. Returns a (rut, verifier)
  56
+        tuple.
  57
+        """
  58
+        rut = str(rut).replace(' ', '').replace('.', '').replace('-', '')
  59
+        return rut[:-1], rut[-1]
  60
+
  61
+    def _format(self, code, verifier=None):
  62
+        """
  63
+        Formats the RUT from canonical form to the common string representation.
  64
+        If verifier=None, then the last digit in 'code' is the verifier.
  65
+        """
  66
+        if verifier is None:
  67
+            verifier = code[-1]
  68
+            code = code[:-1]
  69
+        while len(code) > 3 and '.' not in code[:3]:
  70
+            pos = code.find('.')
  71
+            if pos == -1:
  72
+                new_dot = -3
  73
+            else:
  74
+                new_dot = pos - 3
  75
+            code = code[:new_dot] + '.' + code[new_dot:]
  76
+        return '%s-%s' % (code, verifier)
  77
+
0  localflavor/cl/__init__.py b/django/contrib/localflavor/cl/__init__.py
No changes.
64  tests/regressiontests/forms/localflavor.py
@@ -1150,4 +1150,68 @@
1150 1150
 
1151 1151
 >>> f.render('foo', 'bar')
1152 1152
 u'<select name="foo">\n<option value="101">101 Reykjav\xedk</option>\n<option value="103">103 Reykjav\xedk</option>\n<option value="104">104 Reykjav\xedk</option>\n<option value="105">105 Reykjav\xedk</option>\n<option value="107">107 Reykjav\xedk</option>\n<option value="108">108 Reykjav\xedk</option>\n<option value="109">109 Reykjav\xedk</option>\n<option value="110">110 Reykjav\xedk</option>\n<option value="111">111 Reykjav\xedk</option>\n<option value="112">112 Reykjav\xedk</option>\n<option value="113">113 Reykjav\xedk</option>\n<option value="116">116 Kjalarnes</option>\n<option value="121">121 Reykjav\xedk</option>\n<option value="123">123 Reykjav\xedk</option>\n<option value="124">124 Reykjav\xedk</option>\n<option value="125">125 Reykjav\xedk</option>\n<option value="127">127 Reykjav\xedk</option>\n<option value="128">128 Reykjav\xedk</option>\n<option value="129">129 Reykjav\xedk</option>\n<option value="130">130 Reykjav\xedk</option>\n<option value="132">132 Reykjav\xedk</option>\n<option value="150">150 Reykjav\xedk</option>\n<option value="155">155 Reykjav\xedk</option>\n<option value="170">170 Seltjarnarnes</option>\n<option value="172">172 Seltjarnarnes</option>\n<option value="190">190 Vogar</option>\n<option value="200">200 K\xf3pavogur</option>\n<option value="201">201 K\xf3pavogur</option>\n<option value="202">202 K\xf3pavogur</option>\n<option value="203">203 K\xf3pavogur</option>\n<option value="210">210 Gar\xf0ab\xe6r</option>\n<option value="212">212 Gar\xf0ab\xe6r</option>\n<option value="220">220 Hafnarfj\xf6r\xf0ur</option>\n<option value="221">221 Hafnarfj\xf6r\xf0ur</option>\n<option value="222">222 Hafnarfj\xf6r\xf0ur</option>\n<option value="225">225 \xc1lftanes</option>\n<option value="230">230 Reykjanesb\xe6r</option>\n<option value="232">232 Reykjanesb\xe6r</option>\n<option value="233">233 Reykjanesb\xe6r</option>\n<option value="235">235 Keflav\xedkurflugv\xf6llur</option>\n<option value="240">240 Grindav\xedk</option>\n<option value="245">245 Sandger\xf0i</option>\n<option value="250">250 Gar\xf0ur</option>\n<option value="260">260 Reykjanesb\xe6r</option>\n<option value="270">270 Mosfellsb\xe6r</option>\n<option value="300">300 Akranes</option>\n<option value="301">301 Akranes</option>\n<option value="302">302 Akranes</option>\n<option value="310">310 Borgarnes</option>\n<option value="311">311 Borgarnes</option>\n<option value="320">320 Reykholt \xed Borgarfir\xf0i</option>\n<option value="340">340 Stykkish\xf3lmur</option>\n<option value="345">345 Flatey \xe1 Brei\xf0afir\xf0i</option>\n<option value="350">350 Grundarfj\xf6r\xf0ur</option>\n<option value="355">355 \xd3lafsv\xedk</option>\n<option value="356">356 Sn\xe6fellsb\xe6r</option>\n<option value="360">360 Hellissandur</option>\n<option value="370">370 B\xfa\xf0ardalur</option>\n<option value="371">371 B\xfa\xf0ardalur</option>\n<option value="380">380 Reykh\xf3lahreppur</option>\n<option value="400">400 \xcdsafj\xf6r\xf0ur</option>\n<option value="401">401 \xcdsafj\xf6r\xf0ur</option>\n<option value="410">410 Hn\xedfsdalur</option>\n<option value="415">415 Bolungarv\xedk</option>\n<option value="420">420 S\xfa\xf0av\xedk</option>\n<option value="425">425 Flateyri</option>\n<option value="430">430 Su\xf0ureyri</option>\n<option value="450">450 Patreksfj\xf6r\xf0ur</option>\n<option value="451">451 Patreksfj\xf6r\xf0ur</option>\n<option value="460">460 T\xe1lknafj\xf6r\xf0ur</option>\n<option value="465">465 B\xedldudalur</option>\n<option value="470">470 \xdeingeyri</option>\n<option value="471">471 \xdeingeyri</option>\n<option value="500">500 Sta\xf0ur</option>\n<option value="510">510 H\xf3lmav\xedk</option>\n<option value="512">512 H\xf3lmav\xedk</option>\n<option value="520">520 Drangsnes</option>\n<option value="522">522 Kj\xf6rvogur</option>\n<option value="523">523 B\xe6r</option>\n<option value="524">524 Nor\xf0urfj\xf6r\xf0ur</option>\n<option value="530">530 Hvammstangi</option>\n<option value="531">531 Hvammstangi</option>\n<option value="540">540 Bl\xf6ndu\xf3s</option>\n<option value="541">541 Bl\xf6ndu\xf3s</option>\n<option value="545">545 Skagastr\xf6nd</option>\n<option value="550">550 Sau\xf0\xe1rkr\xf3kur</option>\n<option value="551">551 Sau\xf0\xe1rkr\xf3kur</option>\n<option value="560">560 Varmahl\xed\xf0</option>\n<option value="565">565 Hofs\xf3s</option>\n<option value="566">566 Hofs\xf3s</option>\n<option value="570">570 Flj\xf3t</option>\n<option value="580">580 Siglufj\xf6r\xf0ur</option>\n<option value="600">600 Akureyri</option>\n<option value="601">601 Akureyri</option>\n<option value="602">602 Akureyri</option>\n<option value="603">603 Akureyri</option>\n<option value="610">610 Greniv\xedk</option>\n<option value="611">611 Gr\xedmsey</option>\n<option value="620">620 Dalv\xedk</option>\n<option value="621">621 Dalv\xedk</option>\n<option value="625">625 \xd3lafsfj\xf6r\xf0ur</option>\n<option value="630">630 Hr\xedsey</option>\n<option value="640">640 H\xfasav\xedk</option>\n<option value="641">641 H\xfasav\xedk</option>\n<option value="645">645 Fossh\xf3ll</option>\n<option value="650">650 Laugar</option>\n<option value="660">660 M\xfdvatn</option>\n<option value="670">670 K\xf3pasker</option>\n<option value="671">671 K\xf3pasker</option>\n<option value="675">675 Raufarh\xf6fn</option>\n<option value="680">680 \xde\xf3rsh\xf6fn</option>\n<option value="681">681 \xde\xf3rsh\xf6fn</option>\n<option value="685">685 Bakkafj\xf6r\xf0ur</option>\n<option value="690">690 Vopnafj\xf6r\xf0ur</option>\n<option value="700">700 Egilssta\xf0ir</option>\n<option value="701">701 Egilssta\xf0ir</option>\n<option value="710">710 Sey\xf0isfj\xf6r\xf0ur</option>\n<option value="715">715 Mj\xf3ifj\xf6r\xf0ur</option>\n<option value="720">720 Borgarfj\xf6r\xf0ur eystri</option>\n<option value="730">730 Rey\xf0arfj\xf6r\xf0ur</option>\n<option value="735">735 Eskifj\xf6r\xf0ur</option>\n<option value="740">740 Neskaupsta\xf0ur</option>\n<option value="750">750 F\xe1skr\xfa\xf0sfj\xf6r\xf0ur</option>\n<option value="755">755 St\xf6\xf0varfj\xf6r\xf0ur</option>\n<option value="760">760 Brei\xf0dalsv\xedk</option>\n<option value="765">765 Dj\xfapivogur</option>\n<option value="780">780 H\xf6fn \xed Hornafir\xf0i</option>\n<option value="781">781 H\xf6fn \xed Hornafir\xf0i</option>\n<option value="785">785 \xd6r\xe6fi</option>\n<option value="800">800 Selfoss</option>\n<option value="801">801 Selfoss</option>\n<option value="802">802 Selfoss</option>\n<option value="810">810 Hverager\xf0i</option>\n<option value="815">815 \xdeorl\xe1ksh\xf6fn</option>\n<option value="820">820 Eyrarbakki</option>\n<option value="825">825 Stokkseyri</option>\n<option value="840">840 Laugarvatn</option>\n<option value="845">845 Fl\xfa\xf0ir</option>\n<option value="850">850 Hella</option>\n<option value="851">851 Hella</option>\n<option value="860">860 Hvolsv\xf6llur</option>\n<option value="861">861 Hvolsv\xf6llur</option>\n<option value="870">870 V\xedk</option>\n<option value="871">871 V\xedk</option>\n<option value="880">880 Kirkjub\xe6jarklaustur</option>\n<option value="900">900 Vestmannaeyjar</option>\n<option value="902">902 Vestmannaeyjar</option>\n</select>'
  1153
+
  1154
+## CLRutField #############################################################
  1155
+
  1156
+CLRutField is a Field that checks the validity of the Chilean
  1157
+personal identification number (RUT). It has two modes relaxed (default) and
  1158
+strict.
  1159
+
  1160
+>>> from django.contrib.localflavor.cl.forms import CLRutField
  1161
+>>> rut = CLRutField()
  1162
+
  1163
+>>> rut.clean('11-6')
  1164
+'11-6'
  1165
+>>> rut.clean('116')
  1166
+'11-6'
  1167
+
  1168
+# valid format, bad verifier.
  1169
+>>> rut.clean('11.111.111-0')
  1170
+Traceback (most recent call last):
  1171
+...
  1172
+ValidationError: [u'The Chilean RUT is not valid.']
  1173
+>>> rut.clean('111')
  1174
+Traceback (most recent call last):
  1175
+...
  1176
+ValidationError: [u'The Chilean RUT is not valid.']
  1177
+
  1178
+>>> rut.clean('767484100')
  1179
+'76.748.410-0'
  1180
+>>> rut.clean('78.412.790-7')
  1181
+'78.412.790-7'
  1182
+>>> rut.clean('8.334.6043')
  1183
+'8.334.604-3'
  1184
+>>> rut.clean('76793310-K')
  1185
+'76.793.310-K'
  1186
+
  1187
+Strict RUT usage (does not allow imposible values)
  1188
+>>> rut = CLRutField(strict=True)
  1189
+
  1190
+>>> rut.clean('11-6')
  1191
+Traceback (most recent call last):
  1192
+...
  1193
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
  1194
+
  1195
+# valid format, bad verifier.
  1196
+>>> rut.clean('11.111.111-0')
  1197
+Traceback (most recent call last):
  1198
+...
  1199
+ValidationError: [u'The Chilean RUT is not valid.']
  1200
+
  1201
+# Correct input, invalid format.
  1202
+>>> rut.clean('767484100')
  1203
+Traceback (most recent call last):
  1204
+...
  1205
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
  1206
+>>> rut.clean('78.412.790-7')
  1207
+'78.412.790-7'
  1208
+>>> rut.clean('8.334.6043')
  1209
+Traceback (most recent call last):
  1210
+...
  1211
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
  1212
+>>> rut.clean('76793310-K')
  1213
+Traceback (most recent call last):
  1214
+...
  1215
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
  1216
+
1153 1217
 """

0 notes on commit ed60b86

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