| 21 | class MXPostalCodeField(RegexField): |
| 22 | default_error_messages = { |
| 23 | 'invalid': _('Enter a postal code in the format XXXXX.'), |
| 24 | } |
| 25 | |
| 26 | def __init__(self, *args, **kwargs): |
| 27 | super(MXPostalCodeField, self).__init__(r'^\d{5}$', |
| 28 | min_length=5, max_length=5, *args, **kwargs) |
| 29 | |
| 30 | class MXRFCField(RegexField): |
| 31 | """ |
| 32 | Registro federal de contribuyente. |
| 33 | """ |
| 34 | default_error_messages = { |
| 35 | 'invalid': _('Invalid RFC.'), |
| 36 | } |
| 37 | |
| 38 | def __init__(self, *args, **kwargs): |
| 39 | super(MXRFCField, self).__init__( |
| 40 | re.compile(r'^[A-Z&\d]{3,4}\d{6}[A-Z\d]{3}$', re.I), |
| 41 | min_length=12, max_length=13, *args, **kwargs) |
| 42 | |
| 43 | def clean(self, value): |
| 44 | value = super(MXRFCField, self).clean(value) |
| 45 | |
| 46 | if value in EMPTY_VALUES: |
| 47 | return u'' |
| 48 | |
| 49 | value = value.upper().strip() |
| 50 | if value[-1] != self._checksum(value[:-1]): |
| 51 | raise ValidationError(self.error_messages['invalid']) |
| 52 | |
| 53 | return value |
| 54 | |
| 55 | def _checksum(self, rfc): |
| 56 | chars = '0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ-' |
| 57 | |
| 58 | if len(rfc) == 11: |
| 59 | rfc = '-' + rfc |
| 60 | |
| 61 | s = sum(i * chars.index(c) for i, c in zip(reversed(xrange(14)), rfc)) |
| 62 | checksum = 11 - (s % 11) |
| 63 | |
| 64 | if checksum == 10: |
| 65 | return 'A' |
| 66 | elif checksum == 11: |
| 67 | return '0' |
| 68 | else: |
| 69 | return str(checksum) |
| 70 | |
| 71 | class MXCURPField(RegexField): |
| 72 | """ |
| 73 | Clave única de registro de población. |
| 74 | """ |
| 75 | default_error_messages = { |
| 76 | 'invalid': _('Invalid CURP.'), |
| 77 | } |
| 78 | |
| 79 | def __init__(self, *args, **kwargs): |
| 80 | curp_re = r'^[A-Z]{4}\d{6}[HM][A-Z]{2}[B-DF-HJ-NP-TV-Z]{3}[0-9A-Z]\d$' |
| 81 | super(MXCURPField, self).__init__(re.compile(curp_re, re.I), |
| 82 | min_length=18, max_length=18, *args, **kwargs) |
| 83 | |
| 84 | def clean(self, value): |
| 85 | value = super(MXCURPField, self).clean(value) |
| 86 | |
| 87 | if value in EMPTY_VALUES: |
| 88 | return u'' |
| 89 | |
| 90 | value = value.upper() |
| 91 | if value[-1] != self._checksum(value[:-1]): |
| 92 | raise ValidationError(self.error_messages['invalid']) |
| 93 | |
| 94 | return value |
| 95 | |
| 96 | def _checksum(self, curp): |
| 97 | chars = u'0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ' |
| 98 | s = sum(i * chars.index(c) for i, c in zip(reversed(xrange(19)), curp)) |
| 99 | checksum = 10 - (s % 10) |
| 100 | return '0' if checksum == 10 else str(checksum) |