]> git.ipfire.org Git - thirdparty/python-fints.git/commitdiff
Add get_statement
authorRaphael Michel <mail@raphaelmichel.de>
Mon, 2 Jan 2017 19:34:44 +0000 (20:34 +0100)
committerRaphael Michel <mail@raphaelmichel.de>
Mon, 2 Jan 2017 19:34:44 +0000 (20:34 +0100)
README.md
fints3/client.py
fints3/message.py
fints3/segments/statement.py [new file with mode: 0644]
fints3/utils.py
requirements.txt

index 1c5a0a9a6f0176a0a7e4af52dcdfbe22c805540a..7971656f9f51bf2d137fa268d28c8ee29f589930 100644 (file)
--- a/README.md
+++ b/README.md
@@ -25,8 +25,17 @@ Usage
         'https://mybank.com/…'  # endpoint, e.g.: https://hbci-pintan.gad.de/cgi-bin/hbciservlet
     )
 
-    print(f.get_sepa_accounts())
-
+    accounts = f.get_sepa_accounts()
+    print(accounts)
+    # [SEPAAccount(iban='DE12345678901234567890', bic='ABCDEFGH1DEF', accountnumber='123456790', subaccount='',
+    #              blz='123456789')]
+
+    statement = f.get_statement(accounts[0], date(2016, 12, 1), date.today())
+    print([t.data for t in statement])
+    # The statement is a list of transaction objects as parsed by the mt940 parser, see
+    # https://mt940.readthedocs.io/en/latest/mt940.html#mt940.models.Transaction
+    # for documentation. Most information is contained in a dict accessible via their
+    # ``data`` property
 
 Credits and License
 -------------------
index b52ed7206d6cc59c60b2d473f132ab9a93e539bd..81b84cf69bc2b4302636c056b44a4d6a98a444f1 100644 (file)
@@ -1,10 +1,14 @@
 import logging
 
-from .segments.accounts import HKSPA
+import re
+
 from .connection import FinTSHTTPSConnection
 from .dialog import FinTSDialog
 from .message import FinTSMessage
 from .models import SEPAAccount
+from .segments.accounts import HKSPA
+from .segments.statement import HKKAZ
+from .utils import mt940_to_array
 
 logger = logging.getLogger(__name__)
 
@@ -45,6 +49,71 @@ class FinTS3Client:
 
         return self.accounts
 
+    def get_statement(self, account, start_date, end_date):
+        logger.info('Start fetching from {} to {}'.format(start_date, end_date))
+
+        dialog = self._new_dialog()
+        dialog.sync()
+        dialog.init()
+
+        msg = self._create_statement_message(dialog, account, start_date, end_date, None)
+        resp = dialog.send(msg)
+        touchdowns = resp.get_touchdowns(msg)
+        responses = [resp]
+        touchdown_counter = 1
+
+        while HKKAZ.type in touchdowns:
+            logger.info('Fetching more results ({})...'.format(touchdown_counter))
+            msg = self._create_statement_message(dialog, account, start_date, end_date, touchdowns[HKKAZ.type])
+
+            resp = dialog.send(msg)
+            responses.append(resp)
+            touchdowns = resp.get_touchdowns(msg)
+
+            touchdown_counter += 1
+
+        logger.info('Fetching done.')
+
+        re_data = re.compile(r'[^@]*@([0-9]+)@(.+)', flags=re.MULTILINE | re.DOTALL)
+        statement = []
+        for resp in responses:
+            seg = resp._find_segment('HIKAZ')
+            if seg:
+                m = re_data.match(seg)
+                if m:
+                    statement += mt940_to_array(m.group(2))
+
+        logger.debug('Statement: {}'.format(statement))
+
+        dialog.end()
+        return statement
+
+    def _create_statement_message(self, dialog: FinTSDialog, account: SEPAAccount, start_date, end_date, touchdown):
+        hversion = dialog.hkkazversion
+
+        if hversion in (4, 5, 6):
+            acc = ':'.join([
+                account.accountnumber, account.subaccount, str(280), account.blz
+            ])
+        elif hversion == 7:
+            acc = ':'.join([
+                account.iban, account.bic, account.accountnumber, account.subaccount, str(280), account.blz
+            ])
+        else:
+            raise ValueError('Unsupported HKKAZ version {}'.format(hversion))
+
+        return self._new_message(dialog, [
+            HKKAZ(
+                3,
+                hversion,
+                acc,
+                start_date,
+                end_date,
+                touchdown
+            )
+        ])
+
+
 
 class FinTS3PinTanClient(FinTS3Client):
     def __init__(self, blz, username, pin, server):
index b5fe3cf372f5e99f43660dc3a2d33091cb17c032..9ec14a35d5867389f7b4e6d526b7536915cb1161 100644 (file)
@@ -144,6 +144,26 @@ class FinTSResponse:
                         return [m.group(0)]
         return False
 
+    def _find_segment_for_reference(self, name, ref):
+        segs = self._find_segments(name)
+        for seg in segs:
+            segsplit = seg.split('+')[0].split(':')
+            if segsplit[3] == str(ref.segmentno):
+                return seg
+
+    def get_touchdowns(self, msg: FinTSMessage):
+        touchdown = {}
+        for msgseg in msg.encrypted_segments:
+            seg = self._find_segment_for_reference('HIRMS', msgseg)
+            if seg:
+                parts = seg.split('+')[1:]
+                for p in parts:
+                    psplit = p.split(':')
+                    if psplit[0] == "3040":
+                        td = psplit[3]
+                        touchdown[msgseg.type] = td
+        return touchdown
+
     def _get_segment_max_version(self, name):
         v = 3
         segs = self._find_segments(name)
diff --git a/fints3/segments/statement.py b/fints3/segments/statement.py
new file mode 100644 (file)
index 0000000..9d58aba
--- /dev/null
@@ -0,0 +1,23 @@
+import time
+from . import FinTS3Segment
+
+
+class HKKAZ(FinTS3Segment):
+    """
+    HKKAZ (Kontoumsätze)
+    Section C.2.1.1.1.2
+    """
+    type = 'HKKAZ'
+
+    def __init__(self, segno, version, account, date_start, date_end, touchdown):
+        self.version = version
+
+        data = [
+            account,
+            'N',
+            date_start.strftime('%Y%m%d'),
+            date_end.strftime('%Y%m%d'),
+            '',
+            touchdown if touchdown is not None else ''
+        ]
+        super().__init__(segno, data)
index 28eb3a9039488a94a84346f80ad90aec5f0a7800..bcc10c3c243e293ffe8723d6176e59bee7117622 100644 (file)
@@ -1,13 +1,7 @@
-def segments_to_ascii(segments, counter=1):
-    ascii = ''
+import mt940
 
-    for segment in segments:
-        # do only set counter if is 0; see B.8
-        if segment.get_counter() == 0:
-            counter += 1
-            segment.set_counter(counter)
 
-        s = segment.to_ascii()
-        ascii += s + "'"
-
-    return counter, ascii
+def mt940_to_array(data):
+    data = data.replace("@@", "\r\n")
+    transactions = mt940.models.Transactions()
+    return transactions.parse(data)
index 3288e9274ec871693283821758d00e89be82a8fd..3b33fbc473554584987fbcb14211b5ab3d9b6b6c 100644 (file)
@@ -1,2 +1,3 @@
 requests
+mt-940