1 # -*- coding: utf-8 -*-
3 AR-specific Form helpers.
6 from django
.forms
import ValidationError
7 from django
.core
.validators
import EMPTY_VALUES
8 from django
.forms
.fields
import RegexField
, CharField
, Select
9 from django
.utils
.encoding
import smart_unicode
10 from django
.utils
.translation
import ugettext_lazy
as _
12 class ARProvinceSelect(Select
):
14 A Select widget that uses a list of Argentinean provinces/autonomous cities
17 def __init__(self
, attrs
=None):
18 from ar_provinces
import PROVINCE_CHOICES
19 super(ARProvinceSelect
, self
).__init
__(attrs
, choices
=PROVINCE_CHOICES
)
21 class ARPostalCodeField(RegexField
):
23 A field that accepts a 'classic' NNNN Postal Code or a CPA.
25 See http://www.correoargentino.com.ar/consulta_cpa/home.php
27 default_error_messages
= {
28 'invalid': _("Enter a postal code in the format NNNN or ANNNNAAA."),
31 def __init__(self
, *args
, **kwargs
):
32 super(ARPostalCodeField
, self
).__init
__(r
'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
33 min_length
=4, max_length
=8, *args
, **kwargs
)
35 def clean(self
, value
):
36 value
= super(ARPostalCodeField
, self
).clean(value
)
37 if value
in EMPTY_VALUES
:
39 if len(value
) not in (4, 8):
40 raise ValidationError(self
.error_messages
['invalid'])
42 return u
'%s%s%s' % (value
[0].upper(), value
[1:5], value
[5:].upper())
45 class ARDNIField(CharField
):
47 A field that validates 'Documento Nacional de Identidad' (DNI) numbers.
49 default_error_messages
= {
50 'invalid': _("This field requires only numbers."),
51 'max_digits': _("This field requires 7 or 8 digits."),
54 def __init__(self
, *args
, **kwargs
):
55 super(ARDNIField
, self
).__init
__(max_length
=10, min_length
=7, *args
,
58 def clean(self
, value
):
60 Value can be a string either in the [X]X.XXX.XXX or [X]XXXXXXX formats.
62 value
= super(ARDNIField
, self
).clean(value
)
63 if value
in EMPTY_VALUES
:
65 if not value
.isdigit():
66 value
= value
.replace('.', '')
67 if not value
.isdigit():
68 raise ValidationError(self
.error_messages
['invalid'])
69 if len(value
) not in (7, 8):
70 raise ValidationError(self
.error_messages
['max_digits'])
74 class ARCUITField(RegexField
):
76 This field validates a CUIT (Código Único de Identificación Tributaria). A
77 CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit.
79 default_error_messages
= {
80 'invalid': _('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
81 'checksum': _("Invalid CUIT."),
84 def __init__(self
, *args
, **kwargs
):
85 super(ARCUITField
, self
).__init
__(r
'^\d{2}-?\d{8}-?\d$',
88 def clean(self
, value
):
90 Value can be either a string in the format XX-XXXXXXXX-X or an
93 value
= super(ARCUITField
, self
).clean(value
)
94 if value
in EMPTY_VALUES
:
96 value
, cd
= self
._canon
(value
)
97 if self
._calc
_cd
(value
) != cd
:
98 raise ValidationError(self
.error_messages
['checksum'])
99 return self
._format
(value
, cd
)
101 def _canon(self
, cuit
):
102 cuit
= cuit
.replace('-', '')
103 return cuit
[:-1], cuit
[-1]
105 def _calc_cd(self
, cuit
):
106 mults
= (5, 4, 3, 2, 7, 6, 5, 4, 3, 2)
107 tmp
= sum([m
* int(cuit
[idx
]) for idx
, m
in enumerate(mults
)])
108 return str(11 - tmp
% 11)
110 def _format(self
, cuit
, check_digit
=None):
111 if check_digit
== None:
112 check_digit
= cuit
[-1]
114 return u
'%s-%s-%s' % (cuit
[:2], cuit
[2:], check_digit
)