Feature: FinTS-TAN-Verfahren per Verbindung konfigurierbar + Decoupled-Polling-Fix

This commit is contained in:
fds2610-bot 2026-05-23 13:51:18 +02:00
parent ed3d5d33f1
commit 4b25961190
4 changed files with 41 additions and 9 deletions

View file

@ -0,0 +1,3 @@
ALTER TABLE bank_sources
ADD COLUMN IF NOT EXISTS tan_mode_id INT NULL DEFAULT NULL
COMMENT 'Bevorzugte FinTS-TAN-Verfahren-ID (z.B. 913 für chipTAN QR); NULL = erstes verfügbares';

View file

@ -443,6 +443,7 @@ class BankController extends BaseController
'fints_url' => $isFints ? (trim($_POST['fints_url'] ?? '') ?: null) : null,
'benutzerkennung' => $isFints ? (trim($_POST['benutzerkennung'] ?? '') ?: null) : null,
'pin' => $isFints ? (trim($_POST['pin'] ?? '') ?: null) : null,
'tan_mode_id' => $isFints ? (($_POST['tan_mode_id'] ?? '') !== '' ? (int)$_POST['tan_mode_id'] : null) : null,
'account_filter' => null, // Konten werden beim ersten Abruf ausgewählt
]);
@ -547,6 +548,7 @@ class BankController extends BaseController
'fints_url' => trim($_POST['fints_url'] ?? '') ?: null,
'benutzerkennung' => trim($_POST['benutzerkennung'] ?? '') ?: null,
'pin' => $newPin !== '' ? $newPin : $source['pin'],
'tan_mode_id' => ($_POST['tan_mode_id'] ?? '') !== '' ? (int)$_POST['tan_mode_id'] : null,
];
$filterUpdate = BankSource::computeFilterFromPost(
$source['account_filter'] ?? null,

View file

@ -104,8 +104,25 @@ class FinTsFetchService
$log(sprintf(' [%d] %s (ID %d)', $idx, $mode->getName(), $mode->getId()));
}
$selectedTanMode = reset($tanModes);
$log('Auswahl: ' . $selectedTanMode->getName() . ' (erstes verfügbares Verfahren)');
$preferredId = isset($this->source['tan_mode_id']) && $this->source['tan_mode_id'] !== null
? (int)$this->source['tan_mode_id']
: null;
$selectedTanMode = null;
if ($preferredId !== null) {
foreach ($tanModes as $mode) {
if ($mode->getId() === $preferredId) {
$selectedTanMode = $mode;
break;
}
}
if ($selectedTanMode === null) {
$log('WARNUNG: TAN-Verfahren ID ' . $preferredId . ' nicht gefunden – nutze erstes verfügbares.');
}
}
if ($selectedTanMode === null) {
$selectedTanMode = reset($tanModes);
}
$log('Auswahl: ' . $selectedTanMode->getName() . ' (ID ' . $selectedTanMode->getId() . ')');
$selectedTanMedium = null;
if ($selectedTanMode->needsTanMedium()) {
@ -288,11 +305,14 @@ class FinTsFetchService
$period = max(1, (int)$tanMode->getPeriodicDecoupledCheckDelaySeconds());
for ($attempt = 0; $attempt < $maxChecks; $attempt++) {
try {
$this->fints->checkDecoupledSubmission($action);
return true;
if ($this->fints->checkDecoupledSubmission($action)) {
return true;
}
} catch (\Throwable $e) {
sleep($period);
$log(' → Polling-Fehler: ' . $e->getMessage());
return false;
}
sleep($period);
}
$log(' → Zeitüberschreitung bei App-Bestätigung.');
return false;

View file

@ -292,6 +292,11 @@ $fetchRangeOptions = [
<label for="edit-fints-url">FinTS-Server-URL <span class="text-muted text-sm">(optional)</span></label>
<input type="url" id="edit-fints-url" name="fints_url" placeholder="https://...">
</div>
<div class="form-group">
<label for="edit-tan-mode-id">TAN-Verfahren-ID <span class="text-muted text-sm">(optional)</span></label>
<input type="number" id="edit-tan-mode-id" name="tan_mode_id" min="1" placeholder="z.B. 913 für chipTAN QR">
<div class="text-muted text-sm">Leer = erstes verfügbares Verfahren</div>
</div>
<div class="form-group">
<label for="edit-fetch-range-fints">Abrufen ab</label>
<select id="edit-fetch-range-fints" name="fetch_range" disabled>
@ -463,6 +468,7 @@ $fetchRangeOptions = [
const editBenutzer = document.getElementById('edit-benutzerkennung');
const editPin = document.getElementById('edit-pin');
const editFintsUrl = document.getElementById('edit-fints-url');
const editTanModeId = document.getElementById('edit-tan-mode-id');
const editAccountList = document.getElementById('edit-account-list');
const editResetAcc = document.getElementById('edit-reset-accounts');
const editFetchRangeApi = document.getElementById('edit-fetch-range-api');
@ -839,10 +845,11 @@ $fetchRangeOptions = [
editSandbox.checked = conn.sandbox === true;
}
if (isFints) {
editBlz.value = conn.blz || '';
editBenutzer.value = conn.benutzerkennung || '';
editPin.value = '';
editFintsUrl.value = conn.fints_url || '';
editBlz.value = conn.blz || '';
editBenutzer.value = conn.benutzerkennung || '';
editPin.value = '';
editFintsUrl.value = conn.fints_url || '';
editTanModeId.value = conn.tan_mode_id != null ? conn.tan_mode_id : '';
editResetAcc.checked = false;
// Konto-Checkboxen aus account_filter aufbauen