]> git.ipfire.org Git - thirdparty/python-fints.git/commitdiff
(Re-)implement get_statement() in new API
authorHenryk Plötz <henryk@ploetzli.ch>
Mon, 20 Aug 2018 22:59:04 +0000 (00:59 +0200)
committerRaphael Michel <mail@raphaelmichel.de>
Mon, 3 Dec 2018 18:34:29 +0000 (19:34 +0100)
fints/client.py
fints/message.py
fints/segments/statement.py

index e43c6f5a4259ec35fc575d2af66795750d39be7d..f38c50376871f254ba41a93ad9eafebc829a60fc 100644 (file)
@@ -26,8 +26,8 @@ from .segments.accounts import HISPA1, HKSPA, HKSPA1
 from .segments.auth import HKTAB, HKTAN
 from .segments.depot import HKWPD
 from .segments.dialog import HISYN4, HKSYN3
-from .segments.saldo import HISAL5, HISAL6, HISAL7, HKSAL5, HKSAL6, HKSAL7
-from .segments.statement import HKKAZ
+from .segments.saldo import HKSAL5, HKSAL6, HKSAL7
+from .segments.statement import HKKAZ5, HKKAZ6, HKKAZ7
 from .segments.transfer import HKCCM, HKCCS
 from .types import SegmentSequence
 from .utils import MT535_Miniparser, Password, mt940_to_array
@@ -110,7 +110,7 @@ class FinTS3Client:
 
         return [a for a in [acc.as_sepa_account() for acc in self.accounts] if a]
 
-    def get_statement(self, account: SEPAAccount, start_date: datetime.datetime, end_date: datetime.date):
+    def get_statement(self, account: SEPAAccount, start_date: datetime.date, end_date: datetime.date):
         """
         Fetches the statement of a bank account in a certain timeframe.
 
@@ -119,77 +119,58 @@ class FinTS3Client:
         :param end_date: Last day to fetch
         :return: A list of mt940.models.Transaction objects
         """
-        logger.info('Start fetching from {} to {}'.format(start_date, end_date))
 
-        dialog = self._new_dialog()
-        dialog.sync()
-        dialog.init()
-
-        def _get_msg():
-            return self._create_statement_message(dialog, account, start_date, end_date, None)
-
-        with self.pin.protect():
-            logger.debug('Send message: {}'.format(_get_msg()))
+        with self._new_dialog() as dialog:
+            max_hikazs = self.bpd.find_segment_highest_version('HIKAZS', (5, 6, 7))
+            if not max_hikazs:
+                raise ValueError('No supported HIKAZS version found')
+
+            hkkaz = {
+                5: HKKAZ5,
+                6: HKKAZ6,
+                7: HKKAZ7,
+            }.get(max_hikazs.header.version)
+
+            responses = []
+            touchdown_counter = 1
+            touchdown = None
+
+            logger.info('Start fetching from {} to {}'.format(start_date, end_date))
+            while touchdown or touchdown_counter == 1:
+                seg = hkkaz(
+                    account=hkkaz._fields['account'].type.from_sepa_account(account),
+                    all_accounts=False,
+                    date_start=start_date,
+                    date_end=end_date,
+                    touchdown_point=touchdown,
+                )
 
-        msg = _get_msg()
-        resp = dialog.send(msg)
-        touchdowns = resp.get_touchdowns(msg)
-        responses = [resp]
-        touchdown_counter = 1
+                rm = dialog.send(seg)
 
-        while HKKAZ.type in touchdowns:
-            logger.info('Fetching more results ({})...'.format(touchdown_counter))
+                for resp in rm.response_segments(seg, 'HIKAZ'):
+                    responses.append(resp)
 
-            with self.pin.protect():
-                logger.debug('Send message: {}'.format(
-                    self._create_statement_message(dialog, account, start_date, end_date, touchdowns[HKKAZ.type])
-                ))
+                touchdown = None
+                for response in rm.responses(seg, '3040'):
+                    touchdown = response.parameters[0]
+                    break
 
-            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)
+                if touchdown:
+                    logger.info('Fetching more results ({})...'.format(touchdown_counter))
 
-            touchdown_counter += 1
+                touchdown_counter += 1
+            logger.info('Fetching done.')
 
-        logger.info('Fetching done.')
 
         statement = []
-        for resp in responses:
-            seg = resp._find_segment('HIKAZ')
+        for seg in responses:
             ## FIXME What is the encoding of MT940 messages?
-            statement += mt940_to_array(seg[1].decode('iso-8859-1'))
+            statement += mt940_to_array(seg.statement_booked.decode('iso-8859-1'))
 
         logger.debug('Statement: {}'.format(statement))
 
-        dialog.end()
         return statement
 
-    def _create_statement_message(self, dialog: FinTSDialogOLD, account: SEPAAccount, start_date, end_date, touchdown):
-        hversion = dialog.hkkazversion
-
-        if hversion in (4, 5, 6):
-            acc = ':'.join([
-                account.accountnumber, account.subaccount or '', str(280), account.blz
-            ])
-        elif hversion == 7:
-            acc = ':'.join([
-                account.iban, account.bic, account.accountnumber, account.subaccount or '', 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
-            )
-        ])
-
     def get_balance(self, account: SEPAAccount):
         """
         Fetches an accounts current balance.
@@ -207,7 +188,7 @@ class FinTS3Client:
                 5: HKSAL5,
                 6: HKSAL6,
                 7: HKSAL7,
-            }.get(max_hisals.header.version, None)
+            }.get(max_hisals.header.version)
 
             seg = hksal(
                 account=hksal._fields['account'].type.from_sepa_account(account),
index ddf87830cb049d955233a9bcbb9ee9f487ac3b8a..a396b54c2cbda6f19f2d7f34d660c0f5d58d897a 100644 (file)
@@ -32,6 +32,12 @@ class FinTSMessage(SegmentSequence):
             if segment.header.reference == ref.header.number:
                 yield segment
 
+    def responses(self, ref, code=None):
+        for segment in self.response_segments(ref, HIRMS2):
+            for response in segment.responses:
+                if code is None or response.code == code:
+                    yield response
+
 class FinTSCustomerMessage(FinTSMessage):
     DIRECTION = MessageDirection.FROM_CUSTOMER
     # Identification, authentication
index c1d93d1db7c577c966bfbe89c53927169308979a..b80ede0bc0c916acf936855e9684e38823980396 100644 (file)
@@ -1,6 +1,11 @@
 from fints.utils import fints_escape
 
-from . import FinTS3SegmentOLD
+from fints.fields import DataElementField, DataElementGroupField
+from fints.formals import (
+    KTI1, Account3, Account2
+)
+
+from . import FinTS3Segment, FinTS3SegmentOLD
 
 
 class HKKAZ(FinTS3SegmentOLD):
@@ -24,3 +29,60 @@ class HKKAZ(FinTS3SegmentOLD):
             fints_escape(touchdown) if touchdown is not None else ''
         ]
         super().__init__(segno, data)
+
+class HKKAZ5(FinTS3Segment):
+    """Kontoumsätze anfordern/Zeitraum, version 5
+
+    Source: HBCI Homebanking-Computer-Interface, Schnittstellenspezifikation"""
+    account = DataElementGroupField(type=Account2, _d="Kontoverbindung Auftraggeber")
+    all_accounts = DataElementField(type='jn', _d="Alle Konten")
+    date_start = DataElementField(type='dat', required=False, _d="Von Datum")
+    date_end = DataElementField(type='dat', required=False, _d="Bis Datum")
+    max_number_responses = DataElementField(type='num', max_length=4, required=False, _d="Maximale Anzahl Einträge")
+    touchdown_point = DataElementField(type='an', max_length=35, required=False, _d="Aufsetzpunkt")
+
+
+class HIKAZ5(FinTS3Segment):
+    """Kontoumsätze rückmelden/Zeitraum, version 5
+
+    Source: HBCI Homebanking-Computer-Interface, Schnittstellenspezifikation"""
+    statement_booked = DataElementField(type='bin', _d="Gebuchte Umsätze")
+    statement_pending = DataElementField(type='bin', required=False, _d="Nicht gebuchte Umsätze")
+
+class HKKAZ6(FinTS3Segment):
+    """Kontoumsätze anfordern/Zeitraum, version 6
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+    account = DataElementGroupField(type=Account3, _d="Kontoverbindung Auftraggeber")
+    all_accounts = DataElementField(type='jn', _d="Alle Konten")
+    date_start = DataElementField(type='dat', required=False, _d="Von Datum")
+    date_end = DataElementField(type='dat', required=False, _d="Bis Datum")
+    max_number_responses = DataElementField(type='num', max_length=4, required=False, _d="Maximale Anzahl Einträge")
+    touchdown_point = DataElementField(type='an', max_length=35, required=False, _d="Aufsetzpunkt")
+
+
+class HIKAZ6(FinTS3Segment):
+    """Kontoumsätze rückmelden/Zeitraum, version 6
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+    statement_booked = DataElementField(type='bin', _d="Gebuchte Umsätze")
+    statement_pending = DataElementField(type='bin', required=False, _d="Nicht gebuchte Umsätze")
+
+class HKKAZ7(FinTS3Segment):
+    """Kontoumsätze anfordern/Zeitraum, version 7
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+    account = DataElementGroupField(type=KTI1, _d="Kontoverbindung international")
+    all_accounts = DataElementField(type='jn', _d="Alle Konten")
+    date_start = DataElementField(type='dat', required=False, _d="Von Datum")
+    date_end = DataElementField(type='dat', required=False, _d="Bis Datum")
+    max_number_responses = DataElementField(type='num', max_length=4, required=False, _d="Maximale Anzahl Einträge")
+    touchdown_point = DataElementField(type='an', max_length=35, required=False, _d="Aufsetzpunkt")
+
+
+class HIKAZ7(FinTS3Segment):
+    """Kontoumsätze rückmelden/Zeitraum, version 7
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+    statement_booked = DataElementField(type='bin', _d="Gebuchte Umsätze")
+    statement_pending = DataElementField(type='bin', required=False, _d="Nicht gebuchte Umsätze")