From fb5976cf4cb203165a785d3c3b6f210ef29f110f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sa=C5=82aban?= Date: Mon, 11 Jul 2016 19:22:05 +0200 Subject: [PATCH] Add birth date check to PESEL validation --- localflavor/pl/forms.py | 26 ++++++++++++++++++++++++++ tests/test_pl.py | 2 ++ 2 files changed, 28 insertions(+) diff --git a/localflavor/pl/forms.py b/localflavor/pl/forms.py index 00920ac4..16a60319 100644 --- a/localflavor/pl/forms.py +++ b/localflavor/pl/forms.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals +import datetime import re from django.core.validators import EMPTY_VALUES @@ -38,12 +39,16 @@ class PLPESELField(RegexField): Checks the following rules: * the length consist of 11 digits * has a valid checksum + * contains a valid birth date The algorithm is documented at http://en.wikipedia.org/wiki/PESEL. + + .. versionchanged:: 1.4 """ default_error_messages = { 'invalid': _('National Identification Number consists of 11 digits.'), 'checksum': _('Wrong checksum for the National Identification Number.'), + 'birthdate': _('The National Identification Number contains an invalid birth date.'), } def __init__(self, max_length=None, min_length=None, *args, **kwargs): @@ -56,6 +61,8 @@ def clean(self, value): return '' if not self.has_valid_checksum(value): raise ValidationError(self.error_messages['checksum']) + if not self.has_valid_birth_date(value): + raise ValidationError(self.error_messages['birthdate']) return '%s' % value def has_valid_checksum(self, number): @@ -68,6 +75,25 @@ def has_valid_checksum(self, number): result += int(number[i]) * multiple_table[i] return result % 10 == 0 + def has_valid_birth_date(self, number): + """ + Checks whether the birth date encoded in PESEL is valid. + """ + y = int(number[:2]) + m = int(number[2:4]) + d = int(number[4:6]) + md2century = {80: 1800, 0: 1900, 20: 2000, 40: 2100, 60: 2200} + for md, cent in md2century.items(): + if 1 <= m - md <= 12: + y += cent + m -= md + break + try: + self.birth_date = datetime.date(y, m, d) + return True + except ValueError: + return False + class PLNationalIDCardNumberField(RegexField): """ diff --git a/tests/test_pl.py b/tests/test_pl.py index 19eb601c..53a850c4 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -439,6 +439,7 @@ def test_PLNIPField(self): def test_PLPESELField(self): error_checksum = ['Wrong checksum for the National Identification Number.'] error_format = ['National Identification Number consists of 11 digits.'] + error_birthdate = ['The National Identification Number contains an invalid birth date.'] valid = { '80071610614': '80071610614', } @@ -446,6 +447,7 @@ def test_PLPESELField(self): '80071610610': error_checksum, '80': error_format, '800716106AA': error_format, + '98765432121': error_birthdate, } self.assertFieldOutput(PLPESELField, valid, invalid)