/django/contrib/localflavor/ro/forms.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