PageRenderTime 15ms CodeModel.GetById 2ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/localflavor/ro/forms.py

https://code.google.com/p/mango-py/
Python | 206 lines | 189 code | 5 blank | 12 comment | 6 complexity | ea25f01e5308599bb2fa80036d08cfd4 MD5 | raw file
  1# -*- coding: utf-8 -*-
  2"""
  3Romanian specific form helpers.
  4"""
  5
  6import re
  7
  8from django.core.validators import EMPTY_VALUES
  9from django.forms import ValidationError, Field, RegexField, Select
 10from django.utils.translation import ugettext_lazy as _
 11
 12class ROCIFField(RegexField):
 13    """
 14    A Romanian fiscal identity code (CIF) field
 15
 16    For CIF validation algorithm see http://www.validari.ro/cui.html
 17    """
 18    default_error_messages = {
 19        'invalid': _("Enter a valid CIF."),
 20    }
 21
 22    def __init__(self, *args, **kwargs):
 23        super(ROCIFField, self).__init__(r'^(RO)?[0-9]{2,10}', max_length=10,
 24                min_length=2, *args, **kwargs)
 25
 26    def clean(self, value):
 27        """
 28        CIF validation
 29        """
 30        value = super(ROCIFField, self).clean(value)
 31        if value in EMPTY_VALUES:
 32            return u''
 33        # strip RO part
 34        if value[0:2] == 'RO':
 35            value = value[2:]
 36        key = '753217532'[::-1]
 37        value = value[::-1]
 38        key_iter = iter(key)
 39        checksum = 0
 40        for digit in value[1:]:
 41            checksum += int(digit) * int(key_iter.next())
 42        checksum = checksum * 10 % 11
 43        if checksum == 10:
 44            checksum = 0
 45        if checksum != int(value[0]):
 46            raise ValidationError(self.error_messages['invalid'])
 47        return value[::-1]
 48
 49class ROCNPField(RegexField):
 50    """
 51    A Romanian personal identity code (CNP) field
 52
 53    For CNP validation algorithm see http://www.validari.ro/cnp.html
 54    """
 55    default_error_messages = {
 56        'invalid': _("Enter a valid CNP."),
 57    }
 58
 59    def __init__(self, *args, **kwargs):
 60        super(ROCNPField, self).__init__(r'^[1-9][0-9]{12}', max_length=13,
 61            min_length=13, *args, **kwargs)
 62
 63    def clean(self, value):
 64        """
 65        CNP validations
 66        """
 67        value = super(ROCNPField, self).clean(value)
 68        if value in EMPTY_VALUES:
 69            return u''
 70        # check birthdate digits
 71        import datetime
 72        try:
 73            datetime.date(int(value[1:3]),int(value[3:5]),int(value[5:7]))
 74        except:
 75            raise ValidationError(self.error_messages['invalid'])
 76        # checksum
 77        key = '279146358279'
 78        checksum = 0
 79        value_iter = iter(value)
 80        for digit in key:
 81            checksum += int(digit) * int(value_iter.next())
 82        checksum %= 11
 83        if checksum == 10:
 84            checksum = 1
 85        if checksum != int(value[12]):
 86            raise ValidationError(self.error_messages['invalid'])
 87        return value
 88
 89class ROCountyField(Field):
 90    """
 91    A form field that validates its input is a Romanian county name or
 92    abbreviation. It normalizes the input to the standard vehicle registration
 93    abbreviation for the given county
 94
 95    WARNING: This field will only accept names written with diacritics; consider
 96    using ROCountySelect if this behavior is unnaceptable for you
 97    Example:
 98        Arge?&#x; => valid
 99        Arges => invalid
100    """
101    default_error_messages = {
102        'invalid': u'Enter a Romanian county code or name.',
103    }
104
105    def clean(self, value):
106        from ro_counties import COUNTIES_CHOICES
107        super(ROCountyField, self).clean(value)
108        if value in EMPTY_VALUES:
109            return u''
110        try:
111            value = value.strip().upper()
112        except AttributeError:
113            pass
114        # search for county code
115        for entry in COUNTIES_CHOICES:
116            if value in entry:
117                return value
118        # search for county name
119        normalized_CC = []
120        for entry in COUNTIES_CHOICES:
121            normalized_CC.append((entry[0],entry[1].upper()))
122        for entry in normalized_CC:
123            if entry[1] == value:
124                return entry[0]
125        raise ValidationError(self.error_messages['invalid'])
126
127class ROCountySelect(Select):
128    """
129    A Select widget that uses a list of Romanian counties (judete) as its
130    choices.
131    """
132    def __init__(self, attrs=None):
133        from ro_counties import COUNTIES_CHOICES
134        super(ROCountySelect, self).__init__(attrs, choices=COUNTIES_CHOICES)
135
136class ROIBANField(RegexField):
137    """
138    Romanian International Bank Account Number (IBAN) field
139
140    For Romanian IBAN validation algorithm see http://validari.ro/iban.html
141    """
142    default_error_messages = {
143        'invalid': _('Enter a valid IBAN in ROXX-XXXX-XXXX-XXXX-XXXX-XXXX format'),
144    }
145
146    def __init__(self, *args, **kwargs):
147        super(ROIBANField, self).__init__(r'^[0-9A-Za-z\-\s]{24,40}$',
148                max_length=40, min_length=24, *args, **kwargs)
149
150    def clean(self, value):
151        """
152        Strips - and spaces, performs country code and checksum validation
153        """
154        value = super(ROIBANField, self).clean(value)
155        if value in EMPTY_VALUES:
156            return u''
157        value = value.replace('-','')
158        value = value.replace(' ','')
159        value = value.upper()
160        if value[0:2] != 'RO':
161            raise ValidationError(self.error_messages['invalid'])
162        numeric_format = ''
163        for char in value[4:] + value[0:4]:
164            if char.isalpha():
165                numeric_format += str(ord(char) - 55)
166            else:
167                numeric_format += char
168        if int(numeric_format) % 97 != 1:
169            raise ValidationError(self.error_messages['invalid'])
170        return value
171
172class ROPhoneNumberField(RegexField):
173    """Romanian phone number field"""
174    default_error_messages = {
175        'invalid': _('Phone numbers must be in XXXX-XXXXXX format.'),
176    }
177
178    def __init__(self, *args, **kwargs):
179        super(ROPhoneNumberField, self).__init__(r'^[0-9\-\(\)\s]{10,20}$',
180                max_length=20, min_length=10, *args, **kwargs)
181
182    def clean(self, value):
183        """
184        Strips -, (, ) and spaces. Checks the final length.
185        """
186        value = super(ROPhoneNumberField, self).clean(value)
187        if value in EMPTY_VALUES:
188            return u''
189        value = value.replace('-','')
190        value = value.replace('(','')
191        value = value.replace(')','')
192        value = value.replace(' ','')
193        if len(value) != 10:
194            raise ValidationError(self.error_messages['invalid'])
195        return value
196
197class ROPostalCodeField(RegexField):
198    """Romanian postal code field."""
199    default_error_messages = {
200        'invalid': _('Enter a valid postal code in the format XXXXXX'),
201    }
202
203    def __init__(self, *args, **kwargs):
204        super(ROPostalCodeField, self).__init__(r'^[0-9][0-8][0-9]{4}$',
205                max_length=6, min_length=6, *args, **kwargs)
206