--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/lib/django/contrib/localflavor/se/forms.py Tue May 25 02:43:45 2010 +0200
@@ -0,0 +1,157 @@
+# -*- coding: utf-8 -*-
+"""
+Swedish specific Form helpers
+"""
+import re
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+from django.core.validators import EMPTY_VALUES
+from django.contrib.localflavor.se.utils import (id_number_checksum,
+ validate_id_birthday, format_personal_id_number, valid_organisation,
+ format_organisation_number)
+
+__all__ = ('SECountySelect', 'SEOrganisationNumberField',
+ 'SEPersonalIdentityNumberField', 'SEPostalCodeField')
+
+SWEDISH_ID_NUMBER = re.compile(r'^(?P<century>\d{2})?(?P<year>\d{2})(?P<month>\d{2})(?P<day>\d{2})(?P<sign>[\-+])?(?P<serial>\d{3})(?P<checksum>\d)$')
+SE_POSTAL_CODE = re.compile(r'^[1-9]\d{2} ?\d{2}$')
+
+class SECountySelect(forms.Select):
+ """
+ A Select form widget that uses a list of the Swedish counties (län) as its
+ choices.
+
+ The cleaned value is the official county code -- see
+ http://en.wikipedia.org/wiki/Counties_of_Sweden for a list.
+ """
+
+ def __init__(self, attrs=None):
+ from se_counties import COUNTY_CHOICES
+ super(SECountySelect, self).__init__(attrs=attrs,
+ choices=COUNTY_CHOICES)
+
+class SEOrganisationNumberField(forms.CharField):
+ """
+ A form field that validates input as a Swedish organisation number
+ (organisationsnummer).
+
+ It accepts the same input as SEPersonalIdentityField (for sole
+ proprietorships (enskild firma). However, co-ordination numbers are not
+ accepted.
+
+ It also accepts ordinary Swedish organisation numbers with the format
+ NNNNNNNNNN.
+
+ The return value will be YYYYMMDDXXXX for sole proprietors, and NNNNNNNNNN
+ for other organisations.
+ """
+
+ default_error_messages = {
+ 'invalid': _('Enter a valid Swedish organisation number.'),
+ }
+
+ def clean(self, value):
+ value = super(SEOrganisationNumberField, self).clean(value)
+
+ if value in EMPTY_VALUES:
+ return u''
+
+ match = SWEDISH_ID_NUMBER.match(value)
+ if not match:
+ raise forms.ValidationError(self.error_messages['invalid'])
+
+ gd = match.groupdict()
+
+ # Compare the calculated value with the checksum
+ if id_number_checksum(gd) != int(gd['checksum']):
+ raise forms.ValidationError(self.error_messages['invalid'])
+
+ # First: check if this is a real organisation_number
+ if valid_organisation(gd):
+ return format_organisation_number(gd)
+
+ # Is this a single properitor (enskild firma)?
+ try:
+ birth_day = validate_id_birthday(gd, False)
+ return format_personal_id_number(birth_day, gd)
+ except ValueError:
+ raise forms.ValidationError(self.error_messages['invalid'])
+
+
+class SEPersonalIdentityNumberField(forms.CharField):
+ """
+ A form field that validates input as a Swedish personal identity number
+ (personnummer).
+
+ The correct formats are YYYYMMDD-XXXX, YYYYMMDDXXXX, YYMMDD-XXXX,
+ YYMMDDXXXX and YYMMDD+XXXX.
+
+ A + indicates that the person is older than 100 years, which will be taken
+ into consideration when the date is validated.
+
+ The checksum will be calculated and checked. The birth date is checked to
+ be a valid date.
+
+ By default, co-ordination numbers (samordningsnummer) will be accepted. To
+ only allow real personal identity numbers, pass the keyword argument
+ coordination_number=False to the constructor.
+
+ The cleaned value will always have the format YYYYMMDDXXXX.
+ """
+
+ def __init__(self, coordination_number=True, *args, **kwargs):
+ self.coordination_number = coordination_number
+ super(SEPersonalIdentityNumberField, self).__init__(*args, **kwargs)
+
+ default_error_messages = {
+ 'invalid': _('Enter a valid Swedish personal identity number.'),
+ 'coordination_number': _('Co-ordination numbers are not allowed.'),
+ }
+
+ def clean(self, value):
+ value = super(SEPersonalIdentityNumberField, self).clean(value)
+
+ if value in EMPTY_VALUES:
+ return u''
+
+ match = SWEDISH_ID_NUMBER.match(value)
+ if match is None:
+ raise forms.ValidationError(self.error_messages['invalid'])
+
+ gd = match.groupdict()
+
+ # compare the calculated value with the checksum
+ if id_number_checksum(gd) != int(gd['checksum']):
+ raise forms.ValidationError(self.error_messages['invalid'])
+
+ # check for valid birthday
+ try:
+ birth_day = validate_id_birthday(gd)
+ except ValueError:
+ raise forms.ValidationError(self.error_messages['invalid'])
+
+ # make sure that co-ordination numbers do not pass if not allowed
+ if not self.coordination_number and int(gd['day']) > 60:
+ raise forms.ValidationError(self.error_messages['coordination_number'])
+
+ return format_personal_id_number(birth_day, gd)
+
+
+class SEPostalCodeField(forms.RegexField):
+ """
+ A form field that validates input as a Swedish postal code (postnummer).
+ Valid codes consist of five digits (XXXXX). The number can optionally be
+ formatted with a space after the third digit (XXX XX).
+
+ The cleaned value will never contain the space.
+ """
+
+ default_error_messages = {
+ 'invalid': _('Enter a Swedish postal code in the format XXXXX.'),
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(SEPostalCodeField, self).__init__(SE_POSTAL_CODE, *args, **kwargs)
+
+ def clean(self, value):
+ return super(SEPostalCodeField, self).clean(value).replace(' ', '')