| | 100 | |
| | 101 | class CLPatenteField(CharField): |
| | 102 | """ |
| | 103 | Chilean "Patente", Placa Patente Field, support old LL-NNNN and new LLLL-NN |
| | 104 | type, where L in new can't be vowel or m,n and q. |
| | 105 | """ |
| | 106 | |
| | 107 | default_error_messages = CharField.default_error_messages |
| | 108 | default_error_messages.update({'invalid': _('Enter a valid Chilean Car Plate.'),}) |
| | 109 | |
| | 110 | def __init__(self, *args, **kwargs): |
| | 111 | kwargs['max_length'] = 7 |
| | 112 | kwargs['min_length'] = 6 |
| | 113 | kwargs['label'] = "Valor" |
| | 114 | super(CLPatenteField, self).__init__(*args, **kwargs) |
| | 115 | |
| | 116 | def clean(self, value): |
| | 117 | """ |
| | 118 | Check and clean the field for length and type. |
| | 119 | """ |
| | 120 | super(CLPatenteField, self).clean(value) |
| | 121 | if value in EMPTY_VALUES: |
| | 122 | return u'' |
| | 123 | |
| | 124 | value = smart_unicode(value.lower()) |
| | 125 | value_length = len(value) |
| | 126 | if self.max_length is not None and value_length > self.max_length: |
| | 127 | raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) |
| | 128 | if self.min_length is not None and value_length < self.min_length: |
| | 129 | raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) |
| | 130 | |
| | 131 | value = self._canonify(value) |
| | 132 | _type = self._algorithm(value) |
| | 133 | |
| | 134 | if _type not in (OLD, NEW): |
| | 135 | raise ValidationError(self.error_messages['invalid']) |
| | 136 | |
| | 137 | return self._format(value.upper(), _type) |
| | 138 | |
| | 139 | def _algorithm(self, value): |
| | 140 | """ |
| | 141 | Takes Car Plate in canonical form and verify if it is valid. |
| | 142 | Returns the type or None it is not valid. |
| | 143 | """ |
| | 144 | import re |
| | 145 | # Old type patern |
| | 146 | op = '^[a-z]{2,2}\d{4,4}$' |
| | 147 | op = re.compile(op) |
| | 148 | # New type patern |
| | 149 | np = '^[bcdfghjklprstvwxyz]{4,4}\d{2,2}$' |
| | 150 | np = re.compile(np) |
| | 151 | if re.search(op, value): |
| | 152 | return OLD |
| | 153 | elif re.search(np, value): |
| | 154 | return NEW |
| | 155 | else: |
| | 156 | return None |
| | 157 | |
| | 158 | def _canonify(self, patente): |
| | 159 | """ |
| | 160 | Turns the Car Plate into one normalized format. |
| | 161 | """ |
| | 162 | return patente.replace(' ', '').replace('-', '') |
| | 163 | |
| | 164 | def _format(self, value, _type): |
| | 165 | """ |
| | 166 | Formats the Car Plate from canonical form to the common string |
| | 167 | representation. LL-DDDD or LLLL-DD |
| | 168 | """ |
| | 169 | if _type == OLD: |
| | 170 | return u'-'.join((value[:2], value[2:])) |
| | 171 | if _type == NEW: |
| | 172 | return u'-'.join((value[:4], value[4:])) |