Fixed #9289 - Added Swedish localflavor. Thanks to Andreas Pelme, Ludvig Ericson and Filip Noetzel for working on a patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11969 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
cdf5ad4217
commit
d320deef25
2
AUTHORS
2
AUTHORS
|
@ -328,6 +328,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Gopal Narayanan <gopastro@gmail.com>
|
||||
Fraser Nevett <mail@nevett.org>
|
||||
Sam Newman <http://www.magpiebrain.com/>
|
||||
Filip Noetzel <http://filip.noetzel.co.uk/>
|
||||
Afonso Fernández Nogueira <fonzzo.django@gmail.com>
|
||||
Neal Norwitz <nnorwitz@google.com>
|
||||
Todd O'Bryan <toddobryan@mac.com>
|
||||
|
@ -338,6 +339,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Carlos Eduardo de Paula <carlosedp@gmail.com>
|
||||
pavithran s <pavithran.s@gmail.com>
|
||||
Barry Pederson <bp@barryp.org>
|
||||
Andreas Pelme <andreas@pelme.se>
|
||||
permonik@mesias.brnonet.cz
|
||||
peter@mymart.com
|
||||
pgross@thoughtworks.com
|
||||
|
|
|
@ -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.forms.fields 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(' ', '')
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
An alphabetical list of Swedish counties, sorted by codes.
|
||||
|
||||
http://en.wikipedia.org/wiki/Counties_of_Sweden
|
||||
|
||||
This exists in this standalone file so that it's only imported into memory
|
||||
when explicitly needed.
|
||||
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
COUNTY_CHOICES = (
|
||||
('AB', _(u'Stockholm')),
|
||||
('AC', _(u'Västerbotten')),
|
||||
('BD', _(u'Norrbotten')),
|
||||
('C', _(u'Uppsala')),
|
||||
('D', _(u'Södermanland')),
|
||||
('E', _(u'Östergötland')),
|
||||
('F', _(u'Jönköping')),
|
||||
('G', _(u'Kronoberg')),
|
||||
('H', _(u'Kalmar')),
|
||||
('I', _(u'Gotland')),
|
||||
('K', _(u'Blekinge')),
|
||||
('M', _(u'Skåne')),
|
||||
('N', _(u'Halland')),
|
||||
('O', _(u'Västra Götaland')),
|
||||
('S', _(u'Värmland')),
|
||||
('T', _(u'Örebro')),
|
||||
('U', _(u'Västmanland')),
|
||||
('W', _(u'Dalarna')),
|
||||
('X', _(u'Gävleborg')),
|
||||
('Y', _(u'Västernorrland')),
|
||||
('Z', _(u'Jämtland')),
|
||||
)
|
|
@ -0,0 +1,84 @@
|
|||
import re
|
||||
import datetime
|
||||
|
||||
def id_number_checksum(gd):
|
||||
"""
|
||||
Calculates a Swedish ID number checksum, using the
|
||||
"Luhn"-algoritm
|
||||
"""
|
||||
n = s = 0
|
||||
for c in (gd['year'] + gd['month'] + gd['day'] + gd['serial']):
|
||||
tmp = ((n % 2) and 1 or 2) * int(c)
|
||||
|
||||
if tmp > 9:
|
||||
tmp = sum([int(i) for i in str(tmp)])
|
||||
|
||||
s += tmp
|
||||
n += 1
|
||||
|
||||
if (s % 10) == 0:
|
||||
return 0
|
||||
|
||||
return (((s / 10) + 1) * 10) - s
|
||||
|
||||
def validate_id_birthday(gd, fix_coordination_number_day=True):
|
||||
"""
|
||||
Validates the birth_day and returns the datetime.date object for
|
||||
the birth_day.
|
||||
|
||||
If the date is an invalid birth day, a ValueError will be raised.
|
||||
"""
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
day = int(gd['day'])
|
||||
if fix_coordination_number_day and day > 60:
|
||||
day -= 60
|
||||
|
||||
if gd['century'] is None:
|
||||
|
||||
# The century was not specified, and need to be calculated from todays date
|
||||
current_year = today.year
|
||||
year = int(today.strftime('%Y')) - int(today.strftime('%y')) + int(gd['year'])
|
||||
|
||||
if ('%s%s%02d' % (gd['year'], gd['month'], day)) > today.strftime('%y%m%d'):
|
||||
year -= 100
|
||||
|
||||
# If the person is older than 100 years
|
||||
if gd['sign'] == '+':
|
||||
year -= 100
|
||||
else:
|
||||
year = int(gd['century'] + gd['year'])
|
||||
|
||||
# Make sure the year is valid
|
||||
# There are no swedish personal identity numbers where year < 1800
|
||||
if year < 1800:
|
||||
raise ValueError
|
||||
|
||||
# ValueError will be raise for invalid dates
|
||||
birth_day = datetime.date(year, int(gd['month']), day)
|
||||
|
||||
# birth_day must not be in the future
|
||||
if birth_day > today:
|
||||
raise ValueError
|
||||
|
||||
return birth_day
|
||||
|
||||
def format_personal_id_number(birth_day, gd):
|
||||
# birth_day.strftime cannot be used, since it does not support dates < 1900
|
||||
return unicode(str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'] + gd['checksum'])
|
||||
|
||||
def format_organisation_number(gd):
|
||||
if gd['century'] is None:
|
||||
century = ''
|
||||
else:
|
||||
century = gd['century']
|
||||
|
||||
return unicode(century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum'])
|
||||
|
||||
def valid_organisation(gd):
|
||||
return gd['century'] in (None, 16) and \
|
||||
int(gd['month']) >= 20 and \
|
||||
gd['sign'] in (None, '-') and \
|
||||
gd['year'][0] in ('2', '5', '7', '8', '9') # group identifier
|
||||
|
|
@ -61,6 +61,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
|
|||
* Slovakia_
|
||||
* `South Africa`_
|
||||
* Spain_
|
||||
* Sweden_
|
||||
* Switzerland_
|
||||
* `United Kingdom`_
|
||||
* `United States of America`_
|
||||
|
@ -101,6 +102,7 @@ Here's an example of how to use them::
|
|||
.. _Slovakia: `Slovakia (sk)`_
|
||||
.. _South Africa: `South Africa (za)`_
|
||||
.. _Spain: `Spain (es)`_
|
||||
.. _Sweden: `Sweden (se)`_
|
||||
.. _Switzerland: `Switzerland (ch)`_
|
||||
.. _United Kingdom: `United Kingdom (uk)`_
|
||||
.. _United States of America: `United States of America (us)`_
|
||||
|
@ -596,6 +598,60 @@ Spain (``es``)
|
|||
|
||||
A ``Select`` widget that uses a list of Spanish regions as its choices.
|
||||
|
||||
Sweden (``se``)
|
||||
===============
|
||||
|
||||
.. class:: se.forms.SECountySelect
|
||||
|
||||
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.
|
||||
|
||||
.. class:: se.forms.SEOrganisationNumber
|
||||
|
||||
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.
|
||||
|
||||
.. class:: se.forms.SEPersonalIdentityNumber
|
||||
|
||||
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.
|
||||
|
||||
.. class:: se.forms.SEPostalCodeField
|
||||
|
||||
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.
|
||||
|
||||
Switzerland (``ch``)
|
||||
====================
|
||||
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/se form fields.
|
||||
|
||||
tests = r"""
|
||||
# Monkey-patch datetime.date
|
||||
>>> import datetime
|
||||
>>> class MockDate(datetime.date):
|
||||
... def today(cls):
|
||||
... return datetime.date(2008, 5, 14)
|
||||
... today = classmethod(today)
|
||||
...
|
||||
>>> olddate = datetime.date
|
||||
>>> datetime.date = MockDate
|
||||
>>> datetime.date.today()
|
||||
MockDate(2008, 5, 14)
|
||||
|
||||
|
||||
# SECountySelect #####################################################
|
||||
>>> from django.contrib.localflavor.se.forms import SECountySelect
|
||||
|
||||
>>> w = SECountySelect()
|
||||
>>> w.render('swedish_county', 'E')
|
||||
u'<select name="swedish_county">\n<option value="AB">Stockholm</option>\n<option value="AC">V\xe4sterbotten</option>\n<option value="BD">Norrbotten</option>\n<option value="C">Uppsala</option>\n<option value="D">S\xf6dermanland</option>\n<option value="E" selected="selected">\xd6sterg\xf6tland</option>\n<option value="F">J\xf6nk\xf6ping</option>\n<option value="G">Kronoberg</option>\n<option value="H">Kalmar</option>\n<option value="I">Gotland</option>\n<option value="K">Blekinge</option>\n<option value="M">Sk\xe5ne</option>\n<option value="N">Halland</option>\n<option value="O">V\xe4stra G\xf6taland</option>\n<option value="S">V\xe4rmland</option>\n<option value="T">\xd6rebro</option>\n<option value="U">V\xe4stmanland</option>\n<option value="W">Dalarna</option>\n<option value="X">G\xe4vleborg</option>\n<option value="Y">V\xe4sternorrland</option>\n<option value="Z">J\xe4mtland</option>\n</select>'
|
||||
|
||||
# SEOrganisationNumberField #######################################
|
||||
|
||||
>>> from django.contrib.localflavor.se.forms import SEOrganisationNumberField
|
||||
|
||||
>>> f = SEOrganisationNumberField()
|
||||
|
||||
# Ordinary personal identity numbers for sole proprietors
|
||||
# The same rules as for SEPersonalIdentityField applies here
|
||||
>>> f.clean('870512-1989')
|
||||
u'198705121989'
|
||||
>>> f.clean('19870512-1989')
|
||||
u'198705121989'
|
||||
>>> f.clean('870512-2128')
|
||||
u'198705122128'
|
||||
>>> f.clean('081015-6315')
|
||||
u'190810156315'
|
||||
>>> f.clean('081015+6315')
|
||||
u'180810156315'
|
||||
>>> f.clean('0810156315')
|
||||
u'190810156315'
|
||||
|
||||
>>> f.clean('081015 6315')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
>>> f.clean('950231-4496')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
>>> f.clean('6914104499')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
>>> f.clean('950d314496')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
>>> f.clean('invalid!!!')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
>>> f.clean('870514-1111')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
|
||||
|
||||
# Empty values
|
||||
>>> 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.']
|
||||
|
||||
# Co-ordination number checking
|
||||
# Co-ordination numbers are not valid organisation numbers
|
||||
>>> f.clean('870574-1315')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
|
||||
>>> f.clean('870573-1311')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
|
||||
# Test some different organisation numbers
|
||||
>>> f.clean('556074-7569') # IKEA Linköping
|
||||
u'5560747569'
|
||||
|
||||
>>> f.clean('556074-3089') # Volvo Personvagnar
|
||||
u'5560743089'
|
||||
|
||||
>>> f.clean('822001-5476') # LJS (organisation)
|
||||
u'8220015476'
|
||||
|
||||
>>> f.clean('8220015476') # LJS (organisation)
|
||||
u'8220015476'
|
||||
|
||||
>>> f.clean('2120000449') # Katedralskolan Linköping (school)
|
||||
u'2120000449'
|
||||
|
||||
# Faux organisation number, which tests that the checksum can be 0
|
||||
>>> f.clean('232518-5060')
|
||||
u'2325185060'
|
||||
|
||||
>>> f.clean('556074+3089') # Volvo Personvagnar, bad format
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
|
||||
|
||||
# Invalid checksum
|
||||
>>> f.clean('2120000441')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
|
||||
# Valid checksum but invalid organisation type
|
||||
f.clean('1120000441')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish organisation number.']
|
||||
|
||||
# Empty values with required=False
|
||||
>>> f = SEOrganisationNumberField(required=False)
|
||||
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
|
||||
# SEPersonalIdentityNumberField #######################################
|
||||
|
||||
>>> from django.contrib.localflavor.se.forms import SEPersonalIdentityNumberField
|
||||
|
||||
>>> f = SEPersonalIdentityNumberField()
|
||||
|
||||
# Valid id numbers
|
||||
>>> f.clean('870512-1989')
|
||||
u'198705121989'
|
||||
|
||||
>>> f.clean('870512-2128')
|
||||
u'198705122128'
|
||||
|
||||
>>> f.clean('19870512-1989')
|
||||
u'198705121989'
|
||||
|
||||
>>> f.clean('198705121989')
|
||||
u'198705121989'
|
||||
|
||||
>>> f.clean('081015-6315')
|
||||
u'190810156315'
|
||||
|
||||
>>> f.clean('0810156315')
|
||||
u'190810156315'
|
||||
|
||||
# This is a "special-case" in the checksum calculation,
|
||||
# where the sum is divisible by 10 (the checksum digit == 0)
|
||||
>>> f.clean('8705141060')
|
||||
u'198705141060'
|
||||
|
||||
# + means that the person is older than 100 years
|
||||
>>> f.clean('081015+6315')
|
||||
u'180810156315'
|
||||
|
||||
# Bogus values
|
||||
>>> f.clean('081015 6315')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
>>> f.clean('950d314496')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
>>> f.clean('invalid!!!')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
|
||||
# Invalid dates
|
||||
|
||||
# February 31st does not exist
|
||||
>>> f.clean('950231-4496')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
# Month 14 does not exist
|
||||
>>> f.clean('6914104499')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
# There are no Swedish personal id numbers where year < 1800
|
||||
>>> f.clean('17430309-7135')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
# Invalid checksum
|
||||
>>> f.clean('870514-1111')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
# Empty values
|
||||
>>> 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.']
|
||||
|
||||
# Co-ordination number checking
|
||||
>>> f.clean('870574-1315')
|
||||
u'198705741315'
|
||||
|
||||
>>> f.clean('870574+1315')
|
||||
u'188705741315'
|
||||
|
||||
>>> f.clean('198705741315')
|
||||
u'198705741315'
|
||||
|
||||
# Co-ordination number with bad checksum
|
||||
>>> f.clean('870573-1311')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
|
||||
# Check valid co-ordination numbers, that should not be accepted
|
||||
# because of coordination_number=False
|
||||
>>> f = SEPersonalIdentityNumberField(coordination_number=False)
|
||||
|
||||
>>> f.clean('870574-1315')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Co-ordination numbers are not allowed.']
|
||||
|
||||
>>> f.clean('870574+1315')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Co-ordination numbers are not allowed.']
|
||||
|
||||
>>> f.clean('8705741315')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Co-ordination numbers are not allowed.']
|
||||
|
||||
# Invalid co-ordination numbers should be treated as invalid, and not
|
||||
# as co-ordination numbers
|
||||
>>> f.clean('870573-1311')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swedish personal identity number.']
|
||||
|
||||
# Empty values with required=False
|
||||
>>> f = SEPersonalIdentityNumberField(required=False)
|
||||
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# SEPostalCodeField ###############################################
|
||||
>>> from django.contrib.localflavor.se.forms import SEPostalCodeField
|
||||
>>> f = SEPostalCodeField()
|
||||
>>>
|
||||
Postal codes can have spaces
|
||||
>>> f.clean('589 37')
|
||||
u'58937'
|
||||
|
||||
... but the dont have to
|
||||
>>> f.clean('58937')
|
||||
u'58937'
|
||||
>>> f.clean('abcasfassadf')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a Swedish postal code in the format XXXXX.']
|
||||
|
||||
# Only one space is allowed for separation
|
||||
>>> f.clean('589 37')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a Swedish postal code in the format XXXXX.']
|
||||
|
||||
# The postal code must not start with 0
|
||||
>>> f.clean('01234')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a Swedish postal code in the format XXXXX.']
|
||||
|
||||
# Empty values
|
||||
>>> 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.']
|
||||
|
||||
# Empty values, required=False
|
||||
>>> f = SEPostalCodeField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
|
||||
# Revert the monkey patching
|
||||
>>> datetime.date = olddate
|
||||
|
||||
"""
|
|
@ -21,6 +21,7 @@ from localflavor.jp import tests as localflavor_jp_tests
|
|||
from localflavor.nl import tests as localflavor_nl_tests
|
||||
from localflavor.pl import tests as localflavor_pl_tests
|
||||
from localflavor.ro import tests as localflavor_ro_tests
|
||||
from localflavor.se import tests as localflavor_se_tests
|
||||
from localflavor.sk import tests as localflavor_sk_tests
|
||||
from localflavor.uk import tests as localflavor_uk_tests
|
||||
from localflavor.us import tests as localflavor_us_tests
|
||||
|
@ -56,6 +57,7 @@ __test__ = {
|
|||
'localflavor_nl_tests': localflavor_nl_tests,
|
||||
'localflavor_pl_tests': localflavor_pl_tests,
|
||||
'localflavor_ro_tests': localflavor_ro_tests,
|
||||
'localflavor_se_tests': localflavor_se_tests,
|
||||
'localflavor_sk_tests': localflavor_sk_tests,
|
||||
'localflavor_uk_tests': localflavor_uk_tests,
|
||||
'localflavor_us_tests': localflavor_us_tests,
|
||||
|
|
Loading…
Reference in New Issue