Fix n.n.: Bekannte Umsätze bekommen IBAN und Bank der Gegenseite nachgetragen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5695e2e3df
commit
5d39293328
3 changed files with 193 additions and 2 deletions
10
Changes.md
10
Changes.md
|
|
@ -1,5 +1,15 @@
|
|||
# Änderungen
|
||||
|
||||
## Bekannte Umsätze bekommen IBAN und Bank der Gegenseite nachgetragen (29.09.2026)
|
||||
|
||||
- Der Tooltip im Kontoblatt blieb bei älteren Umsätzen leer: IBAN und Bank der Gegenseite
|
||||
werden erst seit dem 28.09. gespeichert, und ein erneuter Abruf übersprang bekannte Umsätze
|
||||
ganz. Jetzt trägt `Bankumsatz::anlegen()` bei einem bekannten Umsatz nach, was ihm fehlt
|
||||
(`Bankumsatz::ergaenzen()`), und gibt es an die verbundene Buchung weiter. Nur leere Felder
|
||||
werden gefüllt, vorhandene bleiben.
|
||||
- Auch `Bankumsatz::verbinden()` überträgt die Angaben auf eine von Hand erfasste Buchung.
|
||||
- Neu: Test 49.
|
||||
|
||||
## E2E-Läufe lassen die Einstellungen unverändert (29.09.2026)
|
||||
|
||||
- Die Browser-Tests laufen gegen die echte Instanz; der Bargeld-Test hatte dabei die Adresse
|
||||
|
|
|
|||
|
|
@ -80,11 +80,17 @@ class Bankumsatz
|
|||
/**
|
||||
* @param array<string,mixed> $daten
|
||||
* @return int|null Die neue Kennung, oder null wenn der Umsatz schon da war.
|
||||
* Ein bekannter Umsatz bekommt dabei nachgetragen, was ihm bisher
|
||||
* fehlte (siehe ergaenzen()).
|
||||
*/
|
||||
public static function anlegen(array $daten): ?int
|
||||
{
|
||||
$externId = (string)($daten['extern_id'] ?? '');
|
||||
if ($externId === '' || self::existiert($externId)) {
|
||||
if ($externId === '') {
|
||||
return null;
|
||||
}
|
||||
if (self::existiert($externId)) {
|
||||
self::ergaenzen($externId, $daten);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +123,53 @@ class Bankumsatz
|
|||
return Database::lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trägt IBAN und Bank der Gegenseite bei einem bereits bekannten Umsatz
|
||||
* nach. Ältere Abrufe haben sie noch nicht gespeichert; der erneute Abruf
|
||||
* liefert sie, und der Fingerabdruck erkennt den Umsatz nur als bekannt.
|
||||
* Nur leere Felder werden gefüllt – was schon dasteht, bleibt. Hängt der
|
||||
* Umsatz an einer Buchung, bekommt auch sie die Angaben, soweit sie dort
|
||||
* fehlen.
|
||||
*
|
||||
* @param array<string,mixed> $daten
|
||||
*/
|
||||
public static function ergaenzen(string $externId, array $daten): void
|
||||
{
|
||||
$iban = mb_substr(strtoupper(trim((string)($daten['gegen_iban'] ?? ''))), 0, 34);
|
||||
$bankname = mb_substr(trim((string)($daten['gegen_bankname'] ?? '')), 0, 128);
|
||||
if ($iban === '' && $bankname === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
Database::execute(
|
||||
"UPDATE bank_umsaetze
|
||||
SET gegen_iban = IF(gegen_iban = '', ?, gegen_iban),
|
||||
gegen_bankname = IF(gegen_bankname = '', ?, gegen_bankname)
|
||||
WHERE benutzer_id = ? AND extern_id = ?",
|
||||
[$iban, $bankname, Mandant::id(), $externId]
|
||||
);
|
||||
|
||||
$buchungId = Database::fetchValue(
|
||||
'SELECT buchung_id FROM bank_umsaetze WHERE benutzer_id = ? AND extern_id = ?',
|
||||
[Mandant::id(), $externId]
|
||||
);
|
||||
if ($buchungId !== null && $buchungId !== false) {
|
||||
self::herkunftUebertragen((int)$buchungId, $iban, $bankname);
|
||||
}
|
||||
}
|
||||
|
||||
/** Füllt IBAN und Bank einer Buchung, soweit sie dort noch leer sind. */
|
||||
private static function herkunftUebertragen(int $buchungId, string $iban, string $bankname): void
|
||||
{
|
||||
Database::execute(
|
||||
"UPDATE buchungen
|
||||
SET iban = IF(iban = '', ?, iban),
|
||||
bankname = IF(bankname = '', ?, bankname)
|
||||
WHERE id = ? AND benutzer_id = ?",
|
||||
[$iban, $bankname, $buchungId, Mandant::id()]
|
||||
);
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
{
|
||||
$zeile = Database::fetchOne(
|
||||
|
|
@ -323,11 +376,20 @@ class Bankumsatz
|
|||
);
|
||||
|
||||
// Was von der Bank kommt, ist dort gebucht – das Kennzeichen der
|
||||
// verbundenen Buchung wird nachgezogen.
|
||||
// verbundenen Buchung wird nachgezogen, ebenso IBAN und Bank der
|
||||
// Gegenseite, falls die Buchung sie nicht kennt.
|
||||
Database::execute(
|
||||
'UPDATE buchungen SET abgeglichen = 1 WHERE id = ? AND benutzer_id = ?',
|
||||
[$buchungId, Mandant::id()]
|
||||
);
|
||||
$umsatz = self::find($id);
|
||||
if ($umsatz !== null) {
|
||||
self::herkunftUebertragen(
|
||||
$buchungId,
|
||||
(string)($umsatz['gegen_iban'] ?? ''),
|
||||
(string)($umsatz['gegen_bankname'] ?? '')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function verwerfen(int $id): void
|
||||
|
|
|
|||
119
tests/49_UmsatzHerkunftNachtragenTest.php
Normal file
119
tests/49_UmsatzHerkunftNachtragenTest.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Finanzmanager\Database;
|
||||
use Finanzmanager\Models\Bankumsatz;
|
||||
use Finanzmanager\Models\Bankzugang;
|
||||
use Finanzmanager\Models\Buchung;
|
||||
use Finanzmanager\Models\Konto;
|
||||
|
||||
/**
|
||||
* IBAN und Bank der Gegenseite werden beim erneuten Abruf nachgetragen – auch
|
||||
* wenn der Umsatz schon bekannt ist und deshalb nicht neu angelegt wird.
|
||||
*/
|
||||
class UmsatzHerkunftNachtragenTest extends TestCase
|
||||
{
|
||||
protected string $testName = 'Test 49: Herkunft eines bekannten Umsatzes nachtragen';
|
||||
|
||||
private int $giro = 0;
|
||||
private int $zugang = 0;
|
||||
private int $bankkonto = 0;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->mandantAnlegen();
|
||||
|
||||
$this->giro = Konto::anlegen([
|
||||
'name' => 'Nachtragsgiro', 'kontoart' => 'bank', 'anfangssaldo' => 0, 'aktiv' => 1,
|
||||
]);
|
||||
$this->zugang = Bankzugang::anlegen([
|
||||
'name' => 'Nachtragsbank', 'bankname' => 'Nachtragsbank AG', 'blz' => '20041111',
|
||||
'fints_url' => 'https://banking.example.org/fints', 'benutzerkennung' => 'testkunde',
|
||||
'pin' => 'geheim1234', 'abrufzeitraum' => 'letzter_abruf', 'aktiv' => 1,
|
||||
]);
|
||||
$this->bankkonto = (int)Bankzugang::findeOderLegeKontoAn(
|
||||
$this->zugang,
|
||||
'DE53200411110847626900',
|
||||
'847626900',
|
||||
'Girokonto'
|
||||
)['id'];
|
||||
Bankzugang::ordneKontoZu($this->bankkonto, $this->giro);
|
||||
|
||||
$this->bekannterUmsatzBekommtHerkunft();
|
||||
$this->vorhandeneAngabenBleiben();
|
||||
$this->verbundeneBuchungBekommtHerkunft();
|
||||
$this->verbindenMitErfasstenBuchungUebertraegt();
|
||||
}
|
||||
|
||||
/** @return array<string,mixed> */
|
||||
private function daten(string $zweck, string $iban = '', string $bank = ''): array
|
||||
{
|
||||
return [
|
||||
'zugang_id' => $this->zugang,
|
||||
'konto_id' => $this->giro,
|
||||
'bank_konto_id' => $this->bankkonto,
|
||||
'extern_id' => Bankumsatz::externId($this->bankkonto, '2026-09-04', 0.01, $zweck),
|
||||
'buchungstag' => '2026-09-04',
|
||||
'wertstellung' => '2026-09-04',
|
||||
'betrag' => 0.01,
|
||||
'empfaenger' => 'Testabsender',
|
||||
'verwendungszweck' => $zweck,
|
||||
'gegen_iban' => $iban,
|
||||
'gegen_bankname' => $bank,
|
||||
];
|
||||
}
|
||||
|
||||
private function bekannterUmsatzBekommtHerkunft(): void
|
||||
{
|
||||
$id = Bankumsatz::anlegen($this->daten('Cent eins'));
|
||||
$this->assertNotEmpty($id, 'Umsatz ohne Herkunft angelegt');
|
||||
|
||||
$zweiter = Bankumsatz::anlegen($this->daten('Cent eins', 'de89370400440532013000', 'Testbank'));
|
||||
$this->assertNull($zweiter, 'Zweiter Abruf legt keinen neuen Umsatz an');
|
||||
|
||||
$umsatz = Bankumsatz::find((int)$id);
|
||||
$this->assertEquals('DE89370400440532013000', $umsatz['gegen_iban'], 'IBAN nachgetragen');
|
||||
$this->assertEquals('Testbank', $umsatz['gegen_bankname'], 'Bank nachgetragen');
|
||||
}
|
||||
|
||||
private function vorhandeneAngabenBleiben(): void
|
||||
{
|
||||
$id = Bankumsatz::anlegen($this->daten('Cent zwei', 'DE02120300000000202051', 'Erste Bank'));
|
||||
Bankumsatz::anlegen($this->daten('Cent zwei', 'DE89370400440532013000', 'Andere Bank'));
|
||||
|
||||
$umsatz = Bankumsatz::find((int)$id);
|
||||
$this->assertEquals('DE02120300000000202051', $umsatz['gegen_iban'], 'Vorhandene IBAN bleibt');
|
||||
$this->assertEquals('Erste Bank', $umsatz['gegen_bankname'], 'Vorhandene Bank bleibt');
|
||||
}
|
||||
|
||||
private function verbundeneBuchungBekommtHerkunft(): void
|
||||
{
|
||||
$id = (int)Bankumsatz::anlegen($this->daten('Cent drei'));
|
||||
$buchungId = Bankumsatz::uebernehmen($id, []);
|
||||
|
||||
$vorher = Buchung::find($buchungId);
|
||||
$this->assertEquals('', (string)$vorher['iban'], 'Buchung zunächst ohne IBAN');
|
||||
|
||||
Bankumsatz::anlegen($this->daten('Cent drei', 'DE89370400440532013000', 'Testbank'));
|
||||
|
||||
$buchung = Buchung::find($buchungId);
|
||||
$this->assertEquals('DE89370400440532013000', $buchung['iban'], 'IBAN in der Buchung');
|
||||
$this->assertEquals('Testbank', $buchung['bankname'], 'Bank in der Buchung');
|
||||
}
|
||||
|
||||
private function verbindenMitErfasstenBuchungUebertraegt(): void
|
||||
{
|
||||
$buchungId = Buchung::anlegen([
|
||||
'konto_id' => $this->giro, 'datum' => '2026-09-04', 'betrag' => 0.01,
|
||||
'empfaenger' => 'Von Hand', 'buchungstext' => 'Cent vier',
|
||||
]);
|
||||
$id = (int)Bankumsatz::anlegen($this->daten('Cent vier', 'DE02120300000000202051', 'Handbank'));
|
||||
|
||||
Bankumsatz::verbinden($id, $buchungId);
|
||||
|
||||
$buchung = Buchung::find($buchungId);
|
||||
$this->assertEquals('DE02120300000000202051', $buchung['iban'], 'Verbinden überträgt die IBAN');
|
||||
$this->assertEquals('Handbank', $buchung['bankname'], 'Verbinden überträgt die Bank');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue