Skip to content

Commit

Permalink
Add support for Pakisstan TIN
Browse files Browse the repository at this point in the history
Fixes #211.
  • Loading branch information
unho committed Sep 11, 2022
1 parent e40c827 commit a256b5d
Show file tree
Hide file tree
Showing 3 changed files with 364 additions and 0 deletions.
24 changes: 24 additions & 0 deletions stdnum/pk/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# __init__.py - collection of Pakistan numbers
# coding: utf-8
#
# Copyright (C) 2022 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 Pakistan numbers."""

# provide aliases
from stdnum.pk import ntn as vat # noqa: F401
83 changes: 83 additions & 0 deletions stdnum/pk/ntn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# ntn.py - functions for handling Pakistan NTN numbers
# coding: utf-8
#
# Copyright (C) 2022 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

"""NTN (National Tax Number, نیشنل ٹیکس نمبر, Pakistan tax number).
This number consists of 8 digits, the last being a check digit, usually
separated by a hyphen like XXXXXXX-X.
Companies and associations of persons (AOP) are assigned a National Tax Number
or Registration Number when they e-enroll on the FBR Iris portal.
More information:
* https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Pakistan-TIN.pdf
* https://e.fbr.gov.pk/
>>> validate('3804142-1')
'38041421'
>>> validate('0822910 - 4')
'08229104'
>>> validate('12345')
Traceback (most recent call last):
...
InvalidLength: ...
>>> format('38041421')
'3804142-1'
""" # 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, ' -')


def validate(number):
"""Check if the number is a valid Pakistan NTN number.
This checks the length, formatting and check digit.
"""
number = compact(number)
if len(number) != 8:
raise InvalidLength()
if not isdigits(number):
raise InvalidFormat()
return number


def is_valid(number):
"""Check if the number is a valid Pakistan NTN number."""
try:
return bool(validate(number))
except ValidationError:
return False


def format(number):
"""Reformat the number to the standard presentation format."""
number = compact(number)
return '-'.join([number[:-1], number[-1]])
257 changes: 257 additions & 0 deletions tests/test_pk_ntn.doctest
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
test_pk_ntn.doctest - more detailed doctests for stdnum.pk.ntn module

Copyright (C) 2022 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.pk.ntn module. It
tries to test more corner cases and detailed functionality that is not really
useful as module documentation.

>>> from stdnum.pk import ntn


Tests for some corner cases.

>>> ntn.validate('3804142-1')
'38041421'
>>> ntn.validate('0822910 - 4')
'08229104'
>>> ntn.validate('08229104')
'08229104'
>>> ntn.format('38041421')
'3804142-1'
>>> ntn.format('3804142-1')
'3804142-1'
>>> ntn.format('0822910 - 4')
'0822910-4'
>>> ntn.validate('12345')
Traceback (most recent call last):
...
InvalidLength: ...
>>> ntn.validate('3804142-X')
Traceback (most recent call last):
...
InvalidFormat: ...


These have been found online and should all be valid numbers.

>>> numbers = '''
...
... 3804142-1
... 0801599-6
... 0816469-0
... 0698343-0
... 0711795-7
... 0801380-2
... 2217220-3
... 2168117-1
... 0700271-8
... 0711545-8
... 2138500-9
... 3027108-8
... 0785983-0
... 4368251-7
... 1347561-4
... 1543137-1
... 0710060-4
... 0658560-4
... 0712242-0
... 0698049-0
... 2261899-6
... 0710672-6
... 1268238-1
... 1496632-8
... 0698202-6
... 3004934-2
... 0822910 - 4
... 0660564-8
... 2544314-3
... 0657297-9
... 0698187-9
... 1158490-4
... 0658678-3
... 0912725-9
... 1143539-9
... 0711554-7
... 0712418-0
... 0999468-8
... 2180652-7
... 0711167-3
... 0712140-7
... 0709930-4
... 0801137-7
... 1868111-5
... 0820781-0
... 0709782-4
... 0698190-9
... 0711982-8
... 0712821-5
... 0676546-7
... 0711020-7
... 7443848-2
... 0698469-0
... 1688091-9
... 3123405-4
... 0815616-6
... 1319140-3
... 7757795-2
... 3072746-4
... 0133480-8
... 2663705-7
... 0657139-5
... 0709694-1
... 3093299-8
... 6110823-3
... 6110854-7
... 6110874-0
... 6111000-0
... 6111008-8
... 6111233-8
... 6111402-6
... 6111534-3
... 6111639-0
... 6117056-8
... 6123199-4
... 6123937-4
... 6143138-8
... 6208694-8
... 6213642-6
... 6238197-0
... 6258534-6
... 6258594-3
... 6258628-1
... 6258698-8
... 6258699-0
... 6258712-4
... 6258719-2
... 6258739-4
... 6258851-8
... 6258861-0
... 6258868-7
... 6258987-0
... 6258988-1
... 6259020-6
... 6259077-0
... 6259177-1
... 6259188-3
... 6259345-7
... 6259393-1
... 6259485-3
... 6259580-8
... 6259606-7
... 6259614-6
... 6259631-5
... 6259636-1
... 6259654-1
... 6259673-2
... 6259684-4
... 6259702-4
... 6259723-7
... 6259761-0
... 6259848-6
... 6259872-3
... 6259949-8
... 6260025-3
... 6260034-3
... 6260067-0
... 6260127-6
... 6260162-5
... 6260189-5
... 6260285-2
... 6260292-0
... 6260294-2
... 6260301-0
... 6260306-5
... 6260307-6
... 6260308-7
... 6260313-3
... 6260314-4
... 6260315-5
... 6260324-5
... 6260334-6
... 6260421-3
... 6260442-6
... 6260623-7
... 6260640-6
... 6260664-3
... 6260687-8
... 6260720-5
... 6260838-6
... 6260840-8
... 6260841-0
... 6260882-5
... 6261128-8
... 6261138-0
... 6261140-2
... 6261155-8
... 6261158-2
... 6261165-0
... 6262127-8
... 6262231-4
... 6262235-8
... 6262277-5
... 6262304-5
... 6262338-3
... 6262384-4
... 6262397-8
... 6262398-0
... 6262426-1
... 6262476-6
... 6262509-3
... 6262559-8
... 6262697-2
... 6262748-8
... 6262838-8
... 6262842-3
... 6262845-6
... 6262849-1
... 6262995-3
... 6263002-1
... 6263010-0
... 6263057-2
... 6263064-0
... 6263094-3
... 6263157-3
... 6263217-0
... 6263229-3
... 6263265-3
... 6263268-6
... 6263276-5
... 6263300-2
... 6263402-5
... 6263404-7
... 6263444-2
... 6263619-6
... 6263734-4
... 6263752-4
... 6263824-4
... 6263826-6
... 6263927-8
... 6263930-2
... 6263980-7
... 6264015-6
... 6264034-7
... 6264038-2
... 6264083-2
... 6264107-8
... 6264112-4
...
... '''
>>> [x for x in numbers.splitlines() if x and not ntn.is_valid(x)]
[]

0 comments on commit a256b5d

Please sign in to comment.