62 lines
1.9 KiB
Python
62 lines
1.9 KiB
Python
|
"""
|
||
|
Kuwait-specific Form helpers
|
||
|
"""
|
||
|
import re
|
||
|
from datetime import date
|
||
|
from django.forms import ValidationError
|
||
|
from django.forms.fields import Field, RegexField, EMPTY_VALUES
|
||
|
from django.utils.translation import gettext as _
|
||
|
|
||
|
id_re = re.compile(r'^(?P<initial>\d{1})(?P<yy>\d\d)(?P<mm>\d\d)(?P<dd>\d\d)(?P<mid>\d{4})(?P<checksum>\d{1})')
|
||
|
|
||
|
class KWCivilIDNumberField(Field):
|
||
|
"""
|
||
|
Kuwaiti Civil ID numbers are 12 digits, second to seventh digits
|
||
|
represents the person's birthdate.
|
||
|
|
||
|
Checks the following rules to determine the validty of the number:
|
||
|
* The number consist of 12 digits.
|
||
|
* The birthdate of the person is a valid date.
|
||
|
* The calculated checksum equals to the last digit of the Civil ID.
|
||
|
"""
|
||
|
default_error_messages = {
|
||
|
'invalid': _('Enter a valid Kuwaiti Civil ID number'),
|
||
|
}
|
||
|
|
||
|
def has_valid_checksum(self, value):
|
||
|
weight = (2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
|
||
|
calculated_checksum = 0
|
||
|
for i in range(11):
|
||
|
calculated_checksum += int(value[i]) * weight[i]
|
||
|
|
||
|
remainder = calculated_checksum % 11
|
||
|
checkdigit = 11 - remainder
|
||
|
if checkdigit != int(value[11]):
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
def clean(self, value):
|
||
|
super(KWCivilIDNumberField, self).clean(value)
|
||
|
if value in EMPTY_VALUES:
|
||
|
return u''
|
||
|
|
||
|
if not re.match(r'^\d{12}$', value):
|
||
|
raise ValidationError(self.error_messages['invalid'])
|
||
|
|
||
|
match = re.match(id_re, value)
|
||
|
|
||
|
if not match:
|
||
|
raise ValidationError(self.error_messages['invalid'])
|
||
|
|
||
|
gd = match.groupdict()
|
||
|
|
||
|
try:
|
||
|
d = date(int(gd['yy']), int(gd['mm']), int(gd['dd']))
|
||
|
except ValueError:
|
||
|
raise ValidationError(self.error_messages['invalid'])
|
||
|
|
||
|
if not self.has_valid_checksum(value):
|
||
|
raise ValidationError(self.error_messages['invalid'])
|
||
|
|
||
|
return value
|