Ticket #8273: localflavor-numberwithchecksumfield.patch
File localflavor-numberwithchecksumfield.patch, 19.6 KB (added by , 16 years ago) |
---|
-
django/contrib/localflavor/ar/forms.py
3 3 AR-specific Form helpers. 4 4 """ 5 5 6 from django.contrib.localflavor.generic.forms import NumberWithChecksumField 6 7 from django.forms import ValidationError 7 8 from django.forms.fields import RegexField, CharField, Select, EMPTY_VALUES 8 9 from django.utils.encoding import smart_unicode … … 70 71 71 72 return value 72 73 73 class ARCUITField( RegexField):74 class ARCUITField(NumberWithChecksumField): 74 75 """ 75 76 This field validates a CUIT (Código Único de Identificación Tributaria). A 76 77 CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit. 77 78 """ 78 default_error_messages = {79 'invalid': _('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),80 'checksum': _("Invalid CUIT."),81 }82 79 83 def __init__(self, *args, **kwargs): 84 super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$', 85 *args, **kwargs) 80 weights = ((5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 0),) 86 81 87 def clean(self, value): 88 """ 89 Value can be either a string in the format XX-XXXXXXXX-X or an 90 11-digit number. 91 """ 92 value = super(ARCUITField, self).clean(value) 93 if value in EMPTY_VALUES: 94 return u'' 95 value, cd = self._canon(value) 96 if self._calc_cd(value) != cd: 97 raise ValidationError(self.error_messages['checksum']) 98 return self._format(value, cd) 82 def format(self, digits, value): 83 return '-'.join([digits[:2], digits[2:-1], digits[-1:]]) 99 84 100 def _canon(self, cuit): 101 cuit = cuit.replace('-', '') 102 return cuit[:-1], cuit[-1] 103 104 def _calc_cd(self, cuit): 105 mults = (5, 4, 3, 2, 7, 6, 5, 4, 3, 2) 106 tmp = sum([m * int(cuit[idx]) for idx, m in enumerate(mults)]) 107 return str(11 - tmp % 11) 108 109 def _format(self, cuit, check_digit=None): 110 if check_digit == None: 111 check_digit = cuit[-1] 112 cuit = cuit[:-1] 113 return u'%s-%s-%s' % (cuit[:2], cuit[2:], check_digit) 114 85 def verify(self, checksum, digits): 86 return 11 - checksum % 11 == digits[-1] -
django/contrib/localflavor/br/forms.py
3 3 BR-specific Form helpers 4 4 """ 5 5 6 from django.contrib.localflavor.generic.forms import NumberWithChecksumField 6 7 from django.forms import ValidationError 7 8 from django.forms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES 8 9 from django.utils.encoding import smart_unicode -
django/contrib/localflavor/at/forms.py
4 4 5 5 import re 6 6 7 from django.contrib.localflavor.generic.forms import NumberWithChecksumField 7 8 from django.utils.translation import ugettext_lazy as _ 8 9 from django.forms.fields import Field, RegexField, Select 9 10 from django.forms import ValidationError … … 31 32 from django.contrib.localflavor.at.at_states import STATE_CHOICES 32 33 super(ATStateSelect, self).__init__(attrs, choices=STATE_CHOICES) 33 34 34 class ATSocialSecurityNumberField( Field):35 class ATSocialSecurityNumberField(NumberWithChecksumField): 35 36 """ 36 37 Austrian Social Security numbers are composed of a 4 digits and 6 digits 37 38 field. The latter represents in most cases the person's birthdate while … … 44 45 http://de.wikipedia.org/wiki/Sozialversicherungsnummer#.C3.96sterreich 45 46 """ 46 47 47 default_error_messages = { 48 'invalid': _(u'Enter a valid Austrian Social Security Number in XXXX XXXXXX format.'), 49 } 48 weights = ((3, 7, 9, -1, 5, 8, 4, 2, 1, 6)), 50 49 51 def clean(self, value): 52 if not re_ssn.search(value): 53 raise ValidationError(self.error_messages['invalid']) 54 sqnr, date = value.split(" ") 55 sqnr, check = (sqnr[:3], (sqnr[3])) 56 if int(sqnr) < 100: 57 raise ValidationError(self.error_messages['invalid']) 58 res = int(sqnr[0])*3 + int(sqnr[1])*7 + int(sqnr[2])*9 \ 59 + int(date[0])*5 + int(date[1])*8 + int(date[2])*4 \ 60 + int(date[3])*2 + int(date[4])*1 + int(date[5])*6 61 res = res % 11 62 if res != int(check): 63 raise ValidationError(self.error_messages['invalid']) 64 return u'%s%s %s'%(sqnr, check, date,) 65 50 def format(self, digits, value): 51 return u'%s %s' % (digits[:4], digits[4:]) -
django/contrib/localflavor/pl/forms.py
7 7 from django.forms import ValidationError 8 8 from django.forms.fields import Select, RegexField 9 9 from django.utils.translation import ugettext_lazy as _ 10 from django.contrib.localflavor.generic.forms import NumberWithChecksumField 10 11 11 12 class PLVoivodeshipSelect(Select): 12 13 """ … … 25 26 from pl_administrativeunits import ADMINISTRATIVE_UNIT_CHOICES 26 27 super(PLAdministrativeUnitSelect, self).__init__(attrs, choices=ADMINISTRATIVE_UNIT_CHOICES) 27 28 28 class PLNationalIdentificationNumberField( RegexField):29 class PLNationalIdentificationNumberField(NumberWithChecksumField): 29 30 """ 30 31 A form field that validates as Polish Identification Number (PESEL). 31 32 … … 35 36 36 37 The algorithm is documented at http://en.wikipedia.org/wiki/PESEL. 37 38 """ 38 default_error_messages = { 39 'invalid': _(u'National Identification Number consists of 11 digits.'), 40 'checksum': _(u'Wrong checksum for the National Identification Number.'), 41 } 39 weights = ((1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1),) 42 40 43 def __init__(self, *args, **kwargs):44 super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',45 max_length=None, min_length=None,*args, **kwargs)41 def verify(self, *args, **kwargs): 42 kwargs['modulo'] = 10 43 return super(PLNationalIdentificationNumberField, self).verify(*args, **kwargs) 46 44 47 def clean(self,value): 48 super(PLNationalIdentificationNumberField, self).clean(value) 49 if not self.has_valid_checksum(value): 50 raise ValidationError(self.error_messages['checksum']) 51 return u'%s' % value 52 53 def has_valid_checksum(self, number): 54 """ 55 Calculates a checksum with the provided algorithm. 56 """ 57 multiple_table = (1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1) 58 result = 0 59 for i in range(len(number)): 60 result += int(number[i]) * multiple_table[i] 61 return result % 10 == 0 62 63 class PLTaxNumberField(RegexField): 45 class PLTaxNumberField(NumberWithChecksumField): 64 46 """ 65 47 A form field that validates as Polish Tax Number (NIP). 66 48 Valid forms are: XXX-XXX-YY-YY or XX-XX-YYY-YYY. … … 68 50 Checksum algorithm based on documentation at 69 51 http://wipos.p.lodz.pl/zylla/ut/nip-rego.html 70 52 """ 71 default_error_messages = { 72 'invalid': _(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), 73 'checksum': _(u'Wrong checksum for the Tax Number (NIP).'), 74 } 53 weights = ((6, 5, 7, 2, 3, 4, 5, 6, 7, -1),) 75 54 76 def __init__(self, *args, **kwargs):77 super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',78 max_length=None, min_length=None, *args, **kwargs)79 55 80 def clean(self,value): 81 super(PLTaxNumberField, self).clean(value) 82 value = re.sub("[-]", "", value) 83 if not self.has_valid_checksum(value): 84 raise ValidationError(self.error_messages['checksum']) 85 return u'%s' % value 86 87 def has_valid_checksum(self, number): 88 """ 89 Calculates a checksum with the provided algorithm. 90 """ 91 multiple_table = (6, 5, 7, 2, 3, 4, 5, 6, 7) 92 result = 0 93 for i in range(len(number)-1): 94 result += int(number[i]) * multiple_table[i] 95 96 result %= 11 97 if result == int(number[-1]): 98 return True 99 else: 100 return False 101 102 class PLNationalBusinessRegisterField(RegexField): 56 class PLNationalBusinessRegisterField(NumberWithChecksumField): 103 57 """ 104 58 A form field that validated as Polish National Official Business Register Number (REGON) 105 59 Valid forms are: 7 or 9 digits number … … 108 62 109 63 The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html 110 64 """ 111 default_error_messages = { 112 'invalid': _(u'National Business Register Number (REGON) consists of 7 or 9 digits.'), 113 'checksum': _(u'Wrong checksum for the National Business Register Number (REGON).'), 114 } 65 weights = ( 66 (2, 3, 4, 5, 6, 7, -1), 67 (8, 9, 2, 3, 4, 5, 6, 7, -1), 68 (2, 4, 8, 5, 0, 9, 7, 3, 6, 1, 2, 4, 8, -1), 69 ) 115 70 116 def __init__(self, *args, **kwargs):117 super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$',118 max_length=None, min_length=None, *args, **kwargs)119 120 def clean(self,value):121 super(PLNationalBusinessRegisterField, self).clean(value)122 if not self.has_valid_checksum(value):123 raise ValidationError(self.error_messages['checksum'])124 return u'%s' % value125 126 def has_valid_checksum(self, number):127 """128 Calculates a checksum with the provided algorithm.129 """130 multiple_table_7 = (2, 3, 4, 5, 6, 7)131 multiple_table_9 = (8, 9, 2, 3, 4, 5, 6, 7)132 result = 0133 134 if len(number) == 7:135 multiple_table = multiple_table_7136 else:137 multiple_table = multiple_table_9138 139 for i in range(len(number)-1):140 result += int(number[i]) * multiple_table[i]141 142 result %= 11143 if result == 10:144 result = 0145 if result == int(number[-1]):146 return True147 else:148 return False149 150 71 class PLPostalCodeField(RegexField): 151 72 """ 152 73 A form field that validates as Polish postal code. -
django/contrib/localflavor/generic/forms.py
1 1 from django import forms 2 from django.utils.translation import ugettext_lazy, ungettext_lazy 3 from itertools import izip 4 import re 2 5 3 6 DEFAULT_DATE_INPUT_FORMATS = ( 4 7 '%Y-%m-%d', '%d/%m/%Y', '%d/%m/%y', # '2006-10-25', '25/10/2006', '25/10/06' … … 36 39 def __init__(self, input_formats=None, *args, **kwargs): 37 40 input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS 38 41 super(DateTimeField, self).__init__(input_formats=input_formats, *args, **kwargs) 42 43 class NumberWithChecksumField(forms.Field): 44 """ 45 A number input field which verifies checksum using provided weights. 46 """ 47 48 def __init__(self, *args, **kwargs): 49 msg_data = dict( 50 number = len(self.weights[-1]) 51 ) 52 if len(self.weights) == 1: 53 errmsg = ungettext_lazy( 54 'This field requires %(number)d digits.', 55 'This field requires %(number)d digits.', 56 msg_data['number'] 57 ) % msg_data 58 else: 59 msg_data['numbers'] = ', '.join([ 60 str(len(set_)) for set_ in self.weights[:-1] 61 ]) 62 errmsg = ungettext_lazy( 63 'This field requires %(numbers)s or %(number)d digits.', 64 'This field requires %(numbers)s or %(number)d digits.', 65 msg_data['number'] 66 ) % msg_data 67 error_messages = kwargs.setdefault('error_messages', {}) 68 error_messages.setdefault('invalid', errmsg) 69 error_messages.setdefault('checksum', ugettext_lazy('This value has invalid checksum.')) 70 super(NumberWithChecksumField, self).__init__(*args, **kwargs) 71 72 def verify(self, checksum, digits, modulo = 11): 73 """ 74 Verifies whether the provided checksum if correct. 75 """ 76 return checksum % modulo % 10 == 0 77 78 def format(self, digits, value): 79 """ 80 Normalizes cleaned value. 81 """ 82 return digits 83 84 def get_digits(self, value): 85 """ 86 Extracts digits from provided value. 87 """ 88 digits = re.sub(r'[^0-9]', '', value) 89 return [int(i) for i in digits] 90 91 def calculate_checksum(self, digits, weights): 92 return sum([v * w for v, w in izip(digits, weights)]) 93 94 def clean(self, value): 95 value = super(NumberWithChecksumField, self).clean(value) 96 if value in forms.fields.EMPTY_VALUES: 97 return u'' 98 digits = self.get_digits(value) 99 for weights in self.weights: 100 if len(digits) != len(weights): 101 continue 102 checksum = self.calculate_checksum(digits, weights) 103 if not self.verify(checksum, digits): 104 raise forms.ValidationError(self.error_messages['checksum']) 105 number = u''.join([str(n) for n in digits]) 106 value = self.format(number, value) 107 return value 108 else: 109 raise forms.ValidationError(self.error_messages['invalid']) -
tests/regressiontests/forms/localflavor/ar.py
200 200 >>> f.clean('2-10123456-9') 201 201 Traceback (most recent call last): 202 202 ... 203 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']203 ValidationError: [u'This field requires 11 digits.'] 204 204 >>> f.clean('210123456-9') 205 205 Traceback (most recent call last): 206 206 ... 207 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']207 ValidationError: [u'This field requires 11 digits.'] 208 208 >>> f.clean('20-10123456') 209 209 Traceback (most recent call last): 210 210 ... 211 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']211 ValidationError: [u'This field requires 11 digits.'] 212 212 >>> f.clean('20-10123456-') 213 213 Traceback (most recent call last): 214 214 ... 215 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']215 ValidationError: [u'This field requires 11 digits.'] 216 216 >>> f.clean('20-10123456-5') 217 217 Traceback (most recent call last): 218 218 ... 219 ValidationError: [u' Invalid CUIT.']219 ValidationError: [u'This value has invalid checksum.'] 220 220 >>> f.clean(u'2-10123456-9') 221 221 Traceback (most recent call last): 222 222 ... 223 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']223 ValidationError: [u'This field requires 11 digits.'] 224 224 >>> f.clean('27-10345678-1') 225 225 Traceback (most recent call last): 226 226 ... 227 ValidationError: [u' Invalid CUIT.']227 ValidationError: [u'This value has invalid checksum.'] 228 228 >>> f.clean(u'27-10345678-1') 229 229 Traceback (most recent call last): 230 230 ... 231 ValidationError: [u' Invalid CUIT.']231 ValidationError: [u'This value has invalid checksum.'] 232 232 >>> f.clean(None) 233 233 Traceback (most recent call last): 234 234 ... … … 256 256 >>> f.clean('2-10123456-9') 257 257 Traceback (most recent call last): 258 258 ... 259 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']259 ValidationError: [u'This field requires 11 digits.'] 260 260 >>> f.clean('210123456-9') 261 261 Traceback (most recent call last): 262 262 ... 263 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']263 ValidationError: [u'This field requires 11 digits.'] 264 264 >>> f.clean('20-10123456') 265 265 Traceback (most recent call last): 266 266 ... 267 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']267 ValidationError: [u'This field requires 11 digits.'] 268 268 >>> f.clean('20-10123456-') 269 269 Traceback (most recent call last): 270 270 ... 271 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']271 ValidationError: [u'This field requires 11 digits.'] 272 272 >>> f.clean('20-10123456-5') 273 273 Traceback (most recent call last): 274 274 ... 275 ValidationError: [u' Invalid CUIT.']275 ValidationError: [u'This value has invalid checksum.'] 276 276 >>> f.clean(u'2-10123456-9') 277 277 Traceback (most recent call last): 278 278 ... 279 ValidationError: [u' Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']279 ValidationError: [u'This field requires 11 digits.'] 280 280 >>> f.clean('27-10345678-1') 281 281 Traceback (most recent call last): 282 282 ... 283 ValidationError: [u' Invalid CUIT.']283 ValidationError: [u'This value has invalid checksum.'] 284 284 >>> f.clean(u'27-10345678-1') 285 285 Traceback (most recent call last): 286 286 ... 287 ValidationError: [u' Invalid CUIT.']287 ValidationError: [u'This value has invalid checksum.'] 288 288 >>> f.clean(None) 289 289 u'' 290 290 >>> f.clean('') -
tests/regressiontests/forms/localflavor/at.py
72 72 >>> f.clean('1237 010181') 73 73 Traceback (most recent call last): 74 74 ... 75 ValidationError: [u' Enter a valid Austrian Social Security Number in XXXX XXXXXX format.']75 ValidationError: [u'This value has invalid checksum.'] 76 76 >>> f.clean('12370 010180') 77 77 Traceback (most recent call last): 78 78 ... 79 ValidationError: [u' Enter a valid Austrian Social Security Number in XXXX XXXXXX format.']79 ValidationError: [u'This field requires 10 digits.'] 80 80 """ -
tests/regressiontests/forms/localflavor/pl.py
34 34 >>> f.clean('43-343-234-323') 35 35 Traceback (most recent call last): 36 36 ... 37 ValidationError: [u' Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']37 ValidationError: [u'This field requires 10 digits.'] 38 38 >>> f.clean('64-62-414-124') 39 39 u'6462414124' 40 40 >>> f.clean('646-241-41-24') … … 42 42 >>> f.clean('646-241-41-23') 43 43 Traceback (most recent call last): 44 44 ... 45 ValidationError: [u' Wrong checksum for the Tax Number (NIP).']45 ValidationError: [u'This value has invalid checksum.'] 46 46 47 47 # PLNationalIdentificationNumberField ############################################ 48 48 … … 53 53 >>> f.clean('80071610610') 54 54 Traceback (most recent call last): 55 55 ... 56 ValidationError: [u' Wrong checksum for the National Identification Number.']56 ValidationError: [u'This value has invalid checksum.'] 57 57 >>> f.clean('80') 58 58 Traceback (most recent call last): 59 59 ... 60 ValidationError: [u' National Identification Number consists of11 digits.']60 ValidationError: [u'This field requires 11 digits.'] 61 61 >>> f.clean('800716106AA') 62 62 Traceback (most recent call last): 63 63 ... 64 ValidationError: [u' National Identification Number consists of11 digits.']64 ValidationError: [u'This field requires 11 digits.'] 65 65 66 66 # PLNationalBusinessRegisterField ################################################ 67 67 … … 72 72 >>> f.clean('590096453') 73 73 Traceback (most recent call last): 74 74 ... 75 ValidationError: [u' Wrong checksum for the National Business Register Number (REGON).']75 ValidationError: [u'This value has invalid checksum.'] 76 76 >>> f.clean('590096') 77 77 Traceback (most recent call last): 78 78 ... 79 ValidationError: [u' National Business Register Number (REGON) consists of 7 or 9digits.']79 ValidationError: [u'This field requires 7, 9 or 14 digits.'] 80 80 81 81 """