1# cf.py - functions for handling Romanian CF (VAT) numbers 2# coding: utf-8 3# 4# Copyright (C) 2012-2015 Arthur de Jong 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"""CF (Cod de înregistrare în scopuri de TVA, Romanian VAT number). 22 23The Romanian CF is used for VAT purposes and can be from 2 to 10 digits long. 24 25>>> validate('RO 185 472 90') 26'18547290' 27>>> validate('185 472 91') 28Traceback (most recent call last): 29 ... 30InvalidChecksum: ... 31>>> validate('1630615123457') # personal code 32'1630615123457' 33""" 34 35from stdnum.exceptions import * 36from stdnum.ro import cnp 37from stdnum.util import clean, isdigits 38 39 40def compact(number): 41 """Convert the number to the minimal representation. This strips the 42 number of any valid separators and removes surrounding whitespace.""" 43 number = clean(number, ' -').upper().strip() 44 if number.startswith('RO'): 45 number = number[2:] 46 return number 47 48 49def calc_check_digit(number): 50 """Calculate the check digit for organisations. The number passed 51 should not have the check digit included.""" 52 weights = (7, 5, 3, 2, 1, 7, 5, 3, 2) 53 number = (9 - len(number)) * '0' + number 54 check = 10 * sum(w * int(n) for w, n in zip(weights, number)) 55 return str(check % 11 % 10) 56 57 58def validate(number): 59 """Check if the number is a valid VAT number. This checks the length, 60 formatting and check digit.""" 61 number = compact(number) 62 if not isdigits(number) or number[0] == '0': 63 raise InvalidFormat() 64 if len(number) == 13: 65 # apparently a CNP can also be used (however, not all sources agree) 66 cnp.validate(number) 67 elif 2 <= len(number) <= 10: 68 if calc_check_digit(number[:-1]) != number[-1]: 69 raise InvalidChecksum() 70 else: 71 raise InvalidLength() 72 return number 73 74 75def is_valid(number): 76 """Check if the number is a valid VAT number.""" 77 try: 78 return bool(validate(number)) 79 except ValidationError: 80 return False 81