-
Notifications
You must be signed in to change notification settings - Fork 84
Description
Describe the bug
For getting older transactions from Skatbank and comdirect there is a TAN needed. I need to pause dialogue, deconstruct client (including private data) and store request. After restoring/resuming and sending TAN there is an exception in _continue_fetch_with_touchdowns
, because self._touchdown_args (amonst others) is not set.
TAN seems to be processed already correctly and accepted by bank.
Bank I tested this with
Name of the bank: comdirect (using PhotoTAN)
FinTS URL: https://fints.comdirect.de/fints
Name of the bank: Skatbank (using VR-SecureGo (Push TAN))
FinTS URL: https://hbci11.fiducia.de/cgi-bin/hbciservlet
Expected behavior
After sending TAN it should return requested transactions
Code required to reproduce
(copied from https://python-fints.readthedocs.io/en/latest/trouble.html)
import datetime
import getpass
import logging
import sys
from decimal import Decimal
from fints.client import FinTS3PinTanClient, NeedTANResponse, FinTSUnsupportedOperation, NeedRetryResponse
from fints.hhd.flicker import terminal_flicker_unix
from fints.utils import minimal_interactive_cli_bootstrap
logging.basicConfig(level=logging.DEBUG)
client_args = (
'REPLACEME', # BLZ
'REPLACEME', # USER
getpass.getpass('PIN: '),
'REPLACEME' # ENDPOINT
)
f = FinTS3PinTanClient(*client_args)
minimal_interactive_cli_bootstrap(f)
def ask_for_tan(response):
print("A TAN is required")
print(response.challenge)
if getattr(response, 'challenge_hhduc', None):
try:
terminal_flicker_unix(response.challenge_hhduc)
except KeyboardInterrupt:
pass
tan = input('Please enter TAN:')
return f.send_tan(response, tan)
# Open the actual dialog
with f:
# Since PSD2, a TAN might be needed for dialog initialization. Let's check if there is one required
if f.init_tan_response:
ask_for_tan(f.init_tan_response)
# Fetch accounts
accounts = f.get_sepa_accounts()
if isinstance(accounts, NeedTANResponse):
accounts = ask_for_tan(accounts)
if len(accounts) == 1:
account = accounts[0]
else:
print("Multiple accounts available, choose one")
for i, mm in enumerate(accounts):
print(i, mm.iban)
choice = input("Choice: ").strip()
account = accounts[int(choice)]
res = f.get_transactions(account, datetime.date.today() - datetime.timedelta(days=120),
datetime.date.today())
# Test pausing and resuming the dialog
dialog_data = f.pause_dialog()
client_data = f.deconstruct(including_private=True)
tan_request_data = res.get_data()
tan_request = NeedRetryResponse.from_data(tan_request_data)
f = FinTS3PinTanClient(*client_args, from_data=client_data)
with f.resume_dialog(dialog_data):
res = ask_for_tan(tan_request)
print("Found", len(res), "transactions")
Log output / error message
Traceback (most recent call last):
File ".../PycharmProjects/fints_test/pyfintstest2.py", line 67, in <module>
res = ask_for_tan(tan_request)
File ".../PycharmProjects/fints_test/pyfintstest2.py", line 33, in ask_for_tan
return f.send_tan(response, tan)
File "...\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\fints\client.py", line 1264, in send_tan
return resume_func(challenge.command_seg, response)
File "...\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\fints\client.py", line 456, in _continue_fetch_with_touchdowns
for resp in response.response_segments(command_seg, *self._touchdown_args, **self._touchdown_kwargs):
AttributeError: 'FinTS3PinTanClient' object has no attribute '_touchdown_args'
Solution / Quick hack
After setting the missing attributes in ask_for_tan
before f.send_tan
- it works: (just some dirty copy paste from _fetch_with_touchdowns
and get_transactions
)
from fints.utils import mt940_to_array
import fints.segments.statement
def ask_for_tan(response):
[...]
tan = input('Please enter TAN:')
f._touchdown_args = ['HIKAZ']
f._touchdown_kwargs = {}
f._touchdown_responses = []
f._touchdown_counter = 1
f._touchdown_response_processor = lambda responses: mt940_to_array(''.join([seg.statement_booked.decode('iso-8859-1') for seg in responses]))
hkkaz = f._find_highest_supported_command(fints.segments.statement.HKKAZ5,
fints.segments.statement.HKKAZ6,
fints.segments.statement.HKKAZ7)
f._touchdown_segment_factory = lambda touchdown: hkkaz(
account=hkkaz._fields['account'].type.from_sepa_account(account),
all_accounts=False,
date_start=datetime.date.today() - datetime.timedelta(days=120),
date_end=datetime.date.today(),
touchdown_point=touchdown,
)
return f.send_tan(response, tan)
I think it needs to be saved in deconstruct
and restored in set_data
?