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/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..db0afcb 100644 --- a/src/Views/bank/fints.php +++ b/src/Views/bank/fints.php @@ -292,6 +292,11 @@ $fetchRangeOptions = [ +