From: Henryk Plötz Date: Mon, 20 Aug 2018 00:45:29 +0000 (+0200) Subject: Implement HKSAL5/HISAL5 X-Git-Tag: v2.0.0~1^2~98 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e26338abc26d792aaac2adf0f066fcf4face81a3;p=thirdparty%2Fpython-fints.git Implement HKSAL5/HISAL5 --- diff --git a/fints/client.py b/fints/client.py index e146635..119222a 100644 --- a/fints/client.py +++ b/fints/client.py @@ -20,7 +20,7 @@ from .segments.accounts import HKSPA, HKSPA1, HISPA1 from .segments.auth import HKTAB, HKTAN from .segments.dialog import HKSYN3, HISYN4 from .segments.depot import HKWPD -from .segments.saldo import HKSAL6, HKSAL7, HISAL6, HISAL7 +from .segments.saldo import HKSAL5, HKSAL6, HKSAL7, HISAL5, HISAL6, HISAL7 from .segments.statement import HKKAZ from .segments.transfer import HKCCM, HKCCS from .utils import MT535_Miniparser, Password, mt940_to_array @@ -204,25 +204,25 @@ class FinTS3Client: default=6 ) - if max_hksal_version in (1, 2, 3, 4, 5, 6): - seg = HKSAL6( - Account3.from_sepa_account(account), - False - ) - elif max_hksal_version == 7: - seg = HKSAL7( - KTI1.from_sepa_account(account), - False - ) - else: + clazz = { + 5: HKSAL5, + 6: HKSAL6, + 7: HKSAL7, + }.get(max_hksal_version, None) + + if clazz is None: raise ValueError('Unsupported HKSAL version {}'.format(max_hksal_version)) + seg = clazz( + account=clazz._fields['account'].type.from_sepa_account(account), + all_accounts=False, + ) with self._new_dialog() as dialog: response = dialog.send(seg) # find segment - seg = response.find_segment_first((HISAL6, HISAL7)) + seg = response.find_segment_first((HISAL5, HISAL6, HISAL7)) if seg: return seg.balance_booked.as_mt940_Balance() diff --git a/fints/fields.py b/fints/fields.py index ef6dad8..06ca8b7 100644 --- a/fints/fields.py +++ b/fints/fields.py @@ -215,7 +215,7 @@ class DigitsField(FieldRenderFormatStringMixin, DataElementField): raise TypeError("Only digits allowed for value of type 'dig': {!r}".format(value)) return _value -class FloatField(FieldRenderFormatStringMixin, DataElementField): +class FloatField(DataElementField): type = 'float' _DOC_TYPE = float _FORMAT_STRING = "{:.12f}" # Warning: Python's float is not exact! @@ -232,8 +232,10 @@ class FloatField(FieldRenderFormatStringMixin, DataElementField): return float(_value.replace(",", ".")) def _render_value(self, value): - retval = super()._render_value(value) - return retval.replace('.', ',').rstrip('0') + retval = self._FORMAT_STRING.format(value) + retval = retval.replace('.', ',').rstrip('0') + self._check_value_length(retval) + return retval class AmountField(FixedLengthMixin, FloatField): type = 'wrt' diff --git a/fints/formals.py b/fints/formals.py index 6043e4c..550596f 100644 --- a/fints/formals.py +++ b/fints/formals.py @@ -357,6 +357,24 @@ class KTI1(DataElementGroup): ) ) +class Account2(DataElementGroup): + """Kontoverbindung, version 2 + + Source: HBCI Homebanking-Computer-Interface, Schnittstellenspezifikation""" + account_number = DataElementField(type='id', _d="Konto-/Depotnummer") + subaccount_number = DataElementField(type='id', _d="Unterkontomerkmal") + country_identifier = DataElementField(type='ctr', _d="Länderkennzeichen") + bank_code = DataElementField(type='an', max_length=30, _d="Kreditinstitutscode") + + @classmethod + def from_sepa_account(cls, acc): + return cls( + account_number=acc.accountnumber, + subaccount_number=acc.subaccount, + country_identifier='280', + bank_code=acc.blz, + ) + class Account3(DataElementGroup): """Kontoverbindung, version 3 @@ -460,6 +478,25 @@ class CreditDebit2(RepresentableEnum): CREDIT = 'C' #: Haben DEBIT = 'D' #: Soll +class Balance1(DataElementGroup): + """Saldo, version 1 + + Source: HBCI Homebanking-Computer-Interface, Schnittstellenspezifikation""" + credit_debit = CodeField(enum=CreditDebit2, length=1, _d="Soll-Haben-Kennzeichen") + amount = DataElementField(type='wrt', _d="Wert") + currency = DataElementField(type='cur', _d="Währung") + date = DataElementField(type='dat', _d="Datum") + time = DataElementField(type='tim', required=False, _d="Uhrzeit") + + def as_mt940_Balance(self): + from mt940.models import Balance + return Balance( + self.credit_debit.value, + "{:.12f}".format(self.amount).rstrip('0'), + self.date, + currency=self.currency + ) + class Balance2(DataElementGroup): """Saldo, version 2 diff --git a/fints/segments/saldo.py b/fints/segments/saldo.py index 19091a2..d211c18 100644 --- a/fints/segments/saldo.py +++ b/fints/segments/saldo.py @@ -1,6 +1,6 @@ from . import FinTS3SegmentOLD, FinTS3Segment -from fints.formals import Account3, KTI1, Balance2, Amount1, Timestamp1 +from fints.formals import Account2, Account3, KTI1, Balance1, Balance2, Amount1, Timestamp1 from fints.fields import DataElementGroupField, DataElementField @@ -19,6 +19,31 @@ class HKSAL(FinTS3SegmentOLD): ] super().__init__(segno, data) +class HKSAL5(FinTS3Segment): + """Saldenabfrage, version 5 + + Source: HBCI Homebanking-Computer-Interface, Schnittstellenspezifikation""" + account = DataElementGroupField(type=Account2, _d="Kontoverbindung Auftraggeber") + all_accounts = DataElementField(type='jn', _d="Alle Konten") + 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 HISAL5(FinTS3Segment): + """Saldenrückmeldung, version 5 + + Source: HBCI Homebanking-Computer-Interface, Schnittstellenspezifikation""" + account = DataElementGroupField(type=Account2, _d="Kontoverbindung Auftraggeber") + account_product = DataElementField(type='an', max_length=30, _d="Kontoproduktbezeichnung") + currency = DataElementField(type='cur', _d="Kontowährung") + balance_booked = DataElementGroupField(type=Balance1, _d="Gebuchter Saldo") + balance_pending = DataElementGroupField(type=Balance1, required=False, _d="Saldo der vorgemerkten Umsätze") + line_of_credit = DataElementGroupField(type=Amount1, required=False, _d="Kreditlinie") + available_amount = DataElementGroupField(type=Amount1, required=False, _d="Verfügbarer Betrag") + used_amount = DataElementGroupField(type=Amount1, required=False, _d="Bereits verfügter Betrag") + booking_date = DataElementField(type='dat', required=False, _d="Buchungsdatum des Saldos") + booking_time = DataElementField(type='tim', required=False, _d="Buchungsuhrzeit des Saldos") + date_due = DataElementField(type='dat', required=False, _d="Fälligkeit") + class HKSAL6(FinTS3Segment): """Saldenabfrage, version 6 @@ -41,7 +66,7 @@ class HISAL6(FinTS3Segment): available_amount = DataElementGroupField(type=Amount1, required=False, _d="Verfügbarer Betrag") used_amount = DataElementGroupField(type=Amount1, required=False, _d="Bereits verfügter Betrag") overdraft = DataElementGroupField(type=Amount1, required=False, _d="Überziehung") - booking_time = DataElementGroupField(type=Timestamp1, required=False, _d="Buchungszeitpunkt") + booking_timestamp = DataElementGroupField(type=Timestamp1, required=False, _d="Buchungszeitpunkt") date_due = DataElementField(type='dat', required=False, _d="Fälligkeit") class HKSAL7(FinTS3Segment): @@ -67,5 +92,5 @@ class HISAL7(FinTS3Segment): available_amount = DataElementGroupField(type=Amount1, required=False, _d="Verfügbarer Betrag") used_amount = DataElementGroupField(type=Amount1, required=False, _d="Bereits verfügter Betrag") overdraft = DataElementGroupField(type=Amount1, required=False, _d="Überziehung") - booking_time = DataElementGroupField(type=Timestamp1, required=False, _d="Buchungszeitpunkt") + booking_timestamp = DataElementGroupField(type=Timestamp1, required=False, _d="Buchungszeitpunkt") date_due = DataElementField(type='dat', required=False, _d="Fälligkeit")