web/lib/django/contrib/localflavor/kw/forms.py
changeset 29 cc9b7e14412b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/lib/django/contrib/localflavor/kw/forms.py	Tue May 25 02:43:45 2010 +0200
@@ -0,0 +1,63 @@
+"""
+Kuwait-specific Form helpers
+"""
+import re
+from datetime import date
+
+from django.core.validators import EMPTY_VALUES
+from django.forms import ValidationError
+from django.forms.fields import Field, RegexField
+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