1 | # -*- coding: utf-8 -*-
|
---|
2 | """
|
---|
3 | VE-specific Form helpers.
|
---|
4 | """
|
---|
5 |
|
---|
6 | from django.forms import ValidationError
|
---|
7 | from django.forms.fields import RegexField, CharField, Select, EMPTY_VALUES
|
---|
8 | from django.utils.encoding import smart_unicode
|
---|
9 | from django.utils.translation import ugettext_lazy as _
|
---|
10 |
|
---|
11 | class VEStateSelect(Select):
|
---|
12 | """
|
---|
13 | A Select widget that uses a list of Venezuelan States
|
---|
14 | as its choices.
|
---|
15 | """
|
---|
16 | def __init__(self, attrs=None):
|
---|
17 | from ve_states import STATE_CHOICES
|
---|
18 | super(VEStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
|
---|
19 |
|
---|
20 | class VEPostalCodeField(RegexField):
|
---|
21 | """
|
---|
22 | A field that accepts a 'classic' XXXX Postal Code
|
---|
23 | """
|
---|
24 | default_error_messages = {
|
---|
25 | 'invalid': _("Enter a postal code in the format XXXX."),
|
---|
26 | }
|
---|
27 |
|
---|
28 | def __init__(self, *args, **kwargs):
|
---|
29 | super(ARPostalCodeField, self).__init__(r'^\d{4}$',
|
---|
30 | min_length=4, max_length=4, *args, **kwargs)
|
---|
31 |
|
---|
32 | def clean(self, value):
|
---|
33 | value = super(VEPostalCodeField, self).clean(value)
|
---|
34 | if value in EMPTY_VALUES:
|
---|
35 | return u''
|
---|
36 | if len(value) not in (4, 8):
|
---|
37 | raise ValidationError(self.error_messages['invalid'])
|
---|
38 | if len(value) == 4:
|
---|
39 | return u'%s' % (value)
|
---|
40 | return value
|
---|
41 |
|
---|
42 | class CIField(CharField):
|
---|
43 | """
|
---|
44 | A field that validates 'Cédula de Identidad' (CI) numbers.
|
---|
45 | """
|
---|
46 | default_error_messages = {
|
---|
47 | 'invalid': _("This field requires only numbers."),
|
---|
48 | 'max_digits': _("This field requires 7 or 8 digits."),
|
---|
49 | }
|
---|
50 |
|
---|
51 | def __init__(self, *args, **kwargs):
|
---|
52 | super(CIField, self).__init__(max_length=10, min_length=7, *args,
|
---|
53 | **kwargs)
|
---|
54 |
|
---|
55 | def clean(self, value):
|
---|
56 | """
|
---|
57 | Value can be a string either in the [X]X.XXX.XXX or [X]XXXXXXX formats.
|
---|
58 | """
|
---|
59 | value = super(CIField, self).clean(value)
|
---|
60 | if value in EMPTY_VALUES:
|
---|
61 | return u''
|
---|
62 | if not value.isdigit():
|
---|
63 | value = value.replace('.', '')
|
---|
64 | if not value.isdigit():
|
---|
65 | raise ValidationError(self.error_messages['invalid'])
|
---|
66 | if len(value) not in (7, 8):
|
---|
67 | raise ValidationError(self.error_messages['max_digits'])
|
---|
68 |
|
---|
69 | return value
|
---|
70 |
|
---|
71 | class RIFField(RegexField):
|
---|
72 | """
|
---|
73 | This field validates a RIF (Registro de Información Fiscal). A
|
---|
74 | RIF is of the form A-XXXXXXXX-X. The last digit is a check digit.
|
---|
75 | """
|
---|
76 | rif_first_char = {
|
---|
77 | 'v':'1',
|
---|
78 | 'e':'2',
|
---|
79 | 'j':'3',
|
---|
80 | 'p':'4',
|
---|
81 | 'g':'5',
|
---|
82 | }
|
---|
83 | default_error_messages = {
|
---|
84 | 'invalid': _('Enter a valid RIF in A-XXXXXXXX-X or AXXXXXXXXX format.'),
|
---|
85 | 'checksum': _("Invalid RIF."),
|
---|
86 | }
|
---|
87 |
|
---|
88 | def __init__(self, *args, **kwargs):
|
---|
89 | super(RIFField, self).__init__(r'^[jJ|vV|eE]-\d{8}-\d$',*args, **kwargs)
|
---|
90 |
|
---|
91 | def clean(self, value):
|
---|
92 | """Value can be either a string in A-XXXXXXXX-X or AXXXXXXXXX format"""
|
---|
93 | value = super(RIFField, 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, rif):
|
---|
102 | rif = rif.replace('-', '')
|
---|
103 | if rif[0].lower() in self.rif_first_char:
|
---|
104 | rif = rif.replace(rif[0], self.rif_first_char[rif[0]])
|
---|
105 | else:
|
---|
106 | raise ValidationError(self.error_messages['invalid'])
|
---|
107 | return rif[:-1], rif[-1]
|
---|
108 |
|
---|
109 | def _calc_cd(self, rif):
|
---|
110 | mults = (4, 3, 2, 7, 6, 5, 4, 3, 2)
|
---|
111 | tmp = sum([m * int(rif[idx]) for idx, m in enumerate(mults)])
|
---|
112 | return str(11 - tmp % 11)
|
---|
113 |
|
---|
114 | def _format(self, rif, check_digit=None):
|
---|
115 | if check_digit == None:
|
---|
116 | check_digit = rif[-1]
|
---|
117 | rif = rif[:-1]
|
---|
118 | return u'%s%s%s' % (rif[:2], rif[2:], check_digit)
|
---|