Skip to content

Commit 1e0add5

Browse files
committed
Add support for Algeria TIN number
Fixes #307
1 parent e40c827 commit 1e0add5

File tree

3 files changed

+354
-0
lines changed

3 files changed

+354
-0
lines changed

stdnum/dz/__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 Algerian numbers
2+
# coding: utf-8
3+
#
4+
# Copyright (C) 2022 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 Algerian numbers."""
22+
23+
# provide vat as an alias
24+
from stdnum.dz import nif as vat # noqa: F401

stdnum/dz/nif.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# pin.py - functions for handling Algeria NIF numbers
2+
# coding: utf-8
3+
#
4+
# Copyright (C) 2022 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+
"""NIF, sometimes N.I.F. (Numéro d'Identification Fiscale, Algeria tax number).
22+
23+
The NIF was adopted by the Algerian tax authorities on 2006, replacing the NIS
24+
number.
25+
26+
The NIF applies to physical persons, legal persons, legal entities,
27+
administrative entities, local branches for foreign companies, associations,
28+
professional organizations, etc.
29+
30+
The NIF consists of 15 digits, but sometimes it can be 20 digits long in order
31+
to represent branches or secondary stablishments.
32+
33+
More information:
34+
35+
* http://www.jecreemonentreprise.dz/index.php?option=com_content&view=article&id=612&Itemid=463&lang=fr
36+
* https://www.mf.gov.dz/index.php/fr/fiscalite
37+
* https://cnrcinfo.cnrc.dz/numero-didentification-fiscale-nif/
38+
* https://nifenligne.mfdgi.gov.dz/
39+
* http://nif.mfdgi.gov.dz/nif.asp
40+
41+
>>> validate('416001000000007')
42+
'416001000000007'
43+
>>> validate('408 020 000 150 039')
44+
'408020000150039'
45+
>>> validate('41201600000606600001')
46+
'41201600000606600001'
47+
>>> validate('000 216 001 808 337 13010')
48+
'00021600180833713010'
49+
>>> validate('12345')
50+
Traceback (most recent call last):
51+
...
52+
InvalidLength: ...
53+
>>> validate('X1600100000000V')
54+
Traceback (most recent call last):
55+
...
56+
InvalidFormat: ...
57+
>>> format('408 020 000 150 039')
58+
'408020000150039'
59+
>>> format('000 216 001 808 337 13010')
60+
'00021600180833713010'
61+
"""
62+
63+
from stdnum.exceptions import *
64+
from stdnum.util import clean, isdigits
65+
66+
67+
def compact(number):
68+
"""Convert the number to the minimal representation.
69+
70+
This strips the number of any valid separators, removes surrounding
71+
whitespace.
72+
"""
73+
return clean(number, ' ')
74+
75+
76+
def validate(number):
77+
"""Check if the number is a valid Algeria NIF number.
78+
79+
This checks the length and formatting.
80+
"""
81+
number = compact(number)
82+
if len(number) not in (15, 20):
83+
raise InvalidLength()
84+
if not isdigits(number):
85+
raise InvalidFormat()
86+
return number
87+
88+
89+
def is_valid(number):
90+
"""Check if the number is a valid Algeria NIF number."""
91+
try:
92+
return bool(validate(number))
93+
except ValidationError:
94+
return False
95+
96+
97+
def format(number):
98+
"""Reformat the number to the standard presentation format."""
99+
return compact(number)

tests/test_dz_nif.doctest

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
test_dz_nif.doctest - more detailed doctests for stdnum.dz.nif module
2+
3+
Copyright (C) 2022 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.dz.nif 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.dz import nif
26+
27+
28+
Tests for some corner cases.
29+
30+
>>> nif.validate('416001000000007')
31+
'416001000000007'
32+
>>> nif.validate('408 020 000 150 039')
33+
'408020000150039'
34+
>>> nif.validate('41201600000606600001')
35+
'41201600000606600001'
36+
>>> nif.validate('000 216 001 808 337 13010')
37+
'00021600180833713010'
38+
>>> nif.validate('12345')
39+
Traceback (most recent call last):
40+
...
41+
InvalidLength: ...
42+
>>> nif.validate('X1600100000000V')
43+
Traceback (most recent call last):
44+
...
45+
InvalidFormat: ...
46+
>>> nif.format('408 020 000 150 039')
47+
'408020000150039'
48+
>>> nif.format('000 216 001 808 337 13010')
49+
'00021600180833713010'
50+
51+
52+
These have been found online and should all be valid numbers.
53+
54+
>>> numbers = '''
55+
...
56+
... 416001000000007
57+
... 000116001560982
58+
... 000416096544827
59+
... 408 020 000 150 039
60+
... 000016001381120
61+
... 000 216 001 808 337
62+
... 408020000060031
63+
... 000216002104442
64+
... 000216001808337
65+
... 000007019004069
66+
... 000 216 001 808 337 13010
67+
... 001125069042347
68+
... 408020001100031
69+
... 411020000240004
70+
... 408002000000065
71+
... 000616097268506
72+
... 000716097805474
73+
... 408020000020098
74+
... 41201600000606600001
75+
... 408020000290087
76+
... 000416096547023
77+
... 001309109031646
78+
... 001431039004061
79+
... 000116180849545
80+
... 408020000310039
81+
... 420016000090015
82+
... 408020000210125
83+
... 001116098865826
84+
... 000716097425528
85+
... 408020000160863
86+
... 000016001159195
87+
... 098919015000337
88+
... 00131 6099242493
89+
... 410007000000046
90+
... 000216299033049
91+
... 420110400000042
92+
... 001519019003549
93+
... 412014000190014
94+
... 408008000100033
95+
... 001816104587248
96+
... 001125019041843
97+
... 099816000344301
98+
... 417180000000088
99+
... 000848019007735
100+
... 40802100000204900000
101+
... 000316096228742
102+
... 001616104328611
103+
... 002131011846676
104+
... 408015000017094
105+
... 00021 600 180 833 716 001
106+
... 410011000000012
107+
... 198015500011640
108+
... 001707024366917
109+
... 099925006295010
110+
... 099916000816810
111+
... 000716097425528
112+
... 000816097716198
113+
... 000347019004646
114+
... 181050400060195
115+
... 099815019058902
116+
... 099915004348016
117+
... 164151000512151
118+
... 001609019033838
119+
... 099919008329067
120+
... 000 116 180 807 261
121+
... 157092600693479
122+
... 408004000000082
123+
... 002016101606088
124+
... 27216010518015900000
125+
... 179423501014107
126+
... 169470500236104
127+
... 001730019009056
128+
... 198847070005037
129+
... 408015000043003
130+
... 099807024211756
131+
... 000607024268702
132+
... 000516097078853
133+
... 000016001358124
134+
... 000416096783683
135+
... 099915004292220
136+
... 099916000598324
137+
... 000135072346001
138+
... 001225006964374
139+
... 000735072494667
140+
... 001025006891914
141+
... 00001600137674493006
142+
... 00001600137674493019
143+
... 00001600137674493014
144+
... 00001600137674493005
145+
... 00001600137674493002
146+
... 001206018759104
147+
... 000336068252339
148+
... 000423036376676
149+
... 000307024248170
150+
... 000906018632115
151+
... 099931010410317
152+
... 099747086204339
153+
... 000825006783595
154+
... 000624038263530
155+
... 000434046319884
156+
... 0000 1600 15 01 289
157+
... 196 816 040 011 445
158+
... 001 109 199 007 345
159+
... 195 916 010 107 542
160+
... 194 916 010 095 431
161+
... 197 919 010 321 535
162+
... 165 431 400 300 157
163+
... 797 435 379 003 601
164+
... 097524019047421
165+
... 000245006625193
166+
... 152431400682135
167+
... 000505022347781
168+
... 180240104351164
169+
... 000724038267478
170+
... 000824038269319
171+
... 000428056270862
172+
... 197305380027237
173+
... 001341050285855
174+
... 198805420009824
175+
... 099824038206619
176+
... 099816000499785
177+
... 001513026489736
178+
... 287160700030197
179+
... 000116001567707
180+
... 000016019034356
181+
... 197016180012728
182+
... 001316100750533
183+
... 295161704436174
184+
... 197816180459711
185+
... 195213040012847
186+
... 000619019037344
187+
... 182162000621184
188+
... 000116001524660
189+
... 099916001064029
190+
... 287160700030597
191+
... 000516096872520
192+
... 198018210116342
193+
... 000116001567707
194+
... 153160105528127
195+
... 099935072285348
196+
... 165161701380190
197+
... 001216209014745
198+
... 000516100938845
199+
... 000016001300865
200+
... 287160700030197
201+
... 000216002133054
202+
... 189161702283168
203+
... 001316099262097
204+
... 185160201610152
205+
... 295161704436174
206+
... 000816097696555
207+
... 001216209014175
208+
... 001116099033052
209+
... 000916098321803
210+
... 193160600100148
211+
... 001216098929656
212+
... 000516096872520
213+
... 153160105528127
214+
... 000516096825183
215+
... 099916029015224
216+
... 169164800432122
217+
... 000016001300865
218+
... 000516096980536
219+
... 00131609936785400000
220+
... 001316100750513
221+
... 099716000280672
222+
... 000616097459024
223+
... 099916000745814
224+
... 001716104401413
225+
... 196416140076038
226+
... 000816097696555
227+
... 171161800210177
228+
...
229+
... '''
230+
>>> [x for x in numbers.splitlines() if x and not nif.is_valid(x)]
231+
[]

0 commit comments

Comments
 (0)