PageRenderTime 103ms CodeModel.GetById 60ms app.highlight 12ms RepoModel.GetById 28ms app.codeStats 1ms

/django/contrib/localflavor/ar/forms.py

https://code.google.com/p/mango-py/
Python | 115 lines | 103 code | 3 blank | 9 comment | 2 complexity | 00cea5c9a0db277a9c7d3ab36a0d4172 MD5 | raw file
  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