from contextlib import contextmanager
from collections import OrderedDict
-from fints.segments.debit import HKDME, HKDSE
from mt940.models import Balance
from sepaxml import SepaTransfer
KTI1, Account3, BankIdentifier,
SynchronisationMode, TwoStepParametersCommon,
TANMediaType2, TANMediaClass4, CUSTOMER_ID_ANONYMOUS,
+ DescriptionRequired,
)
from .message import FinTSInstituteMessage
from .models import (
PinTanTwoStepAuthenticationMechanism,
)
from .segments import HIBPA3, HIRMG2, HIRMS2, HIUPA4, HIPINS1, HKKOM4
-from .segments.accounts import HISPA1, HKSPA, HKSPA1
-from .segments.auth import HKTAB, HKTAN, HKTAB4, HKTAB5, HKTAN3, HKTAN5
+from .segments.accounts import HISPA1, HKSPA1
+from .segments.auth import HKTAB4, HKTAB5, HKTAN3, HKTAN5
from .segments.depot import HKWPD5, HKWPD6
from .segments.dialog import HISYN4, HKSYN3
+from .segments.debit import HKDSE1, HKDSE2, HKDME1, HKDME2, HKDMC1
from .segments.saldo import HKSAL5, HKSAL6, HKSAL7
from .segments.statement import HKKAZ5, HKKAZ6, HKKAZ7
from .segments.transfer import HKCCM1, HKCCS1
:param control_sum: Sum of all transfers (required if there are multiple)
:param currency: Transfer currency
:param book_as_single: Kindly ask the bank to put multiple transactions as separate lines on the bank statement (defaults to ``False``)
- :return: Returns a TANChallenge object
+ :return: Returns a TANChallenge object FIXME Wrong
"""
with self._get_dialog() as dialog:
command_class = HKCCS1
hiccxs, hkccx = self._find_highest_supported_command(
- HKCCM1 if multiple else HKCCS1,
+ command_class,
return_parameter_segment=True
)
)
if multiple:
- if hiccxs.parameter.sum_amount_required and not control_sum:
+ if hiccxs.parameter.sum_amount_required and control_sum is None:
raise ValueError("Control sum required.")
if book_as_single and not hiccxs.parameter.single_booking_allowed:
# FIXME Only do a warning and fall-back to book_as_single=False?
# FIXME Properly find return code
return True
- def _get_start_sepa_debit_message(self, dialog, account: SEPAAccount, pain_message: str, tan_method,
- tan_description, multiple, control_sum, currency, book_as_single):
- if multiple:
- if not control_sum:
- raise ValueError("Control sum required.")
- segreq = HKDME(3, account, pain_message, control_sum, currency, book_as_single)
- else:
- segreq = HKDSE(3, account, pain_message)
- segtan = HKTAN(4, '4', '', tan_description, tan_method.version)
- return self._new_message(dialog, [
- segreq,
- segtan
- ])
-
- def start_sepa_debit(self, account: SEPAAccount, pain_message: str, tan_method, tan_description='',
- multiple=False, control_sum=None, currency='EUR', book_as_single=False):
+ def start_sepa_debit(self, account: SEPAAccount, pain_message: str, multiple=False, cor1=False,
+ control_sum=None, currency='EUR', book_as_single=False,
+ pain_descriptor='urn:iso:std:iso:20022:tech:xsd:pain.008.003.01'):
"""
Start a custom SEPA debit.
:param control_sum: Sum of all debits (required if there are multiple)
:param currency: Debit currency
:param book_as_single: Kindly ask the bank to put multiple transactions as separate lines on the bank statement (defaults to ``False``)
- :return: Returns a TANChallenge object
+ :return: Returns a TANChallenge object FIXME Wrong
"""
- dialog = self._get_dialog()
- dialog.sync()
- dialog.tan_mechs = [tan_method]
- dialog.init()
-
- with self.pin.protect():
- logger.debug('Sending: {}'.format(self._get_start_sepa_debit_message(
- dialog, account, pain_message, tan_method, tan_description, multiple, control_sum, currency,
- book_as_single
- )))
-
- resp = dialog.send(self._get_start_sepa_debit_message(
- dialog, account, pain_message, tan_method, tan_description, multiple, control_sum, currency,
- book_as_single
- ))
- logger.debug('Got response: {}'.format(resp))
- return self._tan_requiring_response(dialog, resp)
+
+ with self._get_dialog() as dialog:
+ if multiple:
+ if cor1:
+ command_candidates = (HKDMC1, )
+ else:
+ command_candidates = (HKDME1, HKDME2)
+ else:
+ if cor1:
+ raise Exception("Can't process multiple=False cor1=True")
+ else:
+ command_candidates = (HKDSE1, HKDSE2)
+
+ hidxxs, hkdxx = self._find_highest_supported_command(
+ *command_candidates,
+ return_parameter_segment=True
+ )
+
+ seg = hkdxx(
+ account=hkdxx._fields['account'].type.from_sepa_account(account),
+ sepa_descriptor=pain_descriptor,
+ sepa_pain_message=pain_message,
+ )
+
+ if multiple:
+ if hidxxs.parameter.sum_amount_required and control_sum is None:
+ raise ValueError("Control sum required.")
+ if book_as_single and not hidxxs.parameter.single_booking_allowed:
+ # FIXME Only do a warning and fall-back to book_as_single=False?
+ raise ValueError("Single booking not allowed by bank.")
+
+ if control_sum:
+ seg.sum_amount.amount = control_sum
+ seg.sum_amount.currency = currency
+
+ if book_as_single:
+ seg.request_single_booking = True
+
+ return self._send_with_possible_retry(dialog, seg, self._continue_start_sepa_debit)
+
+ def _continue_start_sepa_debit(self, command_seg, response):
+ # FIXME Properly return something
+ return True
def add_response_callback(self, cb):
# FIXME document
for resp in response.responses(tan_seg):
if resp.code == '0030':
return NeedTANResponse(command_seg, response.find_segment_first('HITAN'), resume_func)
+ if resp.code.startswith('9'):
+ raise Exception("Error response: {!r}".format(response))
else:
response = dialog.send(command_seg)
from .message import (
FinTSCustomerMessage, FinTSMessage, MessageDirection,
)
-from .segments.auth import HKIDN, HKIDN2, HKSYN, HKVVB, HKVVB3
-from .segments.dialog import HKEND, HKEND1
+from .segments.auth import HKIDN2, HKVVB3
+from .segments.dialog import HKEND1
from .segments.message import HNHBK3, HNHBS1
from .utils import compress_datablob, decompress_datablob
address_adjunct = DataElementField(type='an', max_length=512, required=False, _d="Kommunikationsadresszusatz")
filter_function = DataElementField(type='an', length=3, required=False, _d="Filterfunktion")
filter_function_version = DataElementField(type='num', max_length=3, required=False, _d="Version der Filterfunktion")
+
+class ScheduledDebitParameter1(DataElementGroup):
+ """Parameter terminierte SEPA-Einzellastschrift einreichen, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ min_advance_notice_FNAL_RCUR = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit FNAL/RCUR")
+ max_advance_notice_FNAL_RCUR = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit FNAL/RCUR")
+ min_advance_notice_FRST_OOFF = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit FRST/OOFF")
+ max_advance_notice_FRST_OOFF = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit FRST/OOFF")
+
+class ScheduledDebitParameter2(DataElementGroup):
+ """Parameter terminierte SEPA-Einzellastschrift einreichen, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ min_advance_notice = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit SEPA-Lastschrift")
+ max_advance_notice = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit SEPA-Lastschrift")
+ allowed_purpose_codes = DataElementField(type='an', max_length=4096, required=False, _d="Zulässige purpose codes")
+ supported_sepa_formats = DataElementField(type='an', max_length=256, max_count=9, required=False, _d="Unterstützte SEPA-Datenformate")
+
+class ScheduledBatchDebitParameter1(DataElementGroup):
+ """Parameter terminierte SEPA-Sammellastschrift einreichen, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ min_advance_notice_FNAL_RCUR = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit FNAL/RCUR")
+ max_advance_notice_FNAL_RCUR = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit FNAL/RCUR")
+ min_advance_notice_FRST_OOFF = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit FRST/OOFF")
+ max_advance_notice_FRST_OOFF = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit FRST/OOFF")
+ max_debit_count = DataElementField(type='num', max_length=7, _d="Maximale Anzahl DirectDebitTransfer TransactionInformation")
+ sum_amount_required = DataElementField(type='jn', _d="Summenfeld benötigt")
+ single_booking_allowed = DataElementField(type='jn', _d="Einzelbuchung erlaubt")
+
+class ScheduledBatchDebitParameter2(DataElementGroup):
+ """Parameter terminierte SEPA-Sammellastschrift einreichen, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ min_advance_notice = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit SEPA-Lastschrift")
+ max_advance_notice = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit SEPA-Lastschrift")
+ max_debit_count = DataElementField(type='num', max_length=7, _d="Maximale Anzahl DirectDebitTransfer TransactionInformation")
+ sum_amount_required = DataElementField(type='jn', _d="Summenfeld benötigt")
+ single_booking_allowed = DataElementField(type='jn', _d="Einzelbuchung erlaubt")
+ allowed_purpose_codes = DataElementField(type='an', max_length=4096, required=False, _d="Zulässige purpose codes")
+ supported_sepa_formats = DataElementField(type='an', max_length=256, max_count=9, required=False, _d="Unterstützte SEPA-Datenformate")
+
+
+class ScheduledCOR1BatchDebitParameter1(DataElementGroup):
+ """Parameter terminierte SEPA-COR1-Sammellastschrift, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ max_debit_count = DataElementField(type='num', max_length=7, _d="Maximale Anzahl DirectDebitTransfer TransactionInformation")
+ sum_amount_required = DataElementField(type='jn', _d="Summenfeld benötigt")
+ single_booking_allowed = DataElementField(type='jn', _d="Einzelbuchung erlaubt")
+ min_advance_notice_FNAL_RCUR = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit FNAL/RCUR")
+ max_advance_notice_FNAL_RCUR = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit FNAL/RCUR")
+ min_advance_notice_FRST_OOFF = DataElementField(type='num', max_length=4, _d="Minimale Vorlaufzeit FRST/OOFF")
+ max_advance_notice_FRST_OOFF = DataElementField(type='num', max_length=4, _d="Maximale Vorlaufzeit FRST/OOFF")
+ allowed_purpose_codes = DataElementField(type='an', max_length=4096, required=False, _d="Zulässige purpose codes")
+ supported_sepa_formats = DataElementField(type='an', max_length=256, max_count=9, required=False, _d="Unterstützte SEPA-Datenformate")
+
+
-from . import FinTS3SegmentOLD
+from . import FinTS3Segment
from ..models import SEPAAccount
+from ..fields import DataElementField, DataElementGroupField
+from ..formals import ScheduledCOR1BatchDebitParameter1, KTI1, Amount1, ScheduledBatchDebitParameter1, ScheduledBatchDebitParameter2, ScheduledDebitParameter1, ScheduledDebitParameter2
+from . import ParameterSegment
+class HKDSE1(FinTS3Segment):
+ """Terminierte SEPA-Einzellastschrift einreichen, version 1
-class HKDSE(FinTS3SegmentOLD):
- """
- HKDSE (Einreichung terminierter SEPA-Einzellastschrift)
- Section C.10.2.5.4.1
- """
- type = 'HKDSE'
-
- def __init__(self, segno, account: SEPAAccount, pain_msg):
- self.version = 1
- sepa_descriptor = 'urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.008.003.02'
- msg = ':'.join([
- account.iban,
- account.bic
- ])
- data = [
- msg,
- sepa_descriptor,
- '@{}@{}'.format(len(pain_msg), pain_msg)
- ]
- super().__init__(segno, data)
-
-
-class HKDME(FinTS3SegmentOLD):
- """
- HKDME (Einreichung terminierter SEPA-Sammellastschrift)
- Section C.10.3.2.2.1
- """
- type = 'HKDME'
-
- def __init__(self, segno, account: SEPAAccount, pain_msg, control_sum, currency, book_as_single):
- self.version = 1
- sepa_descriptor = 'urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.008.003.02'
- msg = ':'.join([
- account.iban,
- account.bic
- ])
- data = [
- msg,
- str(control_sum).replace('.', ',') + ':' + currency,
- 'J' if book_as_single else '',
- sepa_descriptor,
- '@{}@{}'.format(len(pain_msg), pain_msg)
- ]
- super().__init__(segno, data)
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ account = DataElementGroupField(type=KTI1, _d="Kontoverbindung international")
+ sepa_descriptor = DataElementField(type='an', max_length=256, _d="SEPA Descriptor")
+ sepa_pain_message = DataElementField(type='bin', _d="SEPA pain message")
+
+class HKDSE2(FinTS3Segment):
+ """Terminierte SEPA-Einzellastschrift einreichen, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ account = DataElementGroupField(type=KTI1, _d="Kontoverbindung international")
+ sepa_descriptor = DataElementField(type='an', max_length=256, _d="SEPA Descriptor")
+ sepa_pain_message = DataElementField(type='bin', _d="SEPA pain message")
+
+class BatchDebitBase(FinTS3Segment):
+ account = DataElementGroupField(type=KTI1, _d="Kontoverbindung international")
+ sum_amount = DataElementGroupField(type=Amount1, _d="Summenfeld")
+ request_single_booking = DataElementField(type='jn', _d="Einzelbuchung gewünscht")
+ sepa_descriptor = DataElementField(type='an', max_length=256, _d="SEPA Descriptor")
+ sepa_pain_message = DataElementField(type='bin', _d="SEPA pain message")
+
+class HKDME1(BatchDebitBase):
+ """Einreichung terminierter SEPA-Sammellastschrift, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HKDME2(BatchDebitBase):
+ """Einreichung terminierter SEPA-Sammellastschrift, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HKDMC1(BatchDebitBase):
+ """Terminierte SEPA-COR1-Sammellastschrift einreichen, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+
+class DebitResponseBase(FinTS3Segment):
+ task_id = DataElementField(type='an', max_length=99, required=False, _d="Auftragsidentifikation")
+
+class HIDSE1(DebitResponseBase):
+ """Einreichung terminierter SEPA-Einzellastschrift bestätigen, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HIDSE2(DebitResponseBase):
+ """Einreichung terminierter SEPA-Einzellastschrift bestätigen, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HIDME1(DebitResponseBase):
+ """Einreichung terminierter SEPA-Sammellastschrift bestätigen, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HIDME2(DebitResponseBase):
+ """Einreichung terminierter SEPA-Sammellastschrift bestätigen, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HIDMC1(DebitResponseBase):
+ """Einreichung terminierter SEPA-COR1-Sammellastschrift bestätigen, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+
+class HIDSES1(ParameterSegment):
+ """Terminierte SEPA-Einzellastschrift einreichen Parameter, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ parameter = DataElementGroupField(type=ScheduledDebitParameter1, _d="Parameter terminierte SEPA-Sammellastschrift einreichen")
+
+class HIDSES2(ParameterSegment):
+ """Terminierte SEPA-Einzellastschrift einreichen Parameter, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ parameter = DataElementGroupField(type=ScheduledDebitParameter2, _d="Parameter terminierte SEPA-Sammellastschrift einreichen")
+
+class HIDMES1(ParameterSegment):
+ """Terminierte SEPA-Sammellastschrift einreichen Parameter, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ parameter = DataElementGroupField(type=ScheduledBatchDebitParameter1, _d="Parameter terminierte SEPA-Sammellastschrift einreichen")
+
+class HIDMES2(ParameterSegment):
+ """Terminierte SEPA-Sammellastschrift einreichen Parameter, version 2
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ parameter = DataElementGroupField(type=ScheduledBatchDebitParameter2, _d="Parameter terminierte SEPA-Sammellastschrift einreichen")
+
+class HIDMCS1(ParameterSegment):
+ """Terminierte SEPA-COR1-Sammellastschrift Parameter, version 1
+
+ Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Messages -- Multibankfähige Geschäftsvorfälle """
+ parameter = DataElementGroupField(type=ScheduledCOR1BatchDebitParameter1, _d="Parameter terminierte SEPA-COR1-Sammellastschrift")