Skip to content

Commit fbe094c

Browse files
unhoarthurdejong
authored andcommitted
Add Faroe Islands V-number
Closes arthurdejong#323 Closes arthurdejong#219
1 parent a261a93 commit fbe094c

File tree

3 files changed

+275
-0
lines changed

3 files changed

+275
-0
lines changed

stdnum/fo/__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 Faroe Islands 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 Faroe Islands numbers."""
22+
23+
# provide aliases
24+
from stdnum.fo import vn as vat # noqa: F401

stdnum/fo/vn.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# vn.py - functions for handling Faroe Islands V-number 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+
"""V-number (Vinnutal, Faroe Islands tax number).
22+
23+
In the Faroe Islands the legal persons TIN equals the V number issued by the
24+
Faroese Tax Administration. It is a consecutive number.
25+
26+
More information:
27+
28+
* https://www.taks.fo/fo/borgari/bolkar/at-stovna-virki/
29+
* https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Faroe-islands-TIN.pdf
30+
31+
>>> validate('623857')
32+
'623857'
33+
>>> validate('1234')
34+
Traceback (most recent call last):
35+
...
36+
InvalidLength: ...
37+
>>> validate('12345X')
38+
Traceback (most recent call last):
39+
...
40+
InvalidFormat: ...
41+
>>> format('602 590')
42+
'602590'
43+
""" # noqa: E501
44+
45+
from stdnum.exceptions import *
46+
from stdnum.util import clean, isdigits
47+
48+
49+
def compact(number):
50+
"""Convert the number to the minimal representation.
51+
52+
This strips the number of any valid separators and removes surrounding
53+
whitespace.
54+
"""
55+
number = clean(number, ' -.').upper().strip()
56+
if number.startswith('FO'):
57+
return number[2:]
58+
return number
59+
60+
61+
def validate(number):
62+
"""Check if the number is a valid Faroe Islands V-number number.
63+
64+
This checks the length and formatting.
65+
"""
66+
number = compact(number)
67+
if len(number) != 6:
68+
raise InvalidLength()
69+
if not isdigits(number):
70+
raise InvalidFormat()
71+
return number
72+
73+
74+
def is_valid(number):
75+
"""Check if the number is a valid Faroe Islands V-number number."""
76+
try:
77+
return bool(validate(number))
78+
except ValidationError:
79+
return False
80+
81+
82+
def format(number):
83+
"""Reformat the number to the standard presentation format."""
84+
return compact(number)

tests/test_fo_vn.doctest

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
test_fo_vn.doctest - more detailed doctests for stdnum.fo.vn 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.fo.vn 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.fo import vn
26+
27+
28+
Tests for some corner cases.
29+
30+
>>> vn.validate('623857')
31+
'623857'
32+
>>> vn.validate('602 590')
33+
'602590'
34+
>>> vn.validate('563.609')
35+
'563609'
36+
>>> vn.validate('FO384941')
37+
'384941'
38+
>>> vn.format('623857')
39+
'623857'
40+
>>> vn.format('602 590')
41+
'602590'
42+
>>> vn.format('33 28 28')
43+
'332828'
44+
>>> vn.format('563.609')
45+
'563609'
46+
>>> vn.format('FO384941')
47+
'384941'
48+
>>> vn.validate('12345')
49+
Traceback (most recent call last):
50+
...
51+
InvalidLength: ...
52+
>>> vn.validate('12345X')
53+
Traceback (most recent call last):
54+
...
55+
InvalidFormat: ...
56+
57+
58+
These have been found online and should all be valid numbers.
59+
60+
>>> numbers = '''
61+
...
62+
... 308382
63+
... 309273
64+
... 321079
65+
... 322059
66+
... 322407
67+
... 323853
68+
... 324213
69+
... 328863
70+
... 328871
71+
... 328944
72+
... 33 28 28
73+
... 330833
74+
... 331538
75+
... 339849
76+
... 344338
77+
... 345334
78+
... 345490
79+
... 353477
80+
... 355186
81+
... 355216
82+
... 366161
83+
... 369497
84+
... 374989
85+
... 379778
86+
... 401900
87+
... 403369
88+
... 403687
89+
... 408638
90+
... 427888
91+
... 437.115
92+
... 443921
93+
... 452432
94+
... 463000
95+
... 476897
96+
... 478 865
97+
... 488135
98+
... 489042
99+
... 498.289
100+
... 502855
101+
... 504572
102+
... 509078
103+
... 516244
104+
... 519324
105+
... 522821
106+
... 537.535
107+
... 537.543
108+
... 538485
109+
... 539813
110+
... 546.089
111+
... 549118
112+
... 55 16 00
113+
... 550558
114+
... 550612
115+
... 551.023
116+
... 552569
117+
... 554375
118+
... 557 692
119+
... 559679
120+
... 563.609
121+
... 568 031
122+
... 568 597
123+
... 569682
124+
... 575712
125+
... 576174
126+
... 578 509
127+
... 579319
128+
... 585335
129+
... 587974
130+
... 589.810
131+
... 589306
132+
... 597570
133+
... 601470
134+
... 602 590
135+
... 602221
136+
... 603937
137+
... 604097
138+
... 605 174
139+
... 606294
140+
... 607436
141+
... 613606
142+
... 616 923
143+
... 617105
144+
... 617121
145+
... 619388
146+
... 619558
147+
... 620092
148+
... 620785
149+
... 623016
150+
... 623385
151+
... 623792
152+
... 623857
153+
... 625485
154+
... 625590
155+
... 627976
156+
... 628980
157+
... 630713
158+
... 636223
159+
... 636568
160+
... 637114
161+
... 638722
162+
... 641154
163+
... FO384941
164+
...
165+
... '''
166+
>>> [x for x in numbers.splitlines() if x and not vn.is_valid(x)]
167+
[]

0 commit comments

Comments
 (0)