Skip to content

Commit 62d15e9

Browse files
unhoarthurdejong
authored andcommitted
Add support for Guinea TIN
Closes #384 Closes #386
1 parent 96abcfe commit 62d15e9

File tree

3 files changed

+267
-0
lines changed

3 files changed

+267
-0
lines changed

stdnum/gn/__init__.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# __init__.py - collection of Guinea numbers
2+
# coding: utf-8
3+
#
4+
# Copyright (C) 2023 Leandro Regueiro
5+
#
6+
# This library is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU Lesser General Public
8+
# License as published by the Free Software Foundation; either
9+
# version 2.1 of the License, or (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
# Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public
17+
# License along with this library; if not, write to the Free Software
18+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19+
# 02110-1301 USA
20+
21+
"""Collection of Guinea numbers."""
22+
23+
# provide aliases
24+
from stdnum.gn import nifp as vat # noqa: F401

stdnum/gn/nifp.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# nifp.py - functions for handling Guinea NIFp numbers
2+
# coding: utf-8
3+
#
4+
# Copyright (C) 2023 Leandro Regueiro
5+
#
6+
# This library is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU Lesser General Public
8+
# License as published by the Free Software Foundation; either
9+
# version 2.1 of the License, or (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
# Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public
17+
# License along with this library; if not, write to the Free Software
18+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19+
# 02110-1301 USA
20+
21+
"""NIFp (Numéro d'Identification Fiscale Permanent, Guinea tax number).
22+
23+
This number consists of 9 digits, usually separated into three groups using
24+
hyphens to make it easier to read. The first eight digits are assigned in a
25+
pseudorandom manner. The last digit is the check digit.
26+
27+
More information:
28+
29+
* https://dgi.gov.gn/wp-content/uploads/2022/09/N%C2%B0-12-Cahier-de-Charges-NIF-p.pdf
30+
31+
>>> validate('693770885')
32+
'693770885'
33+
>>> validate('693-770-885')
34+
'693770885'
35+
>>> validate('12345')
36+
Traceback (most recent call last):
37+
...
38+
InvalidLength: ...
39+
>>> validate('693770880')
40+
Traceback (most recent call last):
41+
...
42+
InvalidChecksum: ...
43+
>>> format('693770885')
44+
'693-770-885'
45+
"""
46+
47+
from stdnum import luhn
48+
from stdnum.exceptions import *
49+
from stdnum.util import clean, isdigits
50+
51+
52+
def compact(number):
53+
"""Convert the number to the minimal representation.
54+
55+
This strips the number of any valid separators and removes surrounding
56+
whitespace.
57+
"""
58+
return clean(number, ' -').strip()
59+
60+
61+
def validate(number):
62+
"""Check if the number is a valid Guinea NIFp number.
63+
64+
This checks the length, formatting and check digit.
65+
"""
66+
number = compact(number)
67+
if len(number) != 9:
68+
raise InvalidLength()
69+
if not isdigits(number):
70+
raise InvalidFormat()
71+
luhn.validate(number)
72+
return number
73+
74+
75+
def is_valid(number):
76+
"""Check if the number is a valid Guinea NIFp number."""
77+
try:
78+
return bool(validate(number))
79+
except ValidationError:
80+
return False
81+
82+
83+
def format(number):
84+
"""Reformat the number to the standard presentation format."""
85+
number = compact(number)
86+
return '-'.join([number[:3], number[3:-3], number[-3:]])

tests/test_gn_nifp.doctest

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
test_gn_nifp.doctest - more detailed doctests for stdnum.gn.nifp module
2+
3+
Copyright (C) 2023 Leandro Regueiro
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18+
02110-1301 USA
19+
20+
21+
This file contains more detailed doctests for the stdnum.gn.nifp module. It
22+
tries to test more corner cases and detailed functionality that is not really
23+
useful as module documentation.
24+
25+
>>> from stdnum.gn import nifp
26+
27+
28+
Tests for some corner cases.
29+
30+
>>> nifp.validate('693770885')
31+
'693770885'
32+
>>> nifp.validate('693-770-885')
33+
'693770885'
34+
>>> nifp.format('693770885')
35+
'693-770-885'
36+
>>> nifp.validate('12345')
37+
Traceback (most recent call last):
38+
...
39+
InvalidLength: ...
40+
>>> nifp.validate('VV3456789')
41+
Traceback (most recent call last):
42+
...
43+
InvalidFormat: ...
44+
>>> nifp.validate('693770880')
45+
Traceback (most recent call last):
46+
...
47+
InvalidChecksum: ...
48+
49+
50+
These have been found online and should all be valid numbers.
51+
52+
>>> numbers = '''
53+
...
54+
... 102193364
55+
... 102932480
56+
... 113906614
57+
... 137855094
58+
... 157700758
59+
... 163512015
60+
... 168219525
61+
... 177755154
62+
... 203352125
63+
... 215895707
64+
... 234705127
65+
... 258620392
66+
... 265163162
67+
... 270905136
68+
... 276587276
69+
... 281697813
70+
... 281973404
71+
... 289136574
72+
... 290216472
73+
... 291581551
74+
... 311132112
75+
... 326241312
76+
... 326916780
77+
... 330284803
78+
... 333066967
79+
... 339107195
80+
... 370302309
81+
... 379503667
82+
... 390899623
83+
... 407497502
84+
... 415146935
85+
... 416379998
86+
... 422626143
87+
... 429527492
88+
... 433727930
89+
... 438888018
90+
... 447159617
91+
... 447777913
92+
... 489733675
93+
... 496666249
94+
... 515556629
95+
... 530081389
96+
... 538787201
97+
... 540187069
98+
... 569056062
99+
... 585086473
100+
... 589015205
101+
... 622719409
102+
... 626945182
103+
... 633490883
104+
... 634628101
105+
... 634726517
106+
... 639191436
107+
... 647585900
108+
... 653873455
109+
... 656468998
110+
... 658615315
111+
... 664138476
112+
... 664763828
113+
... 666959549
114+
... 677783854
115+
... 681340105
116+
... 691380299
117+
... 720469097
118+
... 735630923
119+
... 762478154
120+
... 765808340
121+
... 775347206
122+
... 780527677
123+
... 780806089
124+
... 784170151
125+
... 806927760
126+
... 833139827
127+
... 839709987
128+
... 841526031
129+
... 842993172
130+
... 853101202
131+
... 853102234
132+
... 864098611
133+
... 875480923
134+
... 877008771
135+
... 887516623
136+
... 896053261
137+
... 902765809
138+
... 908179583
139+
... 908810518
140+
... 912232667
141+
... 914351234
142+
... 925867079
143+
... 927432484
144+
... 938291994
145+
... 955449905
146+
... 958819708
147+
... 960943835
148+
... 964456891
149+
... 969695261
150+
... 972555296
151+
... 977428416
152+
... 982469827
153+
... 999707235
154+
...
155+
... '''
156+
>>> [x for x in numbers.splitlines() if x and not nifp.is_valid(x)]
157+
[]

0 commit comments

Comments
 (0)