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
|
# Ä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)
|
## 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
|
- 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
|
* @param array<string,mixed> $daten
|
||||||
* @return int|null Die neue Kennung, oder null wenn der Umsatz schon da war.
|
* @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
|
public static function anlegen(array $daten): ?int
|
||||||
{
|
{
|
||||||
$externId = (string)($daten['extern_id'] ?? '');
|
$externId = (string)($daten['extern_id'] ?? '');
|
||||||
if ($externId === '' || self::existiert($externId)) {
|
if ($externId === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (self::existiert($externId)) {
|
||||||
|
self::ergaenzen($externId, $daten);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,6 +123,53 @@ class Bankumsatz
|
||||||
return Database::lastInsertId();
|
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
|
public static function find(int $id): ?array
|
||||||
{
|
{
|
||||||
$zeile = Database::fetchOne(
|
$zeile = Database::fetchOne(
|
||||||
|
|
@ -323,11 +376,20 @@ class Bankumsatz
|
||||||
);
|
);
|
||||||
|
|
||||||
// Was von der Bank kommt, ist dort gebucht – das Kennzeichen der
|
// 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(
|
Database::execute(
|
||||||
'UPDATE buchungen SET abgeglichen = 1 WHERE id = ? AND benutzer_id = ?',
|
'UPDATE buchungen SET abgeglichen = 1 WHERE id = ? AND benutzer_id = ?',
|
||||||
[$buchungId, Mandant::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
|
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