107 lines
5.6 KiB
PHP
107 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Test 92: Bankleitzahlen-Verzeichnis (Fix #187).
|
|
*
|
|
* Deckt FintsInstituteImport (ISO-8859-1, mehrzeiliger Institutsname in
|
|
* Anführungszeichen, doppelte Bankleitzahlen, überzählige Leerzeilen am
|
|
* Ende, Text statt Adresse in der PIN/TAN-Spalte, fehlende Pflicht-Header,
|
|
* Stand-Erkennung) sowie Models\Bankinstitut (replaceAll, search,
|
|
* findAccessPointByBlz, importMeta) ab.
|
|
*/
|
|
class BankinstituteTest extends TestCase
|
|
{
|
|
protected string $testName = 'Test 92: Bankleitzahlen-Verzeichnis';
|
|
|
|
private function makeIso88591Csv(string $utf8Content): string
|
|
{
|
|
$path = $this->tempPath('.csv');
|
|
file_put_contents($path, mb_convert_encoding($utf8Content, 'ISO-8859-1', 'UTF-8'));
|
|
return $path;
|
|
}
|
|
|
|
public function run(): void
|
|
{
|
|
$import = new \Steuerkram\Services\FintsInstituteImport();
|
|
|
|
// ── Vollständige, realistische Datei ───────────────────────────
|
|
$csv = "Kreditinstitute mit PIN/TAN-Zugang Stand: 20.05.2026\n"
|
|
. "BLZ;Institut;Ort;BIC;PIN/TAN-Zugang URL;DDV;RDH-1\n"
|
|
. "10030000;Sparkasse Köln Bonn;Köln;COLSDE33XXX;https://banking.spk.de/fints;1;1\n"
|
|
. "10030000;Sparkasse Köln Bonn Filiale;Bonn;COLSDE33XXX;https://banking.spk.de/fints;1;1\n"
|
|
. "12030000;\"Oldenburgische\nLandesbank\";Oldenburg;OLBODEH2XXX;https://fints.oldenburgischelandesbank.de;0;1\n"
|
|
. "99999999;Kleine Bank ohne Zugang;Nirgendwo;;kein PIN/TAN-Zugang;0;0\n"
|
|
. "88888888;;;;;;\n"
|
|
. ";;;;;;\n"
|
|
. "88888889;;;;;;\n";
|
|
|
|
$tmp = $this->makeIso88591Csv($csv);
|
|
$result = $import->analyze($tmp, 'blz-aktuell-csv-data.csv');
|
|
|
|
$this->assertEquals(4, $result['zeilen'], 'Vier verwertbare Zeilen (Leerzeilen am Ende ausgeschlossen)');
|
|
$this->assertEquals(3, $result['blz_anzahl'], 'Drei verschiedene Bankleitzahlen (10030000 doppelt)');
|
|
$this->assertEquals(3, $result['mit_zugangspunkt'], 'Drei Zeilen mit echtem PIN/TAN-Zugangspunkt (die vierte hat nur Text statt Adresse)');
|
|
$this->assertEquals('20.05.2026', $result['stand'], 'Stand aus der Titelzeile erkannt');
|
|
|
|
$names = array_column($result['rows'], 'name');
|
|
$this->assert(
|
|
(bool)preg_grep('/Oldenburgische.*Landesbank/s', $names),
|
|
'Mehrzeiliger, in Anführungszeichen stehender Institutsname wird als eine Zeile gelesen'
|
|
);
|
|
|
|
$koeln = $result['rows'][0];
|
|
$this->assertEquals('Köln', mb_substr($koeln['ort'], 0, 4), 'ISO-8859-1 → UTF-8: Umlaut in "Köln" korrekt dekodiert');
|
|
|
|
$ohneZugang = array_values(array_filter($result['rows'], fn($r) => $r['blz'] === '99999999'))[0];
|
|
$this->assert($ohneZugang['pin_tan_url'] === null, 'Text statt Adresse in der PIN/TAN-Spalte wird nicht als URL übernommen');
|
|
|
|
$this->assert(
|
|
!in_array('88888888', array_column($result['rows'], 'blz'), true)
|
|
&& !in_array('88888889', array_column($result['rows'], 'blz'), true),
|
|
'Zeilen ohne Institutsnamen (trailing Leerzeilen) werden übersprungen'
|
|
);
|
|
|
|
// ── Fehlender Pflicht-Header bricht den Import ab ──────────────
|
|
$csvOhneHeader = "Nur irgendein Text;ohne;Header\n1;2;3\n";
|
|
$tmpBad = $this->makeIso88591Csv($csvOhneHeader);
|
|
$exceptionThrown = false;
|
|
try {
|
|
$import->analyze($tmpBad, 'kaputt.csv');
|
|
} catch (\RuntimeException $e) {
|
|
$exceptionThrown = true;
|
|
}
|
|
$this->assert($exceptionThrown, 'Fehlen BLZ/Institut-Header, wird der Import mit RuntimeException abgebrochen');
|
|
|
|
// ── Models\Bankinstitut: replaceAll / search / findAccessPointByBlz ──
|
|
\Steuerkram\Models\Bankinstitut::replaceAll($result['rows'], [
|
|
'filename' => 'blz-aktuell-csv-data.csv',
|
|
'stand' => $result['stand'],
|
|
'zeilen' => $result['zeilen'],
|
|
'blz_anzahl' => $result['blz_anzahl'],
|
|
'mit_zugangspunkt' => $result['mit_zugangspunkt'],
|
|
]);
|
|
|
|
$this->assertEquals(4, \Steuerkram\Models\Bankinstitut::count(), 'replaceAll() hat vier Zeilen übernommen');
|
|
|
|
$treffer = \Steuerkram\Models\Bankinstitut::findAccessPointByBlz('10030000');
|
|
$this->assert($treffer !== null && $treffer['pin_tan_url'] === 'https://banking.spk.de/fints', 'findAccessPointByBlz() liefert Zugangspunkt trotz doppelter BLZ');
|
|
|
|
$suchtreffer = \Steuerkram\Models\Bankinstitut::search('1822', 10);
|
|
$this->assertEquals(0, count($suchtreffer), 'Suche nach "1822" findet keinen Treffer, wenn weder BLZ noch Name/Ort/BIC passen');
|
|
|
|
$suchtreffer2 = \Steuerkram\Models\Bankinstitut::search('Köln', 10);
|
|
$this->assertGreaterThan(0, count($suchtreffer2), 'Suche über den Namen findet Treffer');
|
|
|
|
$meta = \Steuerkram\Models\Bankinstitut::importMeta();
|
|
$this->assertEquals('20.05.2026', $meta['stand'] ?? null, 'importMeta() liefert den zuletzt importierten Stand');
|
|
|
|
// ── Ein zweiter Import ersetzt den Bestand vollständig ─────────
|
|
\Steuerkram\Models\Bankinstitut::replaceAll(
|
|
[['blz' => '11111111', 'name' => 'Nur noch dieses Institut', 'ort' => 'X', 'bic' => '', 'pin_tan_url' => null]],
|
|
['filename' => 'neu.csv', 'stand' => null, 'zeilen' => 1, 'blz_anzahl' => 1, 'mit_zugangspunkt' => 0]
|
|
);
|
|
$this->assertEquals(1, \Steuerkram\Models\Bankinstitut::count(), 'Ein erneuter Import ersetzt den gesamten Bestand statt ihn zu ergänzen');
|
|
}
|
|
}
|