Ü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>
138 lines
5.7 KiB
PHP
138 lines
5.7 KiB
PHP
<?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');
|
||
}
|
||
}
|