lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 1.12-1-ga45d4f7

[Date Prev][Date Next] [Thread Prev][Thread Next]

python-stdnum branch master updated. 1.12-1-ga45d4f7



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".

The branch, master has been updated
       via  a45d4f705e7f59ee3e6314491c47199d0d5aa581 (commit)
      from  41b9c946c92f344eb2537e877215e1b75d6abff7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://arthurdejong.org/git/python-stdnum/commit/?id=a45d4f705e7f59ee3e6314491c47199d0d5aa581

commit a45d4f705e7f59ee3e6314491c47199d0d5aa581
Author: Kurt Keller <Kurt@pinboard.jp>
Date:   Sat Nov 2 19:32:40 2019 +0100

    Add Swiss ESR/ISR/QR-reference
    
    Closes https://github.com/arthurdejong/python-stdnum/pull/170

diff --git a/stdnum/ch/esr.py b/stdnum/ch/esr.py
new file mode 100644
index 0000000..862df78
--- /dev/null
+++ b/stdnum/ch/esr.py
@@ -0,0 +1,98 @@
+# esr.py - functions for handling Swiss EinzahlungsSchein mit Referenznummer
+# coding: utf-8
+#
+# Copyright (C) 2019 Kurt Keller
+# Copyright (C) 2019 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
+
+"""ESR, ISR, QR-reference (reference number on Swiss payment slips).
+
+The ESR (Eizahlungsschein mit Referenznummer), ISR (In-payment Slip with
+Reference Number) or QR-reference refers to the orange payment slip in
+Switzerland with which money can be transferred to an account. The slip
+contains a machine-readable part that contains a participant number and
+reference number. The participant number ensures the crediting to the
+corresponding account. The reference number enables the creditor to identify
+the invoice recipient. In this way, the payment process can be handled
+entirely electronically.
+
+The number consists of 26 numerical characters followed by a Modulo 10
+recursive check digit. It is printed in blocks of 5 characters (beginning
+with 2 characters, then 5x5-character groups). Leading zeros digits can be
+omitted.
+
+More information:
+
+* https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-en.pdf
+
+>>> validate('21 00000 00003 13947 14300 09017')
+'210000000003139471430009017'
+>>> validate('210000000003139471430009016')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> format('18 78583')
+'00 00000 00000 00000 00018 78583'
+"""
+
+from stdnum.exceptions import *
+from stdnum.util import clean, isdigits
+
+
+def compact(number):
+    """Convert the number to the minimal representation. This strips
+    surrounding whitespace and separators."""
+    return clean(number, ' ').lstrip('0')
+
+
+def calc_check_digit(number):
+    """Calculate the check digit for number. The number passed should
+    not have the check digit included."""
+    _digits = (0, 9, 4, 6, 8, 2, 7, 1, 3, 5)
+    c = 0
+    for n in compact(number):
+        c = _digits[(int(n) + c) % 10]
+    return str((10 - c) % 10)
+
+
+def validate(number):
+    """Check if the number is a valid ESR. This checks the length, formatting
+    and check digit."""
+    number = compact(number)
+    if len(number) > 27:
+        raise InvalidLength()
+    if not isdigits(number):
+        raise InvalidFormat()
+    if number[-1] != calc_check_digit(number[:-1]):
+        raise InvalidChecksum()
+    return number
+
+
+def is_valid(number):
+    """Check if the number is a valid ESR."""
+    try:
+        return bool(validate(number))
+    except ValidationError:
+        return False
+
+
+def format(number):
+    """Reformat the number to the standard presentation format."""
+    number = 27 * '0' + compact(number)
+    number = number[-27:]
+    return number[:2] + ' ' + ' '.join(
+        number[i:i + 5] for i in range(2, len(number), 5))
diff --git a/tests/test_ch_esr.doctest b/tests/test_ch_esr.doctest
new file mode 100644
index 0000000..5fa31da
--- /dev/null
+++ b/tests/test_ch_esr.doctest
@@ -0,0 +1,64 @@
+test_ch_esr.doctest - more detailed doctests for the stdnum.ch.esr module
+
+Copyright (C) 2019 Kurt Keller
+
+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.ch.esr module.
+
+>>> from stdnum.ch import esr
+>>> from stdnum.exceptions import *
+
+
+Some more detailed tests.
+
+>>> esr.validate('210000000003139471430009016')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> esr.validate('2100000000031394714300090168')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> esr.validate('21000000000313947143000TE45')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+
+
+These have been taken from actual payment slips and should all be valid
+numbers.
+
+>>> numbers = '''
+...
+... 20 12440 00000 46370 02019 05153
+... 1009 76741 00001 47457 50114
+... 1001007711461312058
+... 361610000000000020190704093
+... 31 23711 80610 58530 00071 92101
+... 18 78583
+... 36 13030 00000 00000 00000 04142
+... 01 73575 51208 21125 03398 69724
+... 2101315000320229184501
+... 90 00170 00000 00214 95962 25686
+... 432130000000000573490016096
+... 201244000000463700201900994
+... 32 29790 00000 19151 00002 79617
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not esr.is_valid(x)]
+[]

-----------------------------------------------------------------------

Summary of changes:
 stdnum/ch/esr.py                                   | 98 ++++++++++++++++++++++
 tests/{test_nz_ird.doctest => test_ch_esr.doctest} | 52 ++++++------
 2 files changed, 122 insertions(+), 28 deletions(-)
 create mode 100644 stdnum/ch/esr.py
 copy tests/{test_nz_ird.doctest => test_ch_esr.doctest} (51%)


hooks/post-receive
-- 
python-stdnum