Finanzmanager/tests/46_SammelabrufTest.php
fds2610-bot 4d833f273b Fix #75: Knopf „Alle Umsätze abrufen“ ruft jede Bank der Reihe nach ab
Über der Tabelle der Bankverbindungen ruft ein neuer Knopf jede aktive
Bankverbindung einzeln nacheinander ab. Die Warteschlange (Services\Sammelabruf)
übersteht TAN-Runden in der Sitzung; nach der Freigabe geht es mit der nächsten
Bank weiter. Die TAN-Maske zeigt den Stand und erlaubt, eine Bank zu
überspringen. Am Ende steht je Bankverbindung eine eigene Meldung.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:38:24 +02:00

138 lines
5.7 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 Finanzmanager\Models\Bankzugang;
use Finanzmanager\Services\Sammelabruf;
/**
* „Alle Umsätze abrufen“: die Warteschlange über alle aktiven Bankverbindungen.
*
* Der Abruf selbst bleibt außen vor – geprüft wird, dass jede Bank der Reihe
* nach drankommt, ein Fehler die übrigen nicht aufhält, die Warteschlange eine
* TAN-Pause in der Sitzung übersteht und am Ende je Bank eine Meldung steht.
*/
class SammelabrufTest extends TestCase
{
protected string $testName = 'Test 46: Alle Umsätze abrufen';
public function run(): void
{
$this->mandantAnlegen();
$this->nurAktiveKommenDran();
$this->jedeBankDerReiheNach();
$this->derZustandUeberstehtDieTanPause();
$this->ueberspringenUndAbbrechen();
$this->kaputterZustandIstKeinLauf();
}
private function nurAktiveKommenDran(): void
{
foreach (['Sammel B' => 1, 'Sammel A' => 1, 'Sammel ruht' => 0] as $name => $aktiv) {
Bankzugang::anlegen([
'name' => $name,
'blz' => '12030000',
'fints_url' => 'https://banking.example.org/fints',
'benutzerkennung' => 'kunde',
'pin' => 'geheim',
'abrufzeitraum' => 'letzter_abruf',
'aktiv' => $aktiv,
]);
}
$lauf = Sammelabruf::fuer(Bankzugang::alle(true));
$namen = [];
while (($naechste = $lauf->naechste()) !== null) {
$namen[] = $naechste['name'];
$lauf->vermerke(['status' => 'erfolg', 'meldung' => 'ok']);
}
$this->assertEquals(['Sammel A', 'Sammel B'], $namen,
'Nur aktive Bankverbindungen, in der Reihenfolge der Übersicht');
}
private function jedeBankDerReiheNach(): void
{
$lauf = Sammelabruf::fuer([
['id' => 1, 'name' => 'Girobank'],
['id' => 2, 'name' => 'Kaputtbank'],
['id' => 3, 'name' => 'PayPal'],
]);
$this->assertNull($lauf->aktuell(), 'Vor dem Start läuft keine Bank');
$this->assertEquals(1, $lauf->naechste()['id'] ?? null, 'Die erste Bank kommt zuerst');
$this->assertEquals(['nummer' => 1, 'gesamt' => 3, 'name' => 'Girobank'], $lauf->stand(),
'Der Stand nennt Bank 1 von 3');
$lauf->vermerke(['status' => 'erfolg', 'meldung' => '4 neue Umsätze.']);
$this->assertNull($lauf->aktuell(), 'Nach dem Vermerk läuft keine Bank mehr');
$this->assertEquals(2, $lauf->naechste()['id'] ?? null, 'Dann die zweite');
$lauf->vermerke(['status' => 'fehler', 'meldung' => 'PIN falsch.']);
$this->assertEquals(3, $lauf->naechste()['id'] ?? null,
'Ein Fehler hält die übrigen Banken nicht auf');
$lauf->vermerke(['status' => 'erfolg', 'meldung' => 'Nichts Neues.']);
$this->assertNull($lauf->naechste(), 'Danach ist die Warteschlange leer');
$this->assertEquals([
['typ' => 'erfolg', 'meldung' => 'Girobank: 4 neue Umsätze.'],
['typ' => 'fehler', 'meldung' => 'Kaputtbank: Abruf fehlgeschlagen: PIN falsch.'],
['typ' => 'erfolg', 'meldung' => 'PayPal: Nichts Neues.'],
], $lauf->meldungen(), 'Je Bankverbindung eine Meldung, Fehler als Fehler');
}
private function derZustandUeberstehtDieTanPause(): void
{
$lauf = Sammelabruf::fuer([
['id' => 7, 'name' => 'TAN-Bank'],
['id' => 8, 'name' => 'Folgebank'],
]);
$lauf->naechste();
// Wie in der Sitzung: serialisiert und im nächsten Request zurückgeholt.
$weiter = Sammelabruf::aus(unserialize(serialize($lauf->zustand())));
$this->assert($weiter !== null, 'Der Zustand lässt sich wiederherstellen');
$this->assertEquals(7, $weiter->aktuell()['id'] ?? null, 'Die fragende Bank ist noch die laufende');
$weiter->vermerke(['status' => 'erfolg', 'meldung' => 'Freigegeben.']);
$this->assertEquals(8, $weiter->naechste()['id'] ?? null, 'Nach der Freigabe geht es mit der nächsten weiter');
$this->assertEquals(['nummer' => 2, 'gesamt' => 2, 'name' => 'Folgebank'], $weiter->stand(),
'Der Stand zählt weiter');
}
private function ueberspringenUndAbbrechen(): void
{
$lauf = Sammelabruf::fuer([
['id' => 1, 'name' => 'Erste'],
['id' => 2, 'name' => 'Zweite'],
['id' => 3, 'name' => 'Dritte'],
['id' => 4, 'name' => 'Vierte'],
]);
$lauf->naechste();
$lauf->ueberspringe();
$this->assertEquals(2, $lauf->naechste()['id'] ?? null, 'Überspringen macht mit der nächsten weiter');
$lauf->abbrechen();
$this->assertNull($lauf->aktuell(), 'Nach dem Abbruch läuft nichts mehr');
$this->assertNull($lauf->naechste(), 'Nach dem Abbruch folgt keine Bank mehr');
$meldungen = $lauf->meldungen();
$this->assertEquals(2, count($meldungen), 'Übersprungene Bank und Abbruch je eine Meldung');
$this->assertEquals('fehler', $meldungen[0]['typ'], 'Übersprungen gilt als nicht abgerufen');
$this->assert(str_starts_with($meldungen[0]['meldung'], 'Erste: Übersprungen'),
'Die Meldung nennt die übersprungene Bank');
$this->assertEquals('Abruf abgebrochen – 3 Bankverbindungen nicht abgerufen.',
$meldungen[1]['meldung'], 'Der Abbruch zählt die laufende und die offenen Banken');
}
private function kaputterZustandIstKeinLauf(): void
{
$this->assertNull(Sammelabruf::aus(null), 'Ohne Zustand kein Lauf');
$this->assertNull(Sammelabruf::aus(['gesamt' => 3]), 'Ein unvollständiger Zustand ist kein Lauf');
}
}