diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py index 29d01b9de2f..a2b2eed5c24 100644 --- a/django/contrib/localflavor/fi/forms.py +++ b/django/contrib/localflavor/fi/forms.py @@ -2,8 +2,9 @@ FI-specific Form helpers """ +import re from django.newforms import ValidationError -from django.newforms.fields import RegexField, Select +from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES from django.utils.translation import gettext class FIZipCodeField(RegexField): @@ -20,3 +21,27 @@ class FIMunicipalitySelect(Select): def __init__(self, attrs=None): from fi_municipalities import MUNICIPALITY_CHOICES # relative import super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES) + +class FISocialSecurityNumber(Field): + def clean(self, value): + super(FISocialSecurityNumber, self).clean(value) + if value in EMPTY_VALUES: + return u'' + + checkmarks = "0123456789ABCDEFHJKLMNPRSTUVWXY" + result = re.match(r"""^ + (?P([0-2]\d|3[01]) + (0\d|1[012]) + (\d{2})) + [A+-] + (?P(\d{3})) + (?P[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE) + if not result: + raise ValidationError(gettext(u'Enter a valid Finnish social security number.')) + checksum = int(result.groupdict()['date'] + result.groupdict()['serial']) + + if checkmarks[checksum % len(checkmarks)] == result.groupdict()['chechsum'].upper(): + return u'%s' % value.upper() + + raise ValidationError(gettext(u'Enter a valid Finnish social security number.')) + diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 95453e7eeb9..b2d66469c40 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -3930,6 +3930,50 @@ A Select widget that uses a list of Finnish municipalities as its choices. >>> unicode(w.render('municipalities', 'turku')) u'' +# FISocialSecurityNumber +############################################################## + +>>> from django.contrib.localflavor.fi.forms import FISocialSecurityNumber +>>> f = FISocialSecurityNumber() +>>> f.clean('010101-0101') +u'010101-0101' +>>> f.clean('010101+0101') +u'010101+0101' +>>> f.clean('010101A0101') +u'010101A0101' +>>> f.clean('101010-0102') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid Finnish social security number.'] +>>> f.clean('10a010-0101') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid Finnish social security number.'] +>>> f.clean('101010-0\xe401') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid Finnish social security number.'] +>>> f.clean('101010b0101') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid Finnish social security number.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f = FISocialSecurityNumber(required=False) +>>> f.clean('010101-0101') +u'010101-0101' +>>> f.clean(None) +u'' +>>> f.clean('') +u'' + ################################# # Tests of underlying functions # #################################