app/django/contrib/localflavor/za/forms.py
author Mario Ferraro <fadinlight@gmail.com>
Sun, 15 Nov 2009 22:12:20 +0100
changeset 3093 d1be59b6b627
parent 323 ff1a9aa48cfd
permissions -rw-r--r--
GMaps related JS changed to use new google namespace. Google is going to change permanently in the future the way to load its services, so better stay safe. Also this commit shows uses of the new melange.js module. Fixes Issue 634.

"""
South Africa-specific Form helpers
"""

from django.forms import ValidationError
from django.forms.fields import Field, RegexField, EMPTY_VALUES
from django.utils.checksums import luhn
from django.utils.translation import gettext as _
import re
from datetime import date

id_re = re.compile(r'^(?P<yy>\d\d)(?P<mm>\d\d)(?P<dd>\d\d)(?P<mid>\d{4})(?P<end>\d{3})')

class ZAIDField(Field):
    """A form field for South African ID numbers -- the checksum is validated
    using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
    check for the birthdate
    """
    default_error_messages = {
        'invalid': _(u'Enter a valid South African ID number'),
    }

    def clean(self, value):
        # strip spaces and dashes
        value = value.strip().replace(' ', '').replace('-', '')

        super(ZAIDField, self).clean(value)

        if value in EMPTY_VALUES:
            return u''

        match = re.match(id_re, value)

        if not match:
            raise ValidationError(self.error_messages['invalid'])

        g = match.groupdict()

        try:
            # The year 2000 is conveniently a leapyear.
            # This algorithm will break in xx00 years which aren't leap years
            # There is no way to guess the century of a ZA ID number
            d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd']))
        except ValueError:
            raise ValidationError(self.error_messages['invalid'])

        if not luhn(value):
            raise ValidationError(self.error_messages['invalid'])

        return value

class ZAPostCodeField(RegexField):
    default_error_messages = {
        'invalid': _(u'Enter a valid South African postal code'),
    }

    def __init__(self, *args, **kwargs):
        super(ZAPostCodeField, self).__init__(r'^\d{4}$',
            max_length=None, min_length=None)