diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2015-10-08 14:30:57 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2015-10-08 14:33:15 +0200 |
commit | 320ecea83701cf1a371e360542504414a6403249 (patch) | |
tree | c620cf7c6634877be0e9917d9babbfcc20ca7e38 /stdnum/ch | |
parent | ec9bcb0f13971b70e40dff7a6de3d4744ee4ea61 (diff) |
Add Swiss UID and VAT numbers
The Swiss VAT number (MWST, TVA, IVA, TPV) is the UID
(Unternehmens-Identifikationsnummer) followed by one of the VAT
abbreviations.
Diffstat (limited to 'stdnum/ch')
-rw-r--r-- | stdnum/ch/uid.py | 90 | ||||
-rw-r--r-- | stdnum/ch/vat.py | 79 |
2 files changed, 169 insertions, 0 deletions
diff --git a/stdnum/ch/uid.py b/stdnum/ch/uid.py new file mode 100644 index 0000000..6622f50 --- /dev/null +++ b/stdnum/ch/uid.py @@ -0,0 +1,90 @@ +# uid.py - functions for handling Swiss business identifiers +# coding: utf-8 +# +# Copyright (C) 2015 Arthur de Jong +# +# 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 + +"""UID (Unternehmens-Identifikationsnummer, Swiss business identifier). + +The Swiss UID is used to uniquely identify businesses for taxation purposes. +The number consists of a fixed "CHE" prefix, followed by 9 digits that are +protected with a simple checksum. + +This module only supports the "new" format that was introduced in 2011 which +completely replaced the "old" 6-digit format in 2014. + +More information is available at: + https://www.uid.admin.ch/ + https://de.wikipedia.org/wiki/Unternehmens-Identifikationsnummer + +>>> validate('CHE-100.155.212') +'CHE100155212' +>>> validate('CHE-100.155.213') +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> format('CHE100155212') +'CHE-100.155.212' +""" + +from stdnum.exceptions import * +from stdnum.util import clean + + +def compact(number): + """Convert the number to the minimal representation. This strips + surrounding whitespace and separators.""" + return clean(number, ' -.').strip().upper() + + +def calc_check_digit(number): + """Calculate the check digit for organisations. The number passed should + not have the check digit included.""" + weights = (5, 4, 3, 2, 7, 6, 5, 4) + s = sum(w * int(n) for w, n in zip(weights, number)) + return str((11 - s) % 11) + + +def validate(number): + """Checks to see if the number provided is a valid number. This checks + the length, formatting and check digit.""" + number = compact(number) + if len(number) != 12: + raise InvalidLength() + if not number.startswith('CHE'): + raise InvalidComponent() + if not number[3:].isdigit(): + raise InvalidFormat() + if number[-1] != calc_check_digit(number[3:-1]): + raise InvalidChecksum() + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid number. This checks + the length, formatting and check digit.""" + try: + return bool(validate(number)) + except ValidationError: + return False + + +def format(number): + """Reformat the passed number to the standard format.""" + number = compact(number) + return number[:3] + '-' + '.'.join( + number[i:i + 3] for i in range(3, len(number), 3)) diff --git a/stdnum/ch/vat.py b/stdnum/ch/vat.py new file mode 100644 index 0000000..a61c49e --- /dev/null +++ b/stdnum/ch/vat.py @@ -0,0 +1,79 @@ +# vat.py - functions for handling Swiss VAT numbers +# coding: utf-8 +# +# Copyright (C) 2015 Arthur de Jong +# +# 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 + +"""VAT, MWST, TVA, IVA, TPV (Mehrwertsteuernummer, the Swiss VAT number). + +The Swiss VAT number is based on the UID but is followed by either "MWST" +(Mehrwertsteuer, the German abbreviation for VAT), "TVA" (Taxe sur la valeur +ajoutée in French), "IVA" (Imposta sul valore aggiunto in Italian) or "TPV" +(Taglia sin la plivalur in Romanian). + +This module only supports the "new" format that was introduced in 2011 which +completely replaced the "old" 6-digit format in 2014. + +More information is available at: + https://www.ch.ch/en/value-added-tax-number-und-business-identification-number/ + https://www.uid.admin.ch/ + +>>> validate('CHE-107.787.577 IVA') +'CHE107787577IVA' +>>> validate('CHE-107.787.578 IVA') +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> format('CHE107787577IVA') +'CHE-107.787.577 IVA' +""" + +from stdnum.exceptions import * +from stdnum.ch import uid + + +def compact(number): + """Convert the number to the minimal representation. This strips + surrounding whitespace and separators.""" + return uid.compact(number) + + +def validate(number): + """Checks to see if the number provided is a valid number. This checks + the length, formatting and check digit.""" + number = compact(number) + if len(number) not in (15, 16): + raise InvalidLength() + uid.validate(number[:12]) + if number[12:] not in ('MWST', 'TVA', 'IVA', 'TPV'): + raise InvalidComponent() + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid number. This checks + the length, formatting and check digit.""" + try: + return bool(validate(number)) + except ValidationError: + return False + + +def format(number): + """Reformat the passed number to the standard format.""" + number = compact(number) + return uid.format(number[:12]) + ' ' + number[12:] |