Code

Ticket #5431: argentinean_localflavor_r6139.diff

File argentinean_localflavor_r6139.diff, 14.9 KB (added by ramiro, 7 years ago)
Line 
1diff -r 36ff13ea73e9 django/contrib/localflavor/ar/ar_provinces.py
2--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
3+++ b/django/contrib/localflavor/ar/ar_provinces.py     Thu Sep 13 19:42:20 2007 -0300
4@@ -0,0 +1,36 @@
5+# -*- coding: utf-8 -*-
6+"""
7+A list of Argentinean provinces and autonomous cities as `choices` in a
8+formfield. From
9+http://www.argentina.gov.ar/argentina/portal/paginas.dhtml?pagina=425
10+
11+This exists in this standalone file so that it's only imported into memory
12+when explicitly needed.
13+"""
14+
15+PROVINCE_CHOICES = (
16+    ('B', u'Buenos Aires'),
17+    ('K', u'Catamarca'),
18+    ('H', u'Chaco'),
19+    ('U', u'Chubut'),
20+    ('C', u'Ciudad Autónoma de Buenos Aires'),
21+    ('X', u'Córdoba'),
22+    ('W', u'Corrientes'),
23+    ('E', u'Entre Ríos'),
24+    ('P', u'Formosa'),
25+    ('Y', u'Jujuy'),
26+    ('L', u'La Pampa'),
27+    ('F', u'La Rioja'),
28+    ('M', u'Mendoza'),
29+    ('N', u'Misiones'),
30+    ('Q', u'Neuquén'),
31+    ('R', u'Río Negro'),
32+    ('A', u'Salta'),
33+    ('J', u'San Juan'),
34+    ('D', u'San Luis'),
35+    ('Z', u'Santa Cruz'),
36+    ('S', u'Santa Fe'),
37+    ('G', u'Santiago del Estero'),
38+    ('V', u'Tierra del Fuego, Antártida e Islas del Atlántico Sur'),
39+    ('T', u'Tucumán'),
40+)
41diff -r 36ff13ea73e9 django/contrib/localflavor/ar/forms.py
42--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
43+++ b/django/contrib/localflavor/ar/forms.py    Thu Sep 13 19:42:20 2007 -0300
44@@ -0,0 +1,113 @@
45+# -*- coding: utf-8 -*-
46+"""
47+AR-specific Form helpers.
48+"""
49+
50+from django.newforms import ValidationError
51+from django.newforms.fields import RegexField, CharField, Select, EMPTY_VALUES
52+from django.utils.encoding import smart_unicode
53+from django.utils.translation import ugettext
54+import re
55+
56+class ARProvinceSelect(Select):
57+    """
58+    A Select widget that uses a list of Argentinean provinces/autonomous
59+    cities as its choices.
60+
61+    """
62+    def __init__(self, attrs=None):
63+        from ar_provinces import PROVINCE_CHOICES
64+        super(ARProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
65+
66+
67+class ARPostalCodeField(RegexField):
68+    """
69+    A field that accepts a `classic´ NNNN Postal Code or a CPA.
70+
71+    See http://www.correoargentino.com.ar/consulta_cpa/home.php
72+
73+    """
74+    def __init__(self, *args, **kwargs):
75+        super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
76+            min_length=4, max_length=8,
77+            error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
78+                    *args, **kwargs)
79+
80+    def clean(self, value):
81+        value = super(ARPostalCodeField, self).clean(value)
82+        if value in EMPTY_VALUES:
83+            return u''
84+        if len(value) not in (4, 8):
85+            raise ValidationError(ugettext("Enter a postal code in the format NNNN or ANNNNAAA."))
86+        if len(value) == 8:
87+            return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
88+        return value
89+
90+
91+class ARDNIField(CharField):
92+    """
93+    A field that validates `Documento Nacional de Identidad´ (DNI)
94+    numbers.
95+
96+    """
97+    def __init__(self, *args, **kwargs):
98+        super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
99+                **kwargs)
100+
101+    def clean(self, value):
102+        """
103+        Value can be a string either in the [X]X.XXX.XXX or [X]XXXXXXX formats.
104+        """
105+        value = super(ARDNIField, self).clean(value)
106+        if value in EMPTY_VALUES:
107+            return u''
108+        if not value.isdigit():
109+            value = value.replace('.', '')
110+        if not value.isdigit():
111+            raise ValidationError(ugettext("This field requires only numbers."))
112+        if len(value) not in (7, 8):
113+            raise ValidationError(
114+                    ugettext("This field requires 7 or 8 digits."))
115+
116+        return value
117+
118+
119+class ARCUITField(RegexField):
120+    """
121+    This field validates a CUIT (Código Único de Identificación
122+    Tributaria). A CUIT is of the form XX-XXXXXXXX-V. The last digit
123+    is a check digit.
124+
125+    """
126+    def __init__(self, *args, **kwargs):
127+        super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$',
128+            error_message=ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
129+            *args, **kwargs)
130+
131+    def clean(self, value):
132+        """
133+        Value can be either a string in the format XX-XXXXXXXX-X or an
134+        11-digit number.
135+        """
136+        value = super(ARCUITField, self).clean(value)
137+        if value in EMPTY_VALUES:
138+            return u''
139+        value, cd = self._canon(value)
140+        if self._calc_cd(value) != cd:
141+            raise ValidationError(ugettext("Invalid CUIT."))
142+        return self._format(value, cd)
143+
144+    def _canon(self, cuit):
145+        cuit = cuit.replace('-', '')
146+        return cuit[:-1], cuit[-1]
147+
148+    def _calc_cd(self, cuit):
149+        mults = (5, 4, 3, 2, 7, 6, 5, 4, 3, 2)
150+        tmp = sum([m * int(cuit[idx]) for idx, m in enumerate(mults)])
151+        return str(11 - tmp % 11)
152+
153+    def _format(self, cuit, check_digit=None):
154+        if check_digit == None:
155+            check_digit = cuit[-1]
156+            cuit = code[:-1]
157+        return u'%s-%s-%s' % (cuit[:2], cuit[2:], check_digit)
158diff -r 36ff13ea73e9 tests/regressiontests/forms/localflavor.py
159--- a/tests/regressiontests/forms/localflavor.py        Thu Sep 13 19:16:59 2007 -0300
160+++ b/tests/regressiontests/forms/localflavor.py        Thu Sep 13 19:42:20 2007 -0300
161@@ -1514,4 +1514,294 @@ ValidationError: [u'Enter a valid SoFi n
162 >>> s = NLProvinceSelect()
163 >>> s.render('provinces', 'OV')
164 u'<select name="provinces">\n<option value="DR">Drente</option>\n<option value="FL">Flevoland</option>\n<option value="FR">Friesland</option>\n<option value="GL">Gelderland</option>\n<option value="GR">Groningen</option>\n<option value="LB">Limburg</option>\n<option value="NB">Noord-Brabant</option>\n<option value="NH">Noord-Holland</option>\n<option value="OV" selected="selected">Overijssel</option>\n<option value="UT">Utrecht</option>\n<option value="ZE">Zeeland</option>\n<option value="ZH">Zuid-Holland</option>\n</select>'
165+
166+# ARProvinceField #############################################################
167+
168+>>> from django.contrib.localflavor.ar.forms import ARProvinceSelect
169+>>> f = ARProvinceSelect()
170+>>> f.render('provincias', 'A')
171+u'<select name="provincias">\n<option value="B">Buenos Aires</option>\n<option value="K">Catamarca</option>\n<option value="H">Chaco</option>\n<option value="U">Chubut</option>\n<option value="C">Ciudad Aut\xf3noma de Buenos Aires</option>\n<option value="X">C\xf3rdoba</option>\n<option value="W">Corrientes</option>\n<option value="E">Entre R\xedos</option>\n<option value="P">Formosa</option>\n<option value="Y">Jujuy</option>\n<option value="L">La Pampa</option>\n<option value="F">La Rioja</option>\n<option value="M">Mendoza</option>\n<option value="N">Misiones</option>\n<option value="Q">Neuqu\xe9n</option>\n<option value="R">R\xedo Negro</option>\n<option value="A" selected="selected">Salta</option>\n<option value="J">San Juan</option>\n<option value="D">San Luis</option>\n<option value="Z">Santa Cruz</option>\n<option value="S">Santa Fe</option>\n<option value="G">Santiago del Estero</option>\n<option value="V">Tierra del Fuego, Ant\xe1rtida e Islas del Atl\xe1ntico Sur</option>\n<option value="T">Tucum\xe1n</option>\n</select>'
172+
173+# ARPostalCodeField ###########################################################
174+
175+>>> from django.contrib.localflavor.ar.forms import ARPostalCodeField
176+>>> f = ARPostalCodeField()
177+>>> f.clean('5000')
178+u'5000'
179+>>> f.clean('C1064AAB')
180+u'C1064AAB'
181+>>> f.clean('c1064AAB')
182+u'C1064AAB'
183+>>> f.clean('C1064aab')
184+u'C1064AAB'
185+>>> f.clean(u'4400')
186+u'4400'
187+>>> f.clean(u'C1064AAB')
188+u'C1064AAB'
189+>>> f.clean('C1064AABB')
190+Traceback (most recent call last):
191+...
192+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
193+>>> f.clean('C1064AA')
194+Traceback (most recent call last):
195+...
196+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
197+>>> f.clean('C106AAB')
198+Traceback (most recent call last):
199+...
200+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
201+>>> f.clean('106AAB')
202+Traceback (most recent call last):
203+...
204+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
205+>>> f.clean('500')
206+Traceback (most recent call last):
207+...
208+ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
209+>>> f.clean('5PPP')
210+Traceback (most recent call last):
211+...
212+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
213+>>> f.clean(None)
214+Traceback (most recent call last):
215+...
216+ValidationError: [u'This field is required.']
217+>>> f.clean('')
218+Traceback (most recent call last):
219+...
220+ValidationError: [u'This field is required.']
221+>>> f.clean(u'')
222+Traceback (most recent call last):
223+...
224+ValidationError: [u'This field is required.']
225+
226+>>> f = ARPostalCodeField(required=False)
227+>>> f.clean('5000')
228+u'5000'
229+>>> f.clean('C1064AAB')
230+u'C1064AAB'
231+>>> f.clean('c1064AAB')
232+u'C1064AAB'
233+>>> f.clean('C1064aab')
234+u'C1064AAB'
235+>>> f.clean(u'4400')
236+u'4400'
237+>>> f.clean(u'C1064AAB')
238+u'C1064AAB'
239+>>> f.clean('C1064AABB')
240+Traceback (most recent call last):
241+...
242+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
243+>>> f.clean('C1064AA')
244+Traceback (most recent call last):
245+...
246+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
247+>>> f.clean('C106AAB')
248+Traceback (most recent call last):
249+...
250+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
251+>>> f.clean('106AAB')
252+Traceback (most recent call last):
253+...
254+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
255+>>> f.clean('500')
256+Traceback (most recent call last):
257+...
258+ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
259+>>> f.clean('5PPP')
260+Traceback (most recent call last):
261+...
262+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
263+>>> f.clean(None)
264+u''
265+>>> f.clean('')
266+u''
267+>>> f.clean(u'')
268+u''
269+
270+# ARDNIField ##################################################################
271+
272+>>> from django.contrib.localflavor.ar.forms import ARDNIField
273+>>> f = ARDNIField()
274+>>> f.clean('20123456')
275+u'20123456'
276+>>> f.clean('20.123.456')
277+u'20123456'
278+>>> f.clean('9123456')
279+u'9123456'
280+>>> f.clean('9.123.456')
281+u'9123456'
282+>>> f.clean(u'20123456')
283+u'20123456'
284+>>> f.clean(u'20.123.456')
285+u'20123456'
286+>>> f.clean('20.123456')
287+u'20123456'
288+>>> f.clean('101234566')
289+Traceback (most recent call last):
290+...
291+ValidationError: [u'This field requires 7 or 8 digits.']
292+>>> f.clean('W0123456')
293+Traceback (most recent call last):
294+...
295+ValidationError: [u'This field requires only numbers.']
296+>>> f.clean('10,123,456')
297+Traceback (most recent call last):
298+...
299+ValidationError: [u'This field requires only numbers.']
300+>>> f.clean(None)
301+Traceback (most recent call last):
302+...
303+ValidationError: [u'This field is required.']
304+>>> f.clean('')
305+Traceback (most recent call last):
306+...
307+ValidationError: [u'This field is required.']
308+>>> f.clean(u'')
309+Traceback (most recent call last):
310+...
311+ValidationError: [u'This field is required.']
312+
313+>>> f = ARDNIField(required=False)
314+>>> f.clean('20123456')
315+u'20123456'
316+>>> f.clean('20.123.456')
317+u'20123456'
318+>>> f.clean('9123456')
319+u'9123456'
320+>>> f.clean('9.123.456')
321+u'9123456'
322+>>> f.clean(u'20123456')
323+u'20123456'
324+>>> f.clean(u'20.123.456')
325+u'20123456'
326+>>> f.clean('20.123456')
327+u'20123456'
328+>>> f.clean('101234566')
329+Traceback (most recent call last):
330+...
331+ValidationError: [u'This field requires 7 or 8 digits.']
332+>>> f.clean('W0123456')
333+Traceback (most recent call last):
334+...
335+ValidationError: [u'This field requires only numbers.']
336+>>> f.clean('10,123,456')
337+Traceback (most recent call last):
338+...
339+ValidationError: [u'This field requires only numbers.']
340+>>> f.clean(None)
341+u''
342+>>> f.clean('')
343+u''
344+>>> f.clean(u'')
345+u''
346+
347+# ARCUITField #################################################################
348+
349+>>> from django.contrib.localflavor.ar.forms import ARCUITField
350+>>> f = ARCUITField()
351+>>> f.clean('20-10123456-9')
352+u'20-10123456-9'
353+>>> f.clean(u'20-10123456-9')
354+u'20-10123456-9'
355+>>> f.clean('27-10345678-4')
356+u'27-10345678-4'
357+>>> f.clean('20101234569')
358+u'20-10123456-9'
359+>>> f.clean('27103456784')
360+u'27-10345678-4'
361+>>> f.clean('2-10123456-9')
362+Traceback (most recent call last):
363+...
364+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
365+>>> f.clean('210123456-9')
366+Traceback (most recent call last):
367+...
368+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
369+>>> f.clean('20-10123456')
370+Traceback (most recent call last):
371+...
372+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
373+>>> f.clean('20-10123456-')
374+Traceback (most recent call last):
375+...
376+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
377+>>> f.clean('20-10123456-5')
378+Traceback (most recent call last):
379+...
380+ValidationError: [u'Invalid CUIT.']
381+>>> f.clean(u'2-10123456-9')
382+Traceback (most recent call last):
383+...
384+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
385+>>> f.clean('27-10345678-1')
386+Traceback (most recent call last):
387+...
388+ValidationError: [u'Invalid CUIT.']
389+>>> f.clean(u'27-10345678-1')
390+Traceback (most recent call last):
391+...
392+ValidationError: [u'Invalid CUIT.']
393+>>> f.clean(None)
394+Traceback (most recent call last):
395+...
396+ValidationError: [u'This field is required.']
397+>>> f.clean('')
398+Traceback (most recent call last):
399+...
400+ValidationError: [u'This field is required.']
401+>>> f.clean(u'')
402+Traceback (most recent call last):
403+...
404+ValidationError: [u'This field is required.']
405+
406+>>> f = ARCUITField(required=False)
407+>>> f.clean('20-10123456-9')
408+u'20-10123456-9'
409+>>> f.clean(u'20-10123456-9')
410+u'20-10123456-9'
411+>>> f.clean('27-10345678-4')
412+u'27-10345678-4'
413+>>> f.clean('20101234569')
414+u'20-10123456-9'
415+>>> f.clean('27103456784')
416+u'27-10345678-4'
417+>>> f.clean('2-10123456-9')
418+Traceback (most recent call last):
419+...
420+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
421+>>> f.clean('210123456-9')
422+Traceback (most recent call last):
423+...
424+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
425+>>> f.clean('20-10123456')
426+Traceback (most recent call last):
427+...
428+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
429+>>> f.clean('20-10123456-')
430+Traceback (most recent call last):
431+...
432+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
433+>>> f.clean('20-10123456-5')
434+Traceback (most recent call last):
435+...
436+ValidationError: [u'Invalid CUIT.']
437+>>> f.clean(u'2-10123456-9')
438+Traceback (most recent call last):
439+...
440+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
441+>>> f.clean('27-10345678-1')
442+Traceback (most recent call last):
443+...
444+ValidationError: [u'Invalid CUIT.']
445+>>> f.clean(u'27-10345678-1')
446+Traceback (most recent call last):
447+...
448+ValidationError: [u'Invalid CUIT.']
449+>>> f.clean(None)
450+u''
451+>>> f.clean('')
452+u''
453+>>> f.clean(u'')
454+u''
455 """