1# ird.py - functions for handling New Zealand IRD numbers 2# coding: utf-8 3# 4# Copyright (C) 2019 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"""IRD number (New Zealand Inland Revenue Department (Te Tari Tāke) number). 22 23The IRD number is used by the New Zealand Inland Revenue Department (Te Tari 24Tāke in Māori) to identify businesses and individuals for tax purposes. The 25number consists of 8 or 9 digits where the last digit is a check digit. 26 27More information: 28 29* https://www.ird.govt.nz/ 30* https://www.ird.govt.nz/-/media/Project/IR/PDF/2020RWTNRWTSpecificationDocumentv10.pdf 31* https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/New%20Zealand-TIN.pdf 32 33>>> validate('4909185-0') 34'49091850' 35>>> validate('NZ 49-098-576') 36'49098576' 37>>> validate('136410133') 38Traceback (most recent call last): 39 ... 40InvalidChecksum: ... 41>>> validate('9125568') 42Traceback (most recent call last): 43 ... 44InvalidLength: ... 45>>> format('49098576') 46'49-098-576' 47""" 48 49from stdnum.exceptions import * 50from stdnum.util import clean, isdigits 51 52 53def compact(number): 54 """Convert the number to the minimal representation.""" 55 number = clean(number, ' -').upper().strip() 56 if number.startswith('NZ'): 57 return number[2:] 58 return number 59 60 61def calc_check_digit(number): 62 """Calculate the check digit. 63 64 The number passed should not have the check digit included. 65 """ 66 primary_weights = (3, 2, 7, 6, 5, 4, 3, 2) 67 secondary_weights = (7, 4, 3, 2, 5, 2, 7, 6) 68 # pad with leading zeros 69 number = (8 - len(number)) * '0' + number 70 s = -sum(w * int(n) for w, n in zip(primary_weights, number)) % 11 71 if s != 10: 72 return str(s) 73 s = -sum(w * int(n) for w, n in zip(secondary_weights, number)) % 11 74 return str(s) 75 76 77def validate(number): 78 """Check if the number is a valid IRD number.""" 79 number = compact(number) 80 if len(number) not in (8, 9): 81 raise InvalidLength() 82 if not isdigits(number): 83 raise InvalidFormat() 84 if not 10000000 < int(number) < 150000000: 85 raise InvalidComponent() 86 if number[-1] != calc_check_digit(number[:-1]): 87 raise InvalidChecksum() 88 return number 89 90 91def is_valid(number): 92 """Check if the number is a valid IRD number.""" 93 try: 94 return bool(validate(number)) 95 except ValidationError: 96 return False 97 98 99def format(number): 100 """Reformat the number to the standard presentation format.""" 101 number = compact(number) 102 return '-'.join([number[:-6], number[-6:-3], number[-3:]]) 103