mandantAnlegen(); $this->stammdaten(); $this->kontoOhneBankStehtNichtInDerZuordnung(); $this->zugeordnetesKontoStehtInDerZuordnung(); $this->einDeaktivierterZugangFaelltHeraus(); $this->derAuftragUebernimmtDieBankAutomatisch(); $this->dasAuftragskontoFindetSichUeberDieZuordnung(); $this->ohneZuordnungGreiftDieIbanAmKonto(); } /** * Beim Senden muss unter den Konten, die die Bank meldet, das richtige * gefunden werden. Maßgeblich ist dieselbe Zuordnung wie beim Umsatzabruf – * die IBAN am Konto selbst ist optional und bleibt meist leer. */ private function dasAuftragskontoFindetSichUeberDieZuordnung(): void { $gemeldet = [ $this->sepaKonto('DE29120300000000202052', '202052'), $this->sepaKonto('DE02120300000000202051', '202051'), ]; // Das Girokonto ist über `bank_konten` zugeordnet (siehe oben), hat aber // selbst keine IBAN. $treffer = FinTsUeberweisung::passendesKonto($gemeldet, $this->giro, $this->zugang); $this->assertEquals( 'DE29120300000000202052', $treffer?->getIban(), 'Das zugeordnete Bankkonto wird gefunden, obwohl am Konto keine IBAN steht' ); // Ein Konto ohne Zuordnung darf keines der gemeldeten erwischen. $this->assertNull( FinTsUeberweisung::passendesKonto($gemeldet, $this->ohneBank, $this->zugang), 'Ein nicht zugeordnetes Konto trifft auf nichts' ); // Meldet die Bank keine IBAN, bleibt die Kontonummer. $ohneIban = [$this->sepaKonto('', '202052'), $this->sepaKonto('', '999999')]; $this->assertEquals( '202052', FinTsUeberweisung::passendesKonto($ohneIban, $this->giro, $this->zugang)?->getAccountNumber(), 'Ohne IBAN führt die Kontonummer zum Ziel' ); } /** * Der bisherige Weg bleibt bestehen: Wer die IBAN am Konto gepflegt hat, * kommt auch ohne Zuordnung zum Ziel – und bei genau einem Konto bei der * Bank ist die Sache ohnehin eindeutig. */ private function ohneZuordnungGreiftDieIbanAmKonto(): void { $eigenes = Konto::anlegen([ 'name' => 'Zahlungsverkehr-Giro mit IBAN', 'kontoart' => 'bank', 'iban' => 'DE02120300000000202051', 'anfangssaldo' => 0, 'aktiv' => 1, ]); $gemeldet = [ $this->sepaKonto('DE29120300000000202052', '202052'), $this->sepaKonto('DE02120300000000202051', '202051'), ]; $this->assertEquals( 'DE02120300000000202051', FinTsUeberweisung::passendesKonto($gemeldet, $eigenes, $this->zugang)?->getIban(), 'Die IBAN am Konto genügt auch ohne Zuordnung' ); $einzelnes = [$this->sepaKonto('DE29120300000000202052', '202052')]; $this->assertNotEmpty( FinTsUeberweisung::passendesKonto($einzelnes, $this->ohneBank, $this->zugang), 'Führt die Bank nur ein Konto, ist es eindeutig' ); } private function sepaKonto(string $iban, string $kontonummer): SEPAAccount { $konto = new SEPAAccount(); $konto->setIban($iban); $konto->setBic('GENODEF1TES'); $konto->setAccountNumber($kontonummer); $konto->setBlz('12030000'); return $konto; } private function stammdaten(): void { $this->giro = Konto::anlegen([ 'name' => 'Zahlungsverkehr-Giro', 'kontoart' => 'bank', 'anfangssaldo' => 0, 'aktiv' => 1, ]); $this->ohneBank = Konto::anlegen([ 'name' => 'Zahlungsverkehr-Sparbuch', 'kontoart' => 'sparkonto', 'anfangssaldo' => 0, 'aktiv' => 1, ]); $this->zugang = Bankzugang::anlegen([ 'name' => 'Zahlungsverkehr-Bank', 'bankname' => 'Zahlungsverkehr-Bank AG', 'blz' => '12030000', 'fints_url' => 'https://banking.example.org/fints', 'benutzerkennung' => 'testkunde', 'pin' => 'geheim1234', 'abrufzeitraum' => 'letzter_abruf', 'aktiv' => 1, ]); } private function kontoOhneBankStehtNichtInDerZuordnung(): void { $this->assert( !array_key_exists($this->ohneBank, Bankzugang::zugangJeKonto()), 'Ein Konto ohne Bankverbindung fehlt in der Zuordnung' ); } private function zugeordnetesKontoStehtInDerZuordnung(): void { $bankkonto = Bankzugang::findeOderLegeKontoAn( $this->zugang, 'DE29120300000000202052', '202052', 'Girokonto' ); Bankzugang::ordneKontoZu((int)$bankkonto['id'], $this->giro); $this->assertEquals( $this->zugang, Bankzugang::zugangJeKonto()[$this->giro] ?? null, 'Das zugeordnete Konto verweist auf seine Bank' ); } private function einDeaktivierterZugangFaelltHeraus(): void { Bankzugang::speichern($this->zugang, [ 'name' => 'Zahlungsverkehr-Bank', 'bankname' => 'Zahlungsverkehr-Bank AG', 'blz' => '12030000', 'fints_url' => 'https://banking.example.org/fints', 'benutzerkennung' => 'testkunde', 'abrufzeitraum' => 'letzter_abruf', 'aktiv' => 0, ]); $this->assert( !array_key_exists($this->giro, Bankzugang::zugangJeKonto()), 'Ein deaktivierter Zugang taugt nicht als automatische Auswahl' ); Bankzugang::speichern($this->zugang, [ 'name' => 'Zahlungsverkehr-Bank', 'bankname' => 'Zahlungsverkehr-Bank AG', 'blz' => '12030000', 'fints_url' => 'https://banking.example.org/fints', 'benutzerkennung' => 'testkunde', 'abrufzeitraum' => 'letzter_abruf', 'aktiv' => 1, ]); } /** * Genau das, was der Controller beim Anlegen tut: die Bank kommt aus der * Zuordnung, nicht aus einer eigenen Formularauswahl. */ private function derAuftragUebernimmtDieBankAutomatisch(): void { $zugangId = Bankzugang::zugangJeKonto()[$this->giro] ?? null; $auftragId = Zahlungsauftrag::anlegen([ 'konto_id' => $this->giro, 'zugang_id' => $zugangId, 'empfaenger' => 'Beispielempfänger', 'iban' => 'DE02120300000000202051', 'betrag' => 42.50, ]); $this->assertEquals( $this->zugang, (int)Zahlungsauftrag::find($auftragId)['zugang_id'], 'Der Auftrag trägt die automatisch ermittelte Bank' ); } }