app/django/contrib/localflavor/cl/forms.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 """
       
     2 Chile specific form helpers.
       
     3 """
       
     4 
       
     5 from django.newforms import ValidationError
       
     6 from django.newforms.fields import RegexField, Select, EMPTY_VALUES
       
     7 from django.utils.translation import ugettext
       
     8 from django.utils.encoding import smart_unicode
       
     9 
       
    10 
       
    11 class CLRegionSelect(Select):
       
    12     """
       
    13     A Select widget that uses a list of Chilean Regions (Regiones)
       
    14     as its choices.
       
    15     """
       
    16     def __init__(self, attrs=None):
       
    17         from cl_regions import REGION_CHOICES
       
    18         super(CLRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
       
    19 
       
    20 class CLRutField(RegexField):
       
    21     """
       
    22     Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national
       
    23     identification number.
       
    24 
       
    25     Samples for testing are available from
       
    26     https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
       
    27     """
       
    28     default_error_messages = {
       
    29         'invalid': ugettext('Enter a valid Chilean RUT.'),
       
    30         'strict': ugettext('Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'),
       
    31         'checksum': ugettext('The Chilean RUT is not valid.'),
       
    32     }
       
    33 
       
    34     def __init__(self, *args, **kwargs):
       
    35         if 'strict' in kwargs:
       
    36             del kwargs['strict']
       
    37             super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
       
    38                 error_message=self.default_error_messages['strict'], *args, **kwargs)
       
    39         else:
       
    40             # In non-strict mode, accept RUTs that validate but do not exist in
       
    41             # the real world.
       
    42             super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', *args, **kwargs)
       
    43 
       
    44     def clean(self, value):
       
    45         """
       
    46         Check and clean the Chilean RUT.
       
    47         """
       
    48         super(CLRutField, self).clean(value)
       
    49         if value in EMPTY_VALUES:
       
    50             return u''
       
    51         rut, verificador = self._canonify(value)
       
    52         if self._algorithm(rut) == verificador:
       
    53             return self._format(rut, verificador)
       
    54         else:
       
    55             raise ValidationError(self.error_messages['checksum'])
       
    56 
       
    57     def _algorithm(self, rut):
       
    58         """
       
    59         Takes RUT in pure canonical form, calculates the verifier digit.
       
    60         """
       
    61         suma  = 0
       
    62         multi = 2
       
    63         for r in rut[::-1]:
       
    64             suma  += int(r) * multi
       
    65             multi += 1
       
    66             if multi == 8:
       
    67                 multi = 2
       
    68         return u'0123456789K0'[11 - suma % 11]
       
    69 
       
    70     def _canonify(self, rut):
       
    71         """
       
    72         Turns the RUT into one normalized format. Returns a (rut, verifier)
       
    73         tuple.
       
    74         """
       
    75         rut = smart_unicode(rut).replace(' ', '').replace('.', '').replace('-', '')
       
    76         return rut[:-1], rut[-1]
       
    77 
       
    78     def _format(self, code, verifier=None):
       
    79         """
       
    80         Formats the RUT from canonical form to the common string representation.
       
    81         If verifier=None, then the last digit in 'code' is the verifier.
       
    82         """
       
    83         if verifier is None:
       
    84             verifier = code[-1]
       
    85             code = code[:-1]
       
    86         while len(code) > 3 and '.' not in code[:3]:
       
    87             pos = code.find('.')
       
    88             if pos == -1:
       
    89                 new_dot = -3
       
    90             else:
       
    91                 new_dot = pos - 3
       
    92             code = code[:new_dot] + '.' + code[new_dot:]
       
    93         return u'%s-%s' % (code, verifier)
       
    94