/django/contrib/localflavor/ar/forms.py
Python | 115 lines | 103 code | 3 blank | 9 comment | 2 complexity | 00cea5c9a0db277a9c7d3ab36a0d4172 MD5 | raw file
Possible License(s): BSD-3-Clause
1# -*- coding: utf-8 -*- 2""" 3AR-specific Form helpers. 4""" 5 6from django.forms import ValidationError 7from django.core.validators import EMPTY_VALUES 8from django.forms.fields import RegexField, CharField, Select 9from django.utils.encoding import smart_unicode 10from django.utils.translation import ugettext_lazy as _ 11 12class ARProvinceSelect(Select): 13 """ 14 A Select widget that uses a list of Argentinean provinces/autonomous cities 15 as its choices. 16 """ 17 def __init__(self, attrs=None): 18 from ar_provinces import PROVINCE_CHOICES 19 super(ARProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES) 20 21class ARPostalCodeField(RegexField): 22 """ 23 A field that accepts a 'classic' NNNN Postal Code or a CPA. 24 25 See http://www.correoargentino.com.ar/consulta_cpa/home.php 26 """ 27 default_error_messages = { 28 'invalid': _("Enter a postal code in the format NNNN or ANNNNAAA."), 29 } 30 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) 34 35 def clean(self, value): 36 value = super(ARPostalCodeField, self).clean(value) 37 if value in EMPTY_VALUES: 38 return u'' 39 if len(value) not in (4, 8): 40 raise ValidationError(self.error_messages['invalid']) 41 if len(value) == 8: 42 return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper()) 43 return value 44 45class ARDNIField(CharField): 46 """ 47 A field that validates 'Documento Nacional de Identidad' (DNI) numbers. 48 """ 49 default_error_messages = { 50 'invalid': _("This field requires only numbers."), 51 'max_digits': _("This field requires 7 or 8 digits."), 52 } 53 54 def __init__(self, *args, **kwargs): 55 super(ARDNIField, self).__init__(max_length=10, min_length=7, *args, 56 **kwargs) 57 58 def clean(self, value): 59 """ 60 Value can be a string either in the [X]X.XXX.XXX or [X]XXXXXXX formats. 61 """ 62 value = super(ARDNIField, self).clean(value) 63 if value in EMPTY_VALUES: 64 return u'' 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']) 71 72 return value 73 74class ARCUITField(RegexField): 75 """ 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. 78 """ 79 default_error_messages = { 80 'invalid': _('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'), 81 'checksum': _("Invalid CUIT."), 82 } 83 84 def __init__(self, *args, **kwargs): 85 super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$', 86 *args, **kwargs) 87 88 def clean(self, value): 89 """ 90 Value can be either a string in the format XX-XXXXXXXX-X or an 91 11-digit number. 92 """ 93 value = super(ARCUITField, self).clean(value) 94 if value in EMPTY_VALUES: 95 return u'' 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) 100 101 def _canon(self, cuit): 102 cuit = cuit.replace('-', '') 103 return cuit[:-1], cuit[-1] 104 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) 109 110 def _format(self, cuit, check_digit=None): 111 if check_digit == None: 112 check_digit = cuit[-1] 113 cuit = cuit[:-1] 114 return u'%s-%s-%s' % (cuit[:2], cuit[2:], check_digit) 115