From a6e7ff35a569d5aaf2592d693d446040b9566901 Mon Sep 17 00:00:00 2001 From: Leandro Regueiro Date: Wed, 11 Jan 2023 16:44:34 +0100 Subject: [PATCH] Add TIN number for Rwanda Fixes #315 --- stdnum/rw/__init__.py | 24 ++++ stdnum/rw/tin.py | 82 ++++++++++++ tests/test_rw_tin.doctest | 262 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 368 insertions(+) create mode 100644 stdnum/rw/__init__.py create mode 100644 stdnum/rw/tin.py create mode 100644 tests/test_rw_tin.doctest diff --git a/stdnum/rw/__init__.py b/stdnum/rw/__init__.py new file mode 100644 index 00000000..4946a1bb --- /dev/null +++ b/stdnum/rw/__init__.py @@ -0,0 +1,24 @@ +# __init__.py - collection of Rwanda numbers +# coding: utf-8 +# +# Copyright (C) 2023 Leandro Regueiro +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +"""Collection of Rwanda numbers.""" + +# provide aliases +from stdnum.rw import tin as vat # noqa: F401 diff --git a/stdnum/rw/tin.py b/stdnum/rw/tin.py new file mode 100644 index 00000000..aa3a9aae --- /dev/null +++ b/stdnum/rw/tin.py @@ -0,0 +1,82 @@ +# tin.py - functions for handling Rwanda TIN numbers +# coding: utf-8 +# +# Copyright (C) 2023 Leandro Regueiro +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +"""TIN (Taxpayer's Identification Number, Rwanda tax number). + +This number is also called "Numéro d'Identification du Contribuable", or +"Numéro d'identification fiscale" or "Nomero iranga umusoreshwa", and is also +shortened as "NIF". + +This number consists of 9 digits. + +More information: + +* https://businessprocedures.rdb.rw/procedure/13/47?l=en +* https://www.rra.gov.rw/en/home + +>>> validate('102134442') +'102134442' +>>> validate('10 7826151') +'107826151' +>>> validate('12345') +Traceback (most recent call last): + ... +InvalidLength: ... +>>> format('10 7826151') +'107826151' +""" # noqa: E501 + +from stdnum.exceptions import * +from stdnum.util import clean, isdigits + + +def compact(number): + """Convert the number to the minimal representation. + + This strips the number of any valid separators and removes surrounding + whitespace. + """ + return clean(number, ' -').strip() + + +def validate(number): + """Check if the number is a valid Rwanda TIN number. + + This checks the length and formatting. + """ + number = compact(number) + if len(number) != 9: + raise InvalidLength() + if not isdigits(number): + raise InvalidFormat() + return number + + +def is_valid(number): + """Check if the number is a valid Rwanda TIN number.""" + try: + return bool(validate(number)) + except ValidationError: + return False + + +def format(number): + """Reformat the number to the standard presentation format.""" + return compact(number) diff --git a/tests/test_rw_tin.doctest b/tests/test_rw_tin.doctest new file mode 100644 index 00000000..46e7fd4e --- /dev/null +++ b/tests/test_rw_tin.doctest @@ -0,0 +1,262 @@ +test_rw_tin.doctest - more detailed doctests for stdnum.rw.tin module + +Copyright (C) 2023 Leandro Regueiro + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA + + +This file contains more detailed doctests for the stdnum.rw.tin module. It +tries to test more corner cases and detailed functionality that is not really +useful as module documentation. + +>>> from stdnum.rw import tin + + +Tests for some corner cases. + +>>> tin.validate('102134442') +'102134442' +>>> tin.validate('10 7826151') +'107826151' +>>> tin.validate('12345') +Traceback (most recent call last): + ... +InvalidLength: ... +>>> tin.validate('1234567XX') +Traceback (most recent call last): + ... +InvalidFormat: ... +>>> tin.format('10 7826151') +'107826151' + + +These have been found online and should all be valid numbers. + +>>> numbers = ''' +... +... 102134442 +... 101365708 +... 100384138 +... 101453690 +... 101799622 +... 100054122 +... 101909790 +... 101522783 +... 102259397 +... 102889110 +... 101982714 +... 103752228 +... 103449745 +... 106278222 +... 100003547 +... 102241010 +... 101806185 +... 100003458 +... 102294535 +... 102781991 +... 102750860 +... 100003547 +... 100005973 +... 110842971 +... 102175071 +... 108311419 +... 107610471 +... 111414698 +... 107215286 +... 100475843 +... 104940576 +... 102050982 +... 101302769 +... 104741833 +... 108708667 +... 10 7826151 +... 103745842 +... 107907110 +... 102517684 +... 108630474 +... 102517692 +... 107877617 +... 100842224 +... 111304003 +... 102312520 +... 101411623 +... 102966085 +... 102026860 +... 120201204 +... 106363818 +... 102925497 +... 102503783 +... 101651018 +... 102874107 +... 106208031 +... 107993781 +... 101611834 +... 101313744 +... 101338997 +... 101832055 +... 101898817 +... 101742978 +... 101402045 +... 101369930 +... 101605491 +... 100600260 +... 101658248 +... 119491475 +... 100805888 +... 101725879 +... 101674807 +... 102420381 +... 101056837 +... 102580229 +... 103548327 +... 101669410 +... 100600293 +... 102760872 +... 120335672 +... 101332193 +... 101717108 +... 103372620 +... 111598890 +... 113333440 +... 102043412 +... 101351105 +... 101529751 +... 101337363 +... 001337363 +... 113653574 +... 101406098 +... 101639016 +... 101639016 +... 101932000 +... 101398024 +... 103012202 +... 100834445 +... 101992637 +... 111704557 +... 101846992 +... 101828601 +... 101734460 +... 120385529 +... 101790784 +... 101735377 +... 103144513 +... 102872114 +... 101566434 +... 102279886 +... 116904634 +... 101888471 +... 101587056 +... 101808480 +... 100834501 +... 101931624 +... 101615259 +... 101628996 +... 101868137 +... 101403075 +... 101823693 +... 111444309 +... 120434728 +... 101494914 +... 101507188 +... 101515599 +... 101599094 +... 101743183 +... 101354055 +... 001354055 +... 101330738 +... 100842023 +... 102831150 +... 102000244 +... 102106636 +... 101419173 +... 102065987 +... 100604778 +... 102502361 +... 101378645 +... 101667834 +... 100600431 +... 103058257 +... 101853419 +... 101052213 +... 101662117 +... 101474514 +... 102190813 +... 101896784 +... 119776770 +... 102496275 +... 100834479 +... 101397575 +... 101397028 +... 107433062 +... 100600456 +... 107429609 +... 107433046 +... 120576276 +... 107429659 +... 100840910 +... 101852144 +... 101541027 +... 101673002 +... 101687703 +... 101746067 +... 103644998 +... 101488481 +... 119491475 +... 100805888 +... 101725879 +... 101674807 +... 102420381 +... 101056837 +... 102580229 +... 103548327 +... 101669410 +... 100600293 +... 102543856 +... 107794257 +... 100600423 +... 103047835 +... 101671026 +... 101553163 +... 103061847 +... 106891578 +... 102704958 +... 101792173 +... 101774925 +... 101408122 +... 101535199 +... 101315485 +... 101880603 +... 101711471 +... 101753309 +... 101822442 +... 102059291 +... 120263565 +... 102058377 +... 102058506 +... 102060367 +... 101785453 +... 101895086 +... 101909790 +... 100604752 +... 000604752 +... 111983517 +... 112946918 +... 101310933 +... 111954363 +... +... ''' +>>> [x for x in numbers.splitlines() if x and not tin.is_valid(x)] +[]