/django/contrib/localflavor/se/forms.py
Python | 157 lines | 124 code | 8 blank | 25 comment | 1 complexity | 0d4e0bb4a0d91c0b81a77a031644ddae MD5 | raw file
Possible License(s): BSD-3-Clause
- # -*- 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(' ', '')