Fixed #15713 -- Added a form field for validating Polish National ID Card numbers. Thanks, xtrqt.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16116 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-04-28 13:20:33 +00:00
parent 086ab44336
commit 07854d1c44
3 changed files with 88 additions and 8 deletions

View File

@ -44,7 +44,7 @@ class PLPESELField(RegexField):
super(PLPESELField, self).__init__(r'^\d{11}$', super(PLPESELField, self).__init__(r'^\d{11}$',
max_length=None, min_length=None, *args, **kwargs) max_length=None, min_length=None, *args, **kwargs)
def clean(self,value): def clean(self, value):
super(PLPESELField, self).clean(value) super(PLPESELField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
@ -62,6 +62,60 @@ class PLPESELField(RegexField):
result += int(number[i]) * multiple_table[i] result += int(number[i]) * multiple_table[i]
return result % 10 == 0 return result % 10 == 0
class PLNationalIDCardNumberField(RegexField):
"""
A form field that validates as Polish National ID Card Number.
Checks the following rules:
* the length consist of 3 letter and 6 digits
* has a valid checksum
The algorithm is documented at http://en.wikipedia.org/wiki/Polish_identity_card.
"""
default_error_messages = {
'invalid': _(u'National ID Card Number consists of 3 letters and 6 digits.'),
'checksum': _(u'Wrong checksum for the National ID Card Number.'),
}
def __init__(self, *args, **kwargs):
super(PLNationalIDCardNumberField, self).__init__(r'^[A-Za-z]{3}\d{6}$',
max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLNationalIDCardNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
value = value.upper()
if not self.has_valid_checksum(value):
raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
"""
Calculates a checksum with the provided algorithm.
"""
letter_dict = {'A': 10, 'B': 11, 'C': 12, 'D': 13,
'E': 14, 'F': 15, 'G': 16, 'H': 17,
'I': 18, 'J': 19, 'K': 20, 'L': 21,
'M': 22, 'N': 23, 'O': 24, 'P': 25,
'Q': 26, 'R': 27, 'S': 28, 'T': 29,
'U': 30, 'V': 31, 'W': 32, 'X': 33,
'Y': 34, 'Z': 35}
# convert letters to integer values
int_table = [(not c.isdigit()) and letter_dict[c] or int(c)
for c in number]
multiple_table = (7, 3, 1, -1, 7, 3, 1, 7, 3)
result = 0
for i in range(len(int_table)):
result += int_table[i] * multiple_table[i]
return result % 10 == 0
class PLNIPField(RegexField): class PLNIPField(RegexField):
""" """
A form field that validates as Polish Tax Number (NIP). A form field that validates as Polish Tax Number (NIP).
@ -158,3 +212,4 @@ class PLPostalCodeField(RegexField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$', super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
max_length=None, min_length=None, *args, **kwargs) max_length=None, min_length=None, *args, **kwargs)

View File

@ -759,6 +759,17 @@ Poland (``pl``)
.. _PESEL: http://en.wikipedia.org/wiki/PESEL .. _PESEL: http://en.wikipedia.org/wiki/PESEL
.. versionadded:: 1.4
.. class:: pl.forms.PLNationalIDCardNumberField
A form field that validates input as a Polish National ID Card number. The
valid format is AAAXXXXXX, where A is letter (A-Z), X is digit and left-most
digit is checksum digit. More information about checksum calculation algorithm
see `Polish identity card`_.
.. _`Polish identity card`: http://en.wikipedia.org/wiki/Polish_identity_card
.. class:: pl.forms.PLREGONField .. class:: pl.forms.PLREGONField
A form field that validates input as a Polish National Official Business A form field that validates input as a Polish National Official Business

View File

@ -1,5 +1,5 @@
from django.contrib.localflavor.pl.forms import (PLProvinceSelect, from django.contrib.localflavor.pl.forms import (PLProvinceSelect,
PLCountySelect, PLPostalCodeField, PLNIPField, PLPESELField, PLREGONField) PLCountySelect, PLPostalCodeField, PLNIPField, PLPESELField, PLNationalIDCardNumberField, PLREGONField)
from utils import LocalFlavorTestCase from utils import LocalFlavorTestCase
@ -26,7 +26,7 @@ class PLLocalFlavorTests(LocalFlavorTestCase):
<option value="west_pomerania">West Pomerania</option> <option value="west_pomerania">West Pomerania</option>
</select>''' </select>'''
self.assertEqual(f.render('voivodeships', 'pomerania'), out) self.assertEqual(f.render('voivodeships', 'pomerania'), out)
def test_PLCountrySelect(self): def test_PLCountrySelect(self):
f = PLCountySelect() f = PLCountySelect()
out = u'''<select name="administrativeunit"> out = u'''<select name="administrativeunit">
@ -408,7 +408,7 @@ class PLLocalFlavorTests(LocalFlavorTestCase):
<option value="walecki">wa\u0142ecki</option> <option value="walecki">wa\u0142ecki</option>
</select>''' </select>'''
self.assertEqual(f.render('administrativeunit', 'katowice'), out) self.assertEqual(f.render('administrativeunit', 'katowice'), out)
def test_PLPostalCodeField(self): def test_PLPostalCodeField(self):
error_format = [u'Enter a postal code in the format XX-XXX.'] error_format = [u'Enter a postal code in the format XX-XXX.']
valid = { valid = {
@ -418,7 +418,7 @@ class PLLocalFlavorTests(LocalFlavorTestCase):
'43--434': error_format, '43--434': error_format,
} }
self.assertFieldOutput(PLPostalCodeField, valid, invalid) self.assertFieldOutput(PLPostalCodeField, valid, invalid)
def test_PLNIPField(self): def test_PLNIPField(self):
error_format = [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'] error_format = [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
error_checksum = [u'Wrong checksum for the Tax Number (NIP).'] error_checksum = [u'Wrong checksum for the Tax Number (NIP).']
@ -431,7 +431,7 @@ class PLLocalFlavorTests(LocalFlavorTestCase):
'646-241-41-23': error_checksum, '646-241-41-23': error_checksum,
} }
self.assertFieldOutput(PLNIPField, valid, invalid) self.assertFieldOutput(PLNIPField, valid, invalid)
def test_PLPESELField(self): def test_PLPESELField(self):
error_checksum = [u'Wrong checksum for the National Identification Number.'] error_checksum = [u'Wrong checksum for the National Identification Number.']
error_format = [u'National Identification Number consists of 11 digits.'] error_format = [u'National Identification Number consists of 11 digits.']
@ -444,7 +444,22 @@ class PLLocalFlavorTests(LocalFlavorTestCase):
'800716106AA': error_format, '800716106AA': error_format,
} }
self.assertFieldOutput(PLPESELField, valid, invalid) self.assertFieldOutput(PLPESELField, valid, invalid)
def test_PLNationalIDCardNumberField(self):
error_checksum = [u'Wrong checksum for the National ID Card Number.']
error_format = [u'National ID Card Number consists of 3 letters and 6 digits.']
valid = {
'ABC123458': 'ABC123458',
'abc123458': 'ABC123458',
}
invalid = {
'ABC123457': error_checksum,
'abc123457': error_checksum,
'a12Aaaaaa': error_format,
'AA1234443': error_format,
}
self.assertFieldOutput(PLNationalIDCardNumberField, valid, invalid)
def test_PLREGONField(self): def test_PLREGONField(self):
error_checksum = [u'Wrong checksum for the National Business Register Number (REGON).'] error_checksum = [u'Wrong checksum for the National Business Register Number (REGON).']
error_format = [u'National Business Register Number (REGON) consists of 9 or 14 digits.'] error_format = [u'National Business Register Number (REGON) consists of 9 or 14 digits.']
@ -459,4 +474,3 @@ class PLLocalFlavorTests(LocalFlavorTestCase):
'590096': error_format, '590096': error_format,
} }
self.assertFieldOutput(PLREGONField, valid, invalid) self.assertFieldOutput(PLREGONField, valid, invalid)