lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 1.17-20-gc5595c7

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

python-stdnum branch master updated. 1.17-20-gc5595c7



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  c5595c7e80277bbf2102f293c1f4fbcec07f7101 (commit)
      from  4d4a0b35dd8db8a4ddba469dc2cb646f1f877785 (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=c5595c7e80277bbf2102f293c1f4fbcec07f7101

commit c5595c7e80277bbf2102f293c1f4fbcec07f7101
Author: petr.prikryl <petr.prikryl@olc.cz>
Date:   Wed Jun 8 17:14:40 2022 +0200

    Add Czech bank account numbers
    
    Closes https://github.com/arthurdejong/python-stdnum/issues/295
    Closes https://github.com/arthurdejong/python-stdnum/pull/296

diff --git a/stdnum/cz/bankaccount.py b/stdnum/cz/bankaccount.py
new file mode 100644
index 0000000..76169a6
--- /dev/null
+++ b/stdnum/cz/bankaccount.py
@@ -0,0 +1,133 @@
+# bankaccount.py - functions for handling Czech bank account numbers
+# coding: utf-8
+#
+# Copyright (C) 2022 Petr Přikryl
+#
+# 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
+
+"""Czech bank account number.
+
+The Czech bank account numbers consist of up to 20 digits:
+    UUUUUK-MMMMMMMMKM/XXXX
+
+The first part is prefix that is up to 6 digits. The following part is from 2 
to 10 digits.
+Both parts could be filled with zeros from left if missing.
+The final 4 digits represent the bank code.
+
+More information:
+
+* 
https://www.penize.cz/osobni-ucty/424173-tajemstvi-cisla-uctu-klicem-pro-banky-je-11
+* http://www.zlatakoruna.info/zpravy/ucty/cislo-uctu-v-cr
+
+>>> validate('34278-0727558021/0100')
+'034278-0727558021/0100'
+>>> validate('4278-727558021/0100')  # invalid check digits (prefix)
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> validate('34278-727558021/0000')  # invalid bank
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> format('34278-727558021/0100')
+'034278-0727558021/0100'
+>>> to_bic('34278-727558021/0100')
+'KOMBCZPP'
+"""
+
+import re
+
+from stdnum.exceptions import *
+from stdnum.util import clean
+
+
+_bankaccount_re = re.compile(
+    r'((?P<prefix>[0-9]{0,6})-)?(?P<root>[0-9]{2,10})\/(?P<bank>[0-9]{4})')
+
+
+def compact(number):
+    """Convert the number to the minimal representation. This strips the
+    number of any valid separators and removes surrounding whitespace."""
+    number = clean(number).strip()
+    match = _bankaccount_re.match(number)
+    if match:
+        # zero-pad valid numbers
+        prefix = (match.group('prefix') or '').zfill(6)
+        root = match.group('root').zfill(10)
+        number = ''.join((prefix, '-', root, '/', match.group('bank')))
+    return number
+
+
+def _split(number):
+    """Split valid numbers into prefix, root and bank parts of the number."""
+    match = _bankaccount_re.match(number)
+    if not match:
+        raise InvalidFormat()
+    return match.group('prefix'), match.group('root'), match.group('bank')
+
+
+def _info(bank):
+    """Look up information for the bank."""
+    from stdnum import numdb
+    info = {}
+    for nr, found in numdb.get('cz/banks').info(bank):
+        info.update(found)
+    return info
+
+
+def info(number):
+    """Return a dictionary of data about the supplied number. This typically
+    returns the name of the bank and branch and a BIC if it is valid."""
+    prefix, root, bank = _split(compact(number))
+    return _info(bank)
+
+
+def to_bic(number):
+    """Return the BIC for the bank that this number refers to."""
+    bic = info(number).get('bic')
+    if bic:
+        return str(bic)
+
+
+def _calc_checksum(number):
+    weights = (6, 3, 7, 9, 10, 5, 8, 4, 2, 1)
+    return sum(w * int(n) for w, n in zip(weights, number.zfill(10))) % 11
+
+
+def validate(number):
+    """Check if the number provided is a valid bank account number."""
+    number = compact(number)
+    prefix, root, bank = _split(number)
+    if _calc_checksum(prefix) != 0:
+        raise InvalidChecksum()
+    if _calc_checksum(root) != 0:
+        raise InvalidChecksum()
+    if 'bank' not in _info(bank):
+        raise InvalidComponent()
+    return number
+
+
+def is_valid(number):
+    """Check if the number provided is a valid bank account number."""
+    try:
+        return bool(validate(number))
+    except ValidationError:
+        return False
+
+
+def format(number):
+    """Reformat the number to the standard presentation format."""
+    return compact(number)
diff --git a/stdnum/cz/banks.dat b/stdnum/cz/banks.dat
new file mode 100644
index 0000000..df1a272
--- /dev/null
+++ b/stdnum/cz/banks.dat
@@ -0,0 +1,59 @@
+# generated from kody_bank_CR.csv downloaded from
+# 
https://www.cnb.cz/cs/platebni-styk/.galleries/ucty_kody_bank/download/kody_bank_CR.csv
+0100 bic="KOMBCZPP" bank="Komerční banka, a.s." certis="True"
+0300 bic="CEKOCZPP" bank="Československá obchodní banka, a. s." certis="True"
+0600 bic="AGBACZPP" bank="MONETA Money Bank, a.s." certis="True"
+0710 bic="CNBACZPP" bank="ČESKÁ NÁRODNÍ BANKA" certis="True"
+0800 bic="GIBACZPX" bank="Česká spořitelna, a.s." certis="True"
+2010 bic="FIOBCZPP" bank="Fio banka, a.s." certis="True"
+2020 bic="BOTKCZPP" bank="MUFG Bank (Europe) N.V. Prague Branch" certis="True"
+2060 bic="CITFCZPP" bank="Citfin, spořitelní družstvo" certis="True"
+2070 bic="MPUBCZPP" bank="TRINITY BANK a.s." certis="True"
+2100 bank="Hypoteční banka, a.s." certis="True"
+2200 bank="Peněžní dům, spořitelní družstvo" certis="True"
+2220 bic="ARTTCZPP" bank="Artesa, spořitelní družstvo" certis="True"
+2250 bic="CTASCZ22" bank="Banka CREDITAS a.s." certis="True"
+2260 bank="NEY spořitelní družstvo" certis="True"
+2275 bank="Podnikatelská družstevní záložna"
+2600 bic="CITICZPX" bank="Citibank Europe plc, organizační složka"
+2700 bic="BACXCZPP" bank="UniCredit Bank Czech Republic and Slovakia, a.s." 
certis="True"
+3030 bic="AIRACZPP" bank="Air Bank a.s." certis="True"
+3050 bic="BPPFCZP1" bank="BNP Paribas Personal Finance SA, odštěpný závod" 
certis="True"
+3060 bic="BPKOCZPP" bank="PKO BP S.A., Czech Branch" certis="True"
+3500 bic="INGBCZPP" bank="ING Bank N.V." certis="True"
+4000 bic="EXPNCZPP" bank="Expobank CZ a.s." certis="True"
+4300 bic="NROZCZPP" bank="Národní rozvojová banka, a.s." certis="True"
+5500 bic="RZBCCZPP" bank="Raiffeisenbank a.s." certis="True"
+5800 bic="JTBPCZPP" bank="J&T BANKA, a.s."
+6000 bic="PMBPCZPP" bank="PPF banka a.s." certis="True"
+6100 bic="EQBKCZPP" bank="Raiffeisenbank a.s. (do 31. 12. 2021 Equa bank 
a.s.)" certis="True"
+6200 bic="COBACZPX" bank="COMMERZBANK Aktiengesellschaft, pobočka Praha" 
certis="True"
+6210 bic="BREXCZPP" bank="mBank S.A., organizační složka" certis="True"
+6300 bic="GEBACZPP" bank="BNP Paribas S.A., pobočka Česká republika" 
certis="True"
+6700 bic="SUBACZPP" bank="Všeobecná úverová banka a.s., pobočka Praha" 
certis="True"
+6800 bic="VBOECZ2X" bank="Sberbank CZ, a.s. v likvidaci" certis="True"
+7910 bic="DEUTCZPX" bank="Deutsche Bank Aktiengesellschaft Filiale Prag, 
organizační složka" certis="True"
+7950 bank="Raiffeisen stavební spořitelna a.s." certis="True"
+7960 bank="ČSOB Stavební spořitelna, a.s." certis="True"
+7970 bank="MONETA Stavební Spořitelna, a.s." certis="True"
+7990 bank="Modrá pyramida stavební spořitelna, a.s." certis="True"
+8030 bic="GENOCZ21" bank="Volksbank Raiffeisenbank Nordoberpfalz eG pobočka 
Cheb" certis="True"
+8040 bic="OBKLCZ2X" bank="Oberbank AG pobočka Česká republika" certis="True"
+8060 bank="Stavební spořitelna České spořitelny, a.s." certis="True"
+8090 bic="CZEECZPP" bank="Česká exportní banka, a.s." certis="True"
+8150 bic="MIDLCZPP" bank="HSBC Continental Europe, Czech Republic" 
certis="True"
+8190 bank="Sparkasse Oberlausitz-Niederschlesien" certis="True"
+8198 bic="FFCSCZP1" bank="FAS finance company s.r.o."
+8199 bic="MOUSCZP2" bank="MoneyPolo Europe s.r.o."
+8200 bank="PRIVAT BANK der Raiffeisenlandesbank Oberösterreich 
Aktiengesellschaft, pobočka Česká republika"
+8220 bic="PAERCZP1" bank="Payment execution s.r.o."
+8230 bank="ABAPAY s.r.o."
+8240 bank="Družstevní záložna Kredit, v likvidaci"
+8250 bic="BKCHCZPP" bank="Bank of China (CEE) Ltd. Prague Branch" certis="True"
+8255 bic="COMMCZPP" bank="Bank of Communications Co., Ltd., Prague Branch 
odštěpný závod" certis="True"
+8265 bic="ICBKCZPP" bank="Industrial and Commercial Bank of China Limited, 
Prague Branch, odštěpný závod" certis="True"
+8270 bic="FAPOCZP1" bank="Fairplay Pay s.r.o."
+8280 bic="BEFKCZP1" bank="B-Efekt a.s."
+8293 bic="MRPSCZPP" bank="Mercurius partners s.r.o."
+8299 bic="BEORCZP2" bank="BESTPAY s.r.o."
+8500 bank="Ferratum Bank plc"
diff --git a/tests/test_cz_bankaccount.doctest 
b/tests/test_cz_bankaccount.doctest
new file mode 100644
index 0000000..d140992
--- /dev/null
+++ b/tests/test_cz_bankaccount.doctest
@@ -0,0 +1,59 @@
+test_cz_bankaccount.doctest - more detailed doctests for stdnum.cz.bankaccount
+
+Copyright (C) 2022 Petr Přikryl
+
+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.cz.bankaccount
+module.
+
+>>> from stdnum.cz import bankaccount
+
+>>> bankaccount.validate('34278-0727558021/0100')
+'034278-0727558021/0100'
+>>> bankaccount.is_valid('4278-0727558021/0100')  # missing initial digit
+False
+>>> bankaccount.to_bic('34278-0727558021/0100')
+'KOMBCZPP'
+>>> bankaccount.compact('1/0100')
+'1/0100'
+>>> bankaccount.compact('12/0100')
+'000000-0000000012/0100'
+>>> bankaccount.validate('1/0100')
+Traceback (most recent call last):
+    ...
+bankaccount.InvalidFormat: ...
+>>> bankaccount.validate('8021/0100')
+Traceback (most recent call last):
+    ...
+bankaccount.InvalidChecksum: ...
+>>> bankaccount.to_bic('0727558021/2260')
+
+
+These have been found online and should all be valid numbers.
+
+>>> numbers = '''
+...
+... 19-2000145399/0800
+... 178124-4159/0710
+... 19-34222621/0710
+... 280154417/0300
+... 0500021502/0800
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not bankaccount.is_valid(x)]
+[]
diff --git a/update/cz_banks.py b/update/cz_banks.py
new file mode 100755
index 0000000..fd7c976
--- /dev/null
+++ b/update/cz_banks.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+# coding: utf-8
+
+# update/cz_banks.py - script to download Bank list from Czech National Bank
+#
+# Copyright (C) 2022 Petr Přikryl
+#
+# 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 script downloads the list of banks with bank codes as used in the
+IBAN and BIC codes as published by the Czech National Bank."""
+
+import csv
+import os.path
+from io import StringIO
+
+import requests
+
+
+# The location of the CSV version of the bank identification codes. Also see
+# https://www.cnb.cz/cs/platebni-styk/ucty-kody-bank/
+download_url = 
'https://www.cnb.cz/cs/platebni-styk/.galleries/ucty_kody_bank/download/kody_bank_CR.csv'
+
+
+def get_values(csv_reader):
+    """Return values (bank_number, bic, bank_name, certis) from the CSV."""
+    # skip first row (header)
+    try:
+        next(csv_reader)
+    except StopIteration:
+        pass  # ignore empty CSV
+
+    for row in csv_reader:
+        yield row[0], row[2], row[1], row[3] == 'A'
+
+
+if __name__ == '__main__':
+    response = requests.get(download_url)
+    response.raise_for_status()
+    csv_reader = csv.reader(StringIO(response.content.decode('utf-8')), 
delimiter=';')
+    print('# generated from %s downloaded from' % 
os.path.basename(download_url))
+    print('# %s' % download_url)
+    for bank_number, bic, bank, certis in get_values(csv_reader):
+        info = '%s' % bank_number
+        if bic:
+            info += ' bic="%s"' % bic
+        if bank:
+            info += ' bank="%s"' % bank
+        if certis:
+            info += ' certis="%s"' % certis
+        print(info)

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

Summary of changes:
 stdnum/cz/bankaccount.py          | 133 ++++++++++++++++++++++++++++++++++++++
 stdnum/cz/banks.dat               |  59 +++++++++++++++++
 tests/test_cz_bankaccount.doctest |  59 +++++++++++++++++
 update/cz_banks.py                |  64 ++++++++++++++++++
 4 files changed, 315 insertions(+)
 create mode 100644 stdnum/cz/bankaccount.py
 create mode 100644 stdnum/cz/banks.dat
 create mode 100644 tests/test_cz_bankaccount.doctest
 create mode 100755 update/cz_banks.py


hooks/post-receive
-- 
python-stdnum