app/django/contrib/localflavor/za/forms.py
author Lennard de Rijk <ljvderijk@gmail.com>
Fri, 23 Jan 2009 09:08:26 +0000
changeset 913 db38e7680d1c
parent 323 ff1a9aa48cfd
permissions -rw-r--r--
Added state property to role model. This can be used when for instance a member has been removed from a club or a when a program has been marked inactive. Certain roles would then be shown on the upcoming roles page marked as previous roles. This would give us the archiving capability that was shown in the mockup. Patch by: Lennard de Rijk Reviewd by: to-be-reviewed

"""
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)