Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
  • Loading branch information...
commit 07854d1c44fcf1243afeec087f31651fd5c2264b 1 parent 086ab44
Jannis Leidel authored April 28, 2011
57  django/contrib/localflavor/pl/forms.py
@@ -44,7 +44,7 @@ def __init__(self, *args, **kwargs):
44 44
         super(PLPESELField, self).__init__(r'^\d{11}$',
45 45
             max_length=None, min_length=None, *args, **kwargs)
46 46
 
47  
-    def clean(self,value):
  47
+    def clean(self, value):
48 48
         super(PLPESELField, self).clean(value)
49 49
         if value in EMPTY_VALUES:
50 50
             return u''
@@ -62,6 +62,60 @@ def has_valid_checksum(self, number):
62 62
             result += int(number[i]) * multiple_table[i]
63 63
         return result % 10 == 0
64 64
 
  65
+class PLNationalIDCardNumberField(RegexField):
  66
+    """
  67
+    A form field that validates as Polish National ID Card Number.
  68
+
  69
+    Checks the following rules:
  70
+        * the length consist of 3 letter and 6 digits
  71
+        * has a valid checksum
  72
+
  73
+    The algorithm is documented at http://en.wikipedia.org/wiki/Polish_identity_card.
  74
+    """
  75
+    default_error_messages = {
  76
+        'invalid': _(u'National ID Card Number consists of 3 letters and 6 digits.'),
  77
+        'checksum': _(u'Wrong checksum for the National ID Card Number.'),
  78
+    }
  79
+
  80
+    def __init__(self, *args, **kwargs):
  81
+        super(PLNationalIDCardNumberField, self).__init__(r'^[A-Za-z]{3}\d{6}$',
  82
+            max_length=None, min_length=None, *args, **kwargs)
  83
+
  84
+    def clean(self,value):
  85
+        super(PLNationalIDCardNumberField, self).clean(value)
  86
+        if value in EMPTY_VALUES:
  87
+            return u''
  88
+
  89
+        value = value.upper()
  90
+
  91
+        if not self.has_valid_checksum(value):
  92
+            raise ValidationError(self.error_messages['checksum'])
  93
+        return u'%s' % value
  94
+
  95
+    def has_valid_checksum(self, number):
  96
+        """
  97
+        Calculates a checksum with the provided algorithm.
  98
+        """
  99
+        letter_dict = {'A': 10, 'B': 11, 'C': 12, 'D': 13,
  100
+                       'E': 14, 'F': 15, 'G': 16, 'H': 17,
  101
+                       'I': 18, 'J': 19, 'K': 20, 'L': 21,
  102
+                       'M': 22, 'N': 23, 'O': 24, 'P': 25,
  103
+                       'Q': 26, 'R': 27, 'S': 28, 'T': 29,
  104
+                       'U': 30, 'V': 31, 'W': 32, 'X': 33,
  105
+                       'Y': 34, 'Z': 35}
  106
+
  107
+        # convert letters to integer values
  108
+        int_table = [(not c.isdigit()) and letter_dict[c] or int(c)
  109
+                     for c in number]
  110
+
  111
+        multiple_table = (7, 3, 1, -1, 7, 3, 1, 7, 3)
  112
+        result = 0
  113
+        for i in range(len(int_table)):
  114
+            result += int_table[i] * multiple_table[i]
  115
+
  116
+        return result % 10 == 0
  117
+
  118
+
65 119
 class PLNIPField(RegexField):
66 120
     """
67 121
     A form field that validates as Polish Tax Number (NIP).
@@ -158,3 +212,4 @@ class PLPostalCodeField(RegexField):
158 212
     def __init__(self, *args, **kwargs):
159 213
         super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
160 214
             max_length=None, min_length=None, *args, **kwargs)
  215
+
11  docs/ref/contrib/localflavor.txt
@@ -759,6 +759,17 @@ Poland (``pl``)
759 759
 
760 760
 .. _PESEL: http://en.wikipedia.org/wiki/PESEL
761 761
 
  762
+.. versionadded:: 1.4
  763
+
  764
+.. class:: pl.forms.PLNationalIDCardNumberField
  765
+
  766
+    A form field that validates input as a Polish National ID Card number. The
  767
+    valid format is AAAXXXXXX, where A is letter (A-Z), X is digit and left-most
  768
+    digit is checksum digit. More information about checksum calculation algorithm
  769
+    see `Polish identity card`_.
  770
+
  771
+.. _`Polish identity card`: http://en.wikipedia.org/wiki/Polish_identity_card
  772
+
762 773
 .. class:: pl.forms.PLREGONField
763 774
 
764 775
     A form field that validates input as a Polish National Official Business
28  tests/regressiontests/forms/localflavor/pl.py
... ...
@@ -1,5 +1,5 @@
1 1
 from django.contrib.localflavor.pl.forms import (PLProvinceSelect,
2  
-    PLCountySelect, PLPostalCodeField, PLNIPField, PLPESELField, PLREGONField)
  2
+    PLCountySelect, PLPostalCodeField, PLNIPField, PLPESELField, PLNationalIDCardNumberField, PLREGONField)
3 3
 
4 4
 from utils import LocalFlavorTestCase
5 5
 
@@ -26,7 +26,7 @@ def test_PLProvinceSelect(self):
26 26
 <option value="west_pomerania">West Pomerania</option>
27 27
 </select>'''
28 28
         self.assertEqual(f.render('voivodeships', 'pomerania'), out)
29  
-    
  29
+
30 30
     def test_PLCountrySelect(self):
31 31
         f = PLCountySelect()
32 32
         out = u'''<select name="administrativeunit">
@@ -408,7 +408,7 @@ def test_PLCountrySelect(self):
408 408
 <option value="walecki">wa\u0142ecki</option>
409 409
 </select>'''
410 410
         self.assertEqual(f.render('administrativeunit', 'katowice'), out)
411  
-    
  411
+
412 412
     def test_PLPostalCodeField(self):
413 413
         error_format = [u'Enter a postal code in the format XX-XXX.']
414 414
         valid = {
@@ -418,7 +418,7 @@ def test_PLPostalCodeField(self):
418 418
             '43--434': error_format,
419 419
         }
420 420
         self.assertFieldOutput(PLPostalCodeField, valid, invalid)
421  
-    
  421
+
422 422
     def test_PLNIPField(self):
423 423
         error_format = [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
424 424
         error_checksum = [u'Wrong checksum for the Tax Number (NIP).']
@@ -431,7 +431,7 @@ def test_PLNIPField(self):
431 431
             '646-241-41-23': error_checksum,
432 432
         }
433 433
         self.assertFieldOutput(PLNIPField, valid, invalid)
434  
-    
  434
+
435 435
     def test_PLPESELField(self):
436 436
         error_checksum = [u'Wrong checksum for the National Identification Number.']
437 437
         error_format = [u'National Identification Number consists of 11 digits.']
@@ -444,7 +444,22 @@ def test_PLPESELField(self):
444 444
             '800716106AA': error_format,
445 445
         }
446 446
         self.assertFieldOutput(PLPESELField, valid, invalid)
447  
-    
  447
+
  448
+    def test_PLNationalIDCardNumberField(self):
  449
+        error_checksum = [u'Wrong checksum for the National ID Card Number.']
  450
+        error_format = [u'National ID Card Number consists of 3 letters and 6 digits.']
  451
+        valid = {
  452
+            'ABC123458': 'ABC123458',
  453
+            'abc123458': 'ABC123458',
  454
+        }
  455
+        invalid = {
  456
+            'ABC123457': error_checksum,
  457
+            'abc123457': error_checksum,
  458
+            'a12Aaaaaa': error_format,
  459
+            'AA1234443': error_format,
  460
+        }
  461
+        self.assertFieldOutput(PLNationalIDCardNumberField, valid, invalid)
  462
+
448 463
     def test_PLREGONField(self):
449 464
         error_checksum = [u'Wrong checksum for the National Business Register Number (REGON).']
450 465
         error_format = [u'National Business Register Number (REGON) consists of 9 or 14 digits.']
@@ -459,4 +474,3 @@ def test_PLREGONField(self):
459 474
             '590096': error_format,
460 475
         }
461 476
         self.assertFieldOutput(PLREGONField, valid, invalid)
462  
-

0 notes on commit 07854d1

Please sign in to comment.
Something went wrong with that request. Please try again.