|
1 import re |
|
2 import datetime |
|
3 |
|
4 def id_number_checksum(gd): |
|
5 """ |
|
6 Calculates a Swedish ID number checksum, using the |
|
7 "Luhn"-algoritm |
|
8 """ |
|
9 n = s = 0 |
|
10 for c in (gd['year'] + gd['month'] + gd['day'] + gd['serial']): |
|
11 tmp = ((n % 2) and 1 or 2) * int(c) |
|
12 |
|
13 if tmp > 9: |
|
14 tmp = sum([int(i) for i in str(tmp)]) |
|
15 |
|
16 s += tmp |
|
17 n += 1 |
|
18 |
|
19 if (s % 10) == 0: |
|
20 return 0 |
|
21 |
|
22 return (((s / 10) + 1) * 10) - s |
|
23 |
|
24 def validate_id_birthday(gd, fix_coordination_number_day=True): |
|
25 """ |
|
26 Validates the birth_day and returns the datetime.date object for |
|
27 the birth_day. |
|
28 |
|
29 If the date is an invalid birth day, a ValueError will be raised. |
|
30 """ |
|
31 |
|
32 today = datetime.date.today() |
|
33 |
|
34 day = int(gd['day']) |
|
35 if fix_coordination_number_day and day > 60: |
|
36 day -= 60 |
|
37 |
|
38 if gd['century'] is None: |
|
39 |
|
40 # The century was not specified, and need to be calculated from todays date |
|
41 current_year = today.year |
|
42 year = int(today.strftime('%Y')) - int(today.strftime('%y')) + int(gd['year']) |
|
43 |
|
44 if ('%s%s%02d' % (gd['year'], gd['month'], day)) > today.strftime('%y%m%d'): |
|
45 year -= 100 |
|
46 |
|
47 # If the person is older than 100 years |
|
48 if gd['sign'] == '+': |
|
49 year -= 100 |
|
50 else: |
|
51 year = int(gd['century'] + gd['year']) |
|
52 |
|
53 # Make sure the year is valid |
|
54 # There are no swedish personal identity numbers where year < 1800 |
|
55 if year < 1800: |
|
56 raise ValueError |
|
57 |
|
58 # ValueError will be raise for invalid dates |
|
59 birth_day = datetime.date(year, int(gd['month']), day) |
|
60 |
|
61 # birth_day must not be in the future |
|
62 if birth_day > today: |
|
63 raise ValueError |
|
64 |
|
65 return birth_day |
|
66 |
|
67 def format_personal_id_number(birth_day, gd): |
|
68 # birth_day.strftime cannot be used, since it does not support dates < 1900 |
|
69 return unicode(str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']) |
|
70 |
|
71 def format_organisation_number(gd): |
|
72 if gd['century'] is None: |
|
73 century = '' |
|
74 else: |
|
75 century = gd['century'] |
|
76 |
|
77 return unicode(century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']) |
|
78 |
|
79 def valid_organisation(gd): |
|
80 return gd['century'] in (None, 16) and \ |
|
81 int(gd['month']) >= 20 and \ |
|
82 gd['sign'] in (None, '-') and \ |
|
83 gd['year'][0] in ('2', '5', '7', '8', '9') # group identifier |
|
84 |