8000 Add support for 2013 extension of Irish PPS Numbers · arthurdejong/python-stdnum@a4012f5 · GitHub
[go: up one dir, main page]

Skip to content

Commit a4012f5

Browse files
committed
1 parent 71d9837 commit a4012f5

File tree

3 files changed

+42
-14
lines changed

3 files changed

+42
-14
lines changed

stdnum/ie/pps.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# pps.py - functions for handling Irish PPS numbers
22
#
33
# Copyright (C) 2012, 2013 Arthur de Jong
4+
# Copyright (C) 2014 Olivier Dony
45
#
56
# This library is free software; you can redistribute it and/or
67
# modify it under the terms of the GNU Lesser General Public
@@ -19,17 +20,32 @@
1920

2021
"""PPS No (Personal Public Service Number, Irish personal number).
2122
22-
The Personal Public Service number consists of 8 digits. The first seven
23-
are numeric and the last is the check character. The number is sometimes
24-
be followed by an extra letter that can be a 'W', 'T' or an 'X' and is
25-
ignored for the check algorithm.
23+
The Personal Public Service number consists of 7 digits, and one or
24+
two letters. The first letter is a check character.
25+
When present (which should be the case for new numbers as of 2013),
26+
the second letter can be 'A' (for individuals) or 'H' (for
27+
non-individuals, such as limited companies, trusts, partnerships
28+
and unincorporated bodies). Pre-2013 values may have 'W', 'T',
29+
or 'X' as the second letter ; it is ignored by the check.
2630
27-
>>> validate('6433435F')
31+
>>> validate('6433435F') # pre-2013
2832
'6433435F'
33+
>>> validate('6433435FT') # pre-2013 with special final 'T'
34+
'6433435FT'
35+
>>> validate('6433435FW') # pre-2013 format for married women
36+
'6433435FW'
2937
>>> validate('6433435E') # incorrect check digit
3038
Traceback (most recent call last):
3139
...
3240
InvalidChecksum: ...
41+
>>> validate('6433435OA') # 2013 format (personal)
42+
'6433435OA'
43+
>>> validate('6433435IH') # 2013 format (non-personal)
44+
'6433435IH'
45+
>>> validate('6433435VH') # 2013 format (incorrect check)
46+
Traceback (most recent call last):
47+
...
48+
InvalidChecksum: ...
3349
"""
3450

3551
import re
@@ -39,7 +55,7 @@
3955
from stdnum.util import clean
4056

4157

42-
pps_re = re.compile('^\d{7}[A-W][WTX]?$')
58+
pps_re = re.compile('^\d{7}[A-W][AHWTX]?$')
4359
"""Regular expression used to check syntax of PPS numbers."""
4460

4561

@@ -55,8 +71,14 @@ def validate(number):
5571
number = compact(number)
5672
if not pps_re.match(number):
5773
raise InvalidFormat()
58-
if number[7] != vat.calc_check_digit(number[:7]):
59-
raise InvalidChecksum()
74+
if len(number) == 9 and number[8] in 'AH':
75+
# new 2013 format
76+
if number[7] != vat.calc_check_digit(number[:7] + number[8:]):
77+
raise InvalidChecksum()
78+
else:
79+
# old format, last letter ignored
80+
if number[7] != vat.calc_check_digit(number[:7]):
81+
raise InvalidChecksum()
6082
return number
6183

6284

stdnum/ie/vat.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
The Irish VAT number consists of 8 digits. The last digit is a check
2323
letter, the second digit may be a number, a letter, "+" or "*".
2424
25-
>>> validate('IE 6433435F')
25+
>>> validate('IE 6433435F') # pre-2013 format
2626
'6433435F'
27+
>>> validate('IE 6433435OA') # 2013 format
28+
'6433435OA'
2729
>>> validate('6433435E') # incorrect check digit
2830
Traceback (most recent call last):
2931
...
@@ -53,8 +55,10 @@ def calc_check_digit(number):
5355
"""Calculate the check digit. The number passed should not have the
5456
check digit included."""
5557
alphabet = 'WABCDEFGHIJKLMNOPQRSTUV'
56-
number = (7 - len(number)) * '0' + number
57-
return alphabet[sum((8 - i) * int(n) for i, n in enumerate(number)) % 23]
58+
number = compact(number).zfill(7)
59+
return alphabet[(
60+
sum((8 - i) * int(n) for i, n in enumerate(number[:7])) +
61+
9 * alphabet.index(number[7:])) % 23]
5862

5963

6064
def validate(number):
@@ -63,15 +67,15 @@ def validate(number):
6367
number = compact(number)
6468
if not number[:1].isdigit() or not number[2:7].isdigit():
6569
raise InvalidFormat()
66-
if len(number) != 8:
70+
if len(number) not in (8, 9):
6771
raise InvalidLength()
6872
if number[:7].isdigit():
6973
# new system
70-
if number[-1] != calc_check_digit(number[:-1]):
74+
if number[7] != calc_check_digit(number[:7] + number[8:]):
7175
raise InvalidChecksum()
7276
elif number[1] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ+*':
7377
# old system
74-
if number[-1] != calc_check_digit(number[2:-1] + number[0]):
78+
if number[7] != calc_check_digit(number[2:7] + number[0]):
7579
raise InvalidChecksum()
7680
else:
7781
raise InvalidFormat()

tests/test_eu_vat.doctest

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ These have been found online and should all be valid numbers.
387387
... IE6599001W
388388
... IE8D79739I
389389
... IE9Y71814N
390+
... IE6433435OA
391+
... IE6433435IH
390392
...
391393
... IT - 01404480202
392394
... IT 0 0 6 1 8 2 8 0 4 9 9

0 commit comments

Comments
 (0)
0