Finanzmanager/tests/40_NamensabgleichTest.php
fds2610-bot 290ab86c26 Fix #89: Echtzeitüberweisung scheitert an SEPA-Format und VOP/TAN-Kombination
SepaXml erzeugt jetzt zusätzlich pain.001.001.09 (Dt-Element für den
Ausführungstermin, BICFI statt BIC, UETR je Zahlung) für Banken, die das
ältere pain.001.001.03 nicht mehr führen. FinTsUeberweisung fängt außerdem
die UnsupportedException ab, die php-fints wirft, wenn die Bank
Namensabgleich-Volltreffer und TAN-Anfrage in einem Antwortsatz kombiniert,
und lässt den vorhandenen automatischen Volltreffer-Namensabgleich den Rest
erledigen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 22:54:58 +02:00

112 lines
5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
use Fhp\Model\VopVerificationResult;
use Fhp\UnsupportedException;
use Finanzmanager\Services\FinTsUeberweisung;
/**
* Namensabgleich vor der Überweisung (Verification of Payee).
*
* Seit Oktober 2025 gleicht die Bank den Empfängernamen mit dem Kontoinhaber
* ab. Stimmt beides überein, bestätigt der Finanzmanager selbst und geht direkt
* zur TAN; weicht der Name ab, wird gefragt. Geprüft wird hier, was sich ohne
* Bankverbindung prüfen lässt: die Aufbereitung dessen, was die Bank meldet,
* und dass ohne wartenden Vorgang niemand etwas bestätigen kann.
*/
class NamensabgleichTest extends TestCase
{
protected string $testName = 'Test 40: Namensabgleich vor der Überweisung';
public function run(): void
{
$this->jedesErgebnisHatEinenDeutschenSatz();
$this->derBanktextWirdKlartext();
$this->ohneWartendenVorgangGehtNichts();
$this->dieBekannteVopTanLueckeWirdErkannt();
}
private function jedesErgebnisHatEinenDeutschenSatz(): void
{
$ergebnisse = [
VopVerificationResult::CompletedFullMatch,
VopVerificationResult::CompletedCloseMatch,
VopVerificationResult::CompletedNoMatch,
VopVerificationResult::CompletedPartialMatch,
VopVerificationResult::NotApplicable,
];
$saetze = [];
foreach ($ergebnisse as $ergebnis) {
$satz = FinTsUeberweisung::vopUrteil($ergebnis);
$this->assertNotEmpty($satz, 'Ergebnis ' . $ergebnis . ' hat einen Satz');
$this->assert(
!str_contains($satz, 'Completed') && !str_contains($satz, 'Match'),
'Ergebnis ' . $ergebnis . ' steht auf Deutsch da'
);
$saetze[] = $satz;
}
$this->assertEquals(count($ergebnisse), count(array_unique($saetze)), 'Jedes Ergebnis hat seinen eigenen Satz');
// Auch ein unbekanntes oder fehlendes Ergebnis darf den Dialog nicht leer lassen.
$this->assertNotEmpty(FinTsUeberweisung::vopUrteil(null), 'Ohne Ergebnis steht trotzdem ein Satz da');
$this->assertNotEmpty(FinTsUeberweisung::vopUrteil('Unbekannt'), 'Unbekanntes Ergebnis ebenso');
}
private function derBanktextWirdKlartext(): void
{
// So liefern die Banken den Aufklärungstext: HTML mit Auszeichnung.
$html = 'Der Name stimmt <b>nicht</b> überein.<br>Bitte pr&uuml;fen.'
. '<p><b>Wichtiger Hinweis:</b> Die Überweisung wird ohne Korrektur ausgeführt.</p>';
$text = FinTsUeberweisung::vopHinweis($html);
$this->assert(!str_contains($text, '<'), 'Die Auszeichnung ist weg');
$this->assert(str_contains($text, 'Der Name stimmt nicht überein.'), 'Der Satz bleibt vollständig');
$this->assert(str_contains($text, 'Bitte prüfen.'), 'Entities werden aufgelöst');
$this->assert(str_contains($text, "überein.\nBitte prüfen."), 'Aus <br> wird ein Zeilenumbruch');
$this->assert(
str_contains($text, 'Wichtiger Hinweis: Die Überweisung wird ohne Korrektur ausgeführt.'),
'Auch der letzte Absatz steht da'
);
$this->assert(!str_contains($text, "\n\n\n"), 'Keine Leerzeilenwüsten');
$this->assertEquals('', FinTsUeberweisung::vopHinweis(''), 'Ohne Text bleibt es leer');
$this->assertEquals('', FinTsUeberweisung::vopHinweis(' '), 'Leerraum zählt als kein Text');
}
private function ohneWartendenVorgangGehtNichts(): void
{
$this->assertNull(FinTsUeberweisung::offeneVopAnfrage(), 'Ohne Vorgang wartet kein Namensabgleich');
$ergebnis = FinTsUeberweisung::vopBestaetigen();
$this->assertEquals('fehler', $ergebnis['status'], 'Ohne Vorgang lässt sich nichts bestätigen');
$this->assertNotEmpty($ergebnis['meldung'], 'Und es gibt eine Erklärung dazu');
}
/**
* Meldet die Bank Namensabgleich (Volltreffer) und TAN-Anfrage im selben
* Antwortsatz, wirft php-fints (Stand v4.1.4) dafür eine rohe
* `UnsupportedException`, statt die Kombination zu behandeln – obwohl der
* Vorgang beide Angaben zu diesem Zeitpunkt schon trägt. Ungefangen landete
* ihr englischer Text als Fehlermeldung beim Nutzer (Fix #89). Geprüft wird
* hier die Erkennung selbst; der volle Ablauf (automatische Bestätigung,
* anschließende TAN-Anfrage) lässt sich ohne Bankverbindung nicht auslösen.
*/
private function dieBekannteVopTanLueckeWirdErkannt(): void
{
$istLuecke = new ReflectionMethod(FinTsUeberweisung::class, 'istBekannteVopTanLuecke');
$istLuecke->setAccessible(true);
$this->assert(
$istLuecke->invoke(null, new UnsupportedException('Combined VOP match confirmation and TAN request')),
'Die bekannte Meldung wird erkannt'
);
$this->assert(
!$istLuecke->invoke(null, new UnsupportedException('The bank does not support the XML schema x')),
'Eine andere UnsupportedException der Bibliothek wird nicht mit ihr verwechselt'
);
}
}