diff --git a/migrations/073_bank_sources_tan_mode_id.sql b/migrations/073_bank_sources_tan_mode_id.sql new file mode 100644 index 0000000..637a1b8 --- /dev/null +++ b/migrations/073_bank_sources_tan_mode_id.sql @@ -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'; diff --git a/src/Controllers/BankController.php b/src/Controllers/BankController.php index f19098a..4cd9185 100644 --- a/src/Controllers/BankController.php +++ b/src/Controllers/BankController.php @@ -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, diff --git a/src/Models/BankSource.php b/src/Models/BankSource.php index 597e66a..366cb5c 100644 --- a/src/Models/BankSource.php +++ b/src/Models/BankSource.php @@ -222,7 +222,7 @@ class BankSource 'buchungstext_template_debit', 'buchungstext_template_credit', 'sandbox', 'last_fetched_at', 'fetch_range', 'app_name', 'client_id_enc', 'secret_enc', - 'blz', 'fints_url', 'benutzerkennung', 'pin_enc', 'account_filter', + 'blz', 'fints_url', 'benutzerkennung', 'pin_enc', 'account_filter', 'tan_mode_id', ]; $out = []; diff --git a/src/Services/FinTsFetchService.php b/src/Services/FinTsFetchService.php index e22abfd..007dbf8 100644 --- a/src/Services/FinTsFetchService.php +++ b/src/Services/FinTsFetchService.php @@ -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; diff --git a/src/Views/bank/fints.php b/src/Views/bank/fints.php index 9b30ead..116e828 100644 --- a/src/Views/bank/fints.php +++ b/src/Views/bank/fints.php @@ -21,6 +21,7 @@ $connectionsJson = json_encode(array_map(fn($c) => [ 'benutzerkennung' => $c['benutzerkennung'] ?? '', 'account_filter' => $c['account_filter'] ?? null, 'fetch_range' => $c['fetch_range'] ?? 'last_fetched', + 'tan_mode_id' => isset($c['tan_mode_id']) && $c['tan_mode_id'] !== null ? (int)$c['tan_mode_id'] : null, ], $connections)); $fetchRangeOptions = [ @@ -292,6 +293,11 @@ $fetchRangeOptions = [ +
+ + +
Leer = erstes verfügbares Verfahren
+