Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/stdnum/ch
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2015-10-08 14:30:57 +0200
committerArthur de Jong <arthur@arthurdejong.org>2015-10-08 14:33:15 +0200
commit320ecea83701cf1a371e360542504414a6403249 (patch)
treec620cf7c6634877be0e9917d9babbfcc20ca7e38 /stdnum/ch
parentec9bcb0f13971b70e40dff7a6de3d4744ee4ea61 (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.py90
-rw-r--r--stdnum/ch/vat.py79
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:]