Merge pull request 'Fix n.n.: Einnahme/Ausgabe entscheidet der Geldfluss, nicht die Kategorie-Art' (#86) from fds2610-bot/Finanzmanager:main into main
Reviewed-on: https://codeberg.org/fds2610/Finanzmanager/pulls/86
This commit is contained in:
commit
1a8b64e71d
3 changed files with 124 additions and 42 deletions
23
Changes.md
23
Changes.md
|
|
@ -1,5 +1,28 @@
|
||||||
# Änderungen
|
# Änderungen
|
||||||
|
|
||||||
|
## Einnahme/Ausgabe entscheidet der Geldfluss, nicht die Kategorie-Art (28.09.2026)
|
||||||
|
|
||||||
|
Cockpit und Berichte zählten eine Bewegung nach der Art ihrer Kategorie zu Einnahmen
|
||||||
|
oder Ausgaben – nicht nach ihrem Vorzeichen. Eine Kategorie wie eine Rückstellung, die
|
||||||
|
in beide Richtungen bebucht wird (z. B. „010 - Rückst. USt“, angelegt als Einnahme),
|
||||||
|
ließ dadurch auch negative Beträge in den Einnahmen auftauchen (n.n., Buchung 29285).
|
||||||
|
|
||||||
|
- `Auswertung::artDerBewegung()` entscheidet jetzt allein über das Vorzeichen des
|
||||||
|
Betrags. Die zugewiesene Kategorie-Art spielt für die Auswertung keine Rolle mehr –
|
||||||
|
sie bleibt reine Verwaltungs-Metadaten (Reiter in der Kategorienverwaltung,
|
||||||
|
Vorzeichen im Budgetplaner).
|
||||||
|
- `Auswertung::kategoriezeilen()` baut das Zeilengerüst von Summen- und
|
||||||
|
Vergleichsbericht jetzt aus allen Kategorien statt nur denen der passenden Art –
|
||||||
|
sonst wäre eine Bewegung wie oben zwar in der Abschnittssumme, aber in keiner Zeile
|
||||||
|
aufgetaucht.
|
||||||
|
- `Auswertung::budgetbericht()` summiert den Ist-Wert einer Kategorie jetzt aus beiden
|
||||||
|
Töpfen (Einnahme und Ausgabe), da eine Kategorie nun in beiden auftauchen kann.
|
||||||
|
- Betroffen waren dadurch alle Cockpit-Kacheln, die auf dem Summenbericht aufsetzen
|
||||||
|
(*Einnahmen und Ausgaben*, *Meine Ausgaben*) sowie deren Legenden-Drilldown,
|
||||||
|
Summen-, Vergleichs- und Budgetbericht unter *Auswertungen*.
|
||||||
|
- Neuer Test `summenbericht_geldflussEntscheidet()` in `tests/14_AuswertungTest.php`
|
||||||
|
mit einer Kategorie, die in beide Richtungen bebucht wird.
|
||||||
|
|
||||||
## Cockpit: Legendeneinträge öffnen die Buchungen dahinter (28.09.2026)
|
## Cockpit: Legendeneinträge öffnen die Buchungen dahinter (28.09.2026)
|
||||||
|
|
||||||
In allen Cockpit-Kacheln mit Legende führt ein Klick auf einen Legendeneintrag zu den
|
In allen Cockpit-Kacheln mit Legende führt ein Klick auf einen Legendeneintrag zu den
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,13 @@ use Finanzmanager\View;
|
||||||
* Erst beim Zusammenstellen der Abschnitte dreht der Ausgabenabschnitt sein
|
* Erst beim Zusammenstellen der Abschnitte dreht der Ausgabenabschnitt sein
|
||||||
* Vorzeichen, damit dort – wie im FinanzManager – 636,39 statt −636,39 steht.
|
* Vorzeichen, damit dort – wie im FinanzManager – 636,39 statt −636,39 steht.
|
||||||
* Die Schlusszeile „Einnahmen − Ausgaben“ rechnet wieder mit den echten Werten.
|
* Die Schlusszeile „Einnahmen − Ausgaben“ rechnet wieder mit den echten Werten.
|
||||||
|
*
|
||||||
|
* **Einnahme oder Ausgabe entscheidet allein der Geldfluss**, also das
|
||||||
|
* Vorzeichen der Bewegung – nicht die Art der zugewiesenen Kategorie. Die
|
||||||
|
* Kategorie-Art ist reine Verwaltungs-Metadaten (Reiter in der
|
||||||
|
* Kategorienverwaltung, Vorzeichen im Budgetplaner) und wirkt sich auf
|
||||||
|
* Berichte und Cockpit nicht mehr aus. So bleibt etwa eine Rückstellung, die
|
||||||
|
* in beide Richtungen bebucht wird, in jeder Richtung an der richtigen Stelle.
|
||||||
*/
|
*/
|
||||||
class Auswertung
|
class Auswertung
|
||||||
{
|
{
|
||||||
|
|
@ -200,13 +207,12 @@ class Auswertung
|
||||||
$filter['von'] = $zeitraum['von'];
|
$filter['von'] = $zeitraum['von'];
|
||||||
$filter['bis'] = $zeitraum['bis'];
|
$filter['bis'] = $zeitraum['bis'];
|
||||||
|
|
||||||
$arten = self::kategorienArten();
|
|
||||||
$wurzeln = self::wurzeln();
|
$wurzeln = self::wurzeln();
|
||||||
$faktor = $art === 'ausgabe' ? -1.0 : 1.0;
|
$faktor = $art === 'ausgabe' ? -1.0 : 1.0;
|
||||||
|
|
||||||
$summen = [];
|
$summen = [];
|
||||||
foreach (self::bewegungen($filter) as $bewegung) {
|
foreach (self::bewegungen($filter) as $bewegung) {
|
||||||
if (self::artDerBewegung($bewegung, $arten) !== $art) {
|
if (self::artDerBewegung($bewegung) !== $art) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -369,7 +375,7 @@ class Auswertung
|
||||||
$faktor = $art === 'ausgabe' ? -1.0 : 1.0;
|
$faktor = $art === 'ausgabe' ? -1.0 : 1.0;
|
||||||
|
|
||||||
$zeilen = $filter['zeilensumme'] === 'kategorie'
|
$zeilen = $filter['zeilensumme'] === 'kategorie'
|
||||||
? self::kategoriezeilen($art, $werte, $filter, $spalten, $faktor)
|
? self::kategoriezeilen($werte, $filter, $spalten, $faktor)
|
||||||
: self::flacheZeilen($werte, $filter, $spalten, $faktor);
|
: self::flacheZeilen($werte, $filter, $spalten, $faktor);
|
||||||
|
|
||||||
$summe = self::leereReihe($spalten);
|
$summe = self::leereReihe($spalten);
|
||||||
|
|
@ -395,14 +401,20 @@ class Auswertung
|
||||||
* „Gesamt <Name>“ mit der Summe des Astes. Genau so sieht der Summenbericht
|
* „Gesamt <Name>“ mit der Summe des Astes. Genau so sieht der Summenbericht
|
||||||
* des FinanzManagers aus.
|
* des FinanzManagers aus.
|
||||||
*
|
*
|
||||||
|
* Der Baum läuft über *alle* Kategorien, unabhängig von ihrer eigenen Art:
|
||||||
|
* Einnahme und Ausgabe entscheidet die einzelne Bewegung, nicht die
|
||||||
|
* Kategorie. Äste ohne Bewegung dieser Art bleiben einfach leer und fallen
|
||||||
|
* weiter unten heraus – eine sonst als Ausgabe geführte Kategorie kann so
|
||||||
|
* mit einer einzelnen Gutschrift trotzdem im Einnahmen-Abschnitt auftauchen.
|
||||||
|
*
|
||||||
* @param array<string|int, array<string,float>> $werte
|
* @param array<string|int, array<string,float>> $werte
|
||||||
* @param array<string,mixed> $filter
|
* @param array<string,mixed> $filter
|
||||||
* @param list<array<string,string>> $spalten
|
* @param list<array<string,string>> $spalten
|
||||||
* @return list<array<string,mixed>>
|
* @return list<array<string,mixed>>
|
||||||
*/
|
*/
|
||||||
private static function kategoriezeilen(string $art, array $werte, array $filter, array $spalten, float $faktor): array
|
private static function kategoriezeilen(array $werte, array $filter, array $spalten, float $faktor): array
|
||||||
{
|
{
|
||||||
$baum = Kategorie::baumFlach($art);
|
$baum = Kategorie::baumFlach();
|
||||||
|
|
||||||
// Astsummen von unten nach oben: Erst die eigenen Werte, dann trägt
|
// Astsummen von unten nach oben: Erst die eigenen Werte, dann trägt
|
||||||
// jede Kategorie ihre Summe an die Elternkategorie hoch.
|
// jede Kategorie ihre Summe an die Elternkategorie hoch.
|
||||||
|
|
@ -720,12 +732,10 @@ class Auswertung
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$arten = self::kategorienArten();
|
|
||||||
|
|
||||||
$bewegungen = array_values(array_filter(
|
$bewegungen = array_values(array_filter(
|
||||||
self::bewegungen($filter),
|
self::bewegungen($filter),
|
||||||
static function (array $bewegung) use ($dimension, $wert, $astIds, $alle, $art, $arten): bool {
|
static function (array $bewegung) use ($dimension, $wert, $astIds, $alle, $art): bool {
|
||||||
if ($art !== '' && self::artDerBewegung($bewegung, $arten) !== $art) {
|
if ($art !== '' && self::artDerBewegung($bewegung) !== $art) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($alle) {
|
if ($alle) {
|
||||||
|
|
@ -1079,13 +1089,15 @@ class Auswertung
|
||||||
$gesamt = ['budget' => 0.0, 'ist' => 0.0];
|
$gesamt = ['budget' => 0.0, 'ist' => 0.0];
|
||||||
|
|
||||||
// Astsummen: Eine Elternkategorie zeigt, was ihr Zweig geplant und
|
// Astsummen: Eine Elternkategorie zeigt, was ihr Zweig geplant und
|
||||||
// verbraucht hat – genau wie im Budgetplaner.
|
// verbraucht hat – genau wie im Budgetplaner. Das Ist steht je nach
|
||||||
|
// Vorzeichen der einzelnen Bewegung im Einnahme- oder Ausgabe-Topf;
|
||||||
|
// eine Kategorie kann durchaus in beiden stehen.
|
||||||
$astBudget = [];
|
$astBudget = [];
|
||||||
$astIst = [];
|
$astIst = [];
|
||||||
foreach ($baum as $kategorie) {
|
foreach ($baum as $kategorie) {
|
||||||
$id = (int)$kategorie['id'];
|
$id = (int)$kategorie['id'];
|
||||||
$astBudget[$id] = $summenBudget[$id] ?? 0.0;
|
$astBudget[$id] = $summenBudget[$id] ?? 0.0;
|
||||||
$astIst[$id] = $ist[self::art($kategorie)][$id]['ist'] ?? 0.0;
|
$astIst[$id] = ($ist['einnahme'][$id]['ist'] ?? 0.0) + ($ist['ausgabe'][$id]['ist'] ?? 0.0);
|
||||||
}
|
}
|
||||||
foreach (array_reverse($baum) as $kategorie) {
|
foreach (array_reverse($baum) as $kategorie) {
|
||||||
$eltern = $kategorie['eltern_id'] === null ? 0 : (int)$kategorie['eltern_id'];
|
$eltern = $kategorie['eltern_id'] === null ? 0 : (int)$kategorie['eltern_id'];
|
||||||
|
|
@ -1225,7 +1237,6 @@ class Auswertung
|
||||||
*/
|
*/
|
||||||
private static function verteile(array $bewegungen, array $filter, array $spalten): array
|
private static function verteile(array $bewegungen, array $filter, array $spalten): array
|
||||||
{
|
{
|
||||||
$arten = self::kategorienArten();
|
|
||||||
$aufteilung = (string)$filter['aufteilung'];
|
$aufteilung = (string)$filter['aufteilung'];
|
||||||
$gueltig = array_flip(array_column($spalten, 'schluessel'));
|
$gueltig = array_flip(array_column($spalten, 'schluessel'));
|
||||||
|
|
||||||
|
|
@ -1236,7 +1247,7 @@ class Auswertung
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$art = self::artDerBewegung($zeile, $arten);
|
$art = self::artDerBewegung($zeile);
|
||||||
$schluessel = self::zeilenschluessel($zeile, (string)$filter['zeilensumme']);
|
$schluessel = self::zeilenschluessel($zeile, (string)$filter['zeilensumme']);
|
||||||
|
|
||||||
$roh[$art][$schluessel][$spalte] = ($roh[$art][$schluessel][$spalte] ?? 0.0) + (float)$zeile['betrag'];
|
$roh[$art][$schluessel][$spalte] = ($roh[$art][$schluessel][$spalte] ?? 0.0) + (float)$zeile['betrag'];
|
||||||
|
|
@ -1256,11 +1267,9 @@ class Auswertung
|
||||||
*/
|
*/
|
||||||
private static function verteileAuf(array $bewegungen, array $filter, string $spalte): array
|
private static function verteileAuf(array $bewegungen, array $filter, string $spalte): array
|
||||||
{
|
{
|
||||||
$arten = self::kategorienArten();
|
|
||||||
|
|
||||||
$roh = [];
|
$roh = [];
|
||||||
foreach ($bewegungen as $zeile) {
|
foreach ($bewegungen as $zeile) {
|
||||||
$art = self::artDerBewegung($zeile, $arten);
|
$art = self::artDerBewegung($zeile);
|
||||||
$schluessel = self::zeilenschluessel($zeile, (string)$filter['zeilensumme']);
|
$schluessel = self::zeilenschluessel($zeile, (string)$filter['zeilensumme']);
|
||||||
|
|
||||||
$roh[$art][$schluessel][$spalte] = ($roh[$art][$schluessel][$spalte] ?? 0.0) + (float)$zeile['betrag'];
|
$roh[$art][$schluessel][$spalte] = ($roh[$art][$schluessel][$spalte] ?? 0.0) + (float)$zeile['betrag'];
|
||||||
|
|
@ -1270,20 +1279,15 @@ class Auswertung
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Einnahme oder Ausgabe? Es entscheidet die *Art der Kategorie*, nicht das
|
* Einnahme oder Ausgabe? Es entscheidet allein der Geldfluss, also das
|
||||||
* Vorzeichen: Eine Erstattung ist eine negative Ausgabe und gehört unter
|
* Vorzeichen der Bewegung – nicht die Art der zugewiesenen Kategorie. Eine
|
||||||
* die Ausgaben, nicht unter die Einnahmen. Nur wo keine Kategorie steht,
|
* Kategorie wie eine Rückstellung kann in beide Richtungen bebucht werden;
|
||||||
* bleibt das Vorzeichen als einziger Anhaltspunkt.
|
* die Bewegung zählt dann jedes Mal dort, wo ihr Vorzeichen sie hinstellt.
|
||||||
*
|
*
|
||||||
* @param array<string,mixed> $zeile
|
* @param array<string,mixed> $zeile
|
||||||
* @param array<int,string> $arten
|
|
||||||
*/
|
*/
|
||||||
private static function artDerBewegung(array $zeile, array $arten): string
|
private static function artDerBewegung(array $zeile): string
|
||||||
{
|
{
|
||||||
if ($zeile['kategorie_id'] !== null && isset($arten[(int)$zeile['kategorie_id']])) {
|
|
||||||
return $arten[(int)$zeile['kategorie_id']];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (float)$zeile['betrag'] >= 0 ? 'einnahme' : 'ausgabe';
|
return (float)$zeile['betrag'] >= 0 ? 'einnahme' : 'ausgabe';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1327,22 +1331,6 @@ class Auswertung
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<int,string> kategorie_id => 'einnahme'|'ausgabe' */
|
|
||||||
private static function kategorienArten(): array
|
|
||||||
{
|
|
||||||
$arten = [];
|
|
||||||
foreach (Kategorie::alle() as $kategorie) {
|
|
||||||
$arten[(int)$kategorie['id']] = (string)$kategorie['art'];
|
|
||||||
}
|
|
||||||
return $arten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param array<string,mixed> $kategorie */
|
|
||||||
private static function art(array $kategorie): string
|
|
||||||
{
|
|
||||||
return (string)($kategorie['art'] ?? 'ausgabe');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die gewählten Kategorien samt aller Unterkategorien. Wer „400 - Leben“
|
* Die gewählten Kategorien samt aller Unterkategorien. Wer „400 - Leben“
|
||||||
* filtert, meint den ganzen Ast – alles andere wäre eine Überraschung.
|
* filtert, meint den ganzen Ast – alles andere wäre eine Überraschung.
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ class AuswertungTest extends TestCase
|
||||||
private int $einkauf = 0;
|
private int $einkauf = 0;
|
||||||
private int $freizeit = 0;
|
private int $freizeit = 0;
|
||||||
private int $gehalt = 0;
|
private int $gehalt = 0;
|
||||||
|
private int $ruecklage = 0;
|
||||||
private int $privat = 0;
|
private int $privat = 0;
|
||||||
private int $urlaub = 0;
|
private int $urlaub = 0;
|
||||||
|
|
||||||
|
|
@ -53,6 +54,10 @@ class AuswertungTest extends TestCase
|
||||||
$this->kontostandsbericht();
|
$this->kontostandsbericht();
|
||||||
$this->budgetbericht();
|
$this->budgetbericht();
|
||||||
|
|
||||||
|
// Bucht auf dem Girokonto – nach dem Kontostandsbericht, damit dessen
|
||||||
|
// auf den Cent genaue Salden nicht mit verschoben werden.
|
||||||
|
$this->summenbericht_geldflussEntscheidet();
|
||||||
|
|
||||||
$this->drilldown();
|
$this->drilldown();
|
||||||
$this->csvExport();
|
$this->csvExport();
|
||||||
$this->gespeicherteBerichte();
|
$this->gespeicherteBerichte();
|
||||||
|
|
@ -74,6 +79,11 @@ class AuswertungTest extends TestCase
|
||||||
$this->freizeit = Kategorie::anlegen(['name' => 'A-Freizeit', 'art' => 'ausgabe', 'eltern_id' => $this->leben]);
|
$this->freizeit = Kategorie::anlegen(['name' => 'A-Freizeit', 'art' => 'ausgabe', 'eltern_id' => $this->leben]);
|
||||||
$this->gehalt = Kategorie::anlegen(['name' => 'Auswertungsgehalt', 'art' => 'einnahme']);
|
$this->gehalt = Kategorie::anlegen(['name' => 'Auswertungsgehalt', 'art' => 'einnahme']);
|
||||||
|
|
||||||
|
// Als „Einnahme“ angelegt, aber wie eine Rückstellung gedacht: mal auf-,
|
||||||
|
// mal abgebaut. Genau der Fall, in dem Kategorie-Art und Geldfluss
|
||||||
|
// auseinanderfallen können.
|
||||||
|
$this->ruecklage = Kategorie::anlegen(['name' => 'Auswertungsrücklage', 'art' => 'einnahme']);
|
||||||
|
|
||||||
$this->privat = Klasse::anlegen('Auswertung-Privat');
|
$this->privat = Klasse::anlegen('Auswertung-Privat');
|
||||||
$this->urlaub = Klasse::anlegen('Auswertung-Urlaub');
|
$this->urlaub = Klasse::anlegen('Auswertung-Urlaub');
|
||||||
}
|
}
|
||||||
|
|
@ -405,6 +415,67 @@ class AuswertungTest extends TestCase
|
||||||
$this->assertEquals(100.0, $this->abschnitt($suche, 'ausgabe')['summe'], 'Die Suche filtert auf den Empfänger');
|
$this->assertEquals(100.0, $this->abschnitt($suche, 'ausgabe')['summe'], 'Die Suche filtert auf den Empfänger');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* „Auswertungsrücklage“ ist als Einnahme-Kategorie angelegt, wird hier
|
||||||
|
* aber in beide Richtungen bebucht – wie eine Rückstellung, die auf- und
|
||||||
|
* wieder abgebaut wird. Entscheidend ist der Geldfluss der einzelnen
|
||||||
|
* Bewegung, nicht die Art der Kategorie.
|
||||||
|
*/
|
||||||
|
private function summenbericht_geldflussEntscheidet(): void
|
||||||
|
{
|
||||||
|
// Splitbuchung: 25 Einkauf, 15 Aufbau der Rücklage – beides Ausgaben,
|
||||||
|
// obwohl die Rücklage als „Einnahme“-Kategorie angelegt ist.
|
||||||
|
Buchung::anlegen(
|
||||||
|
['konto_id' => $this->giro, 'datum' => '2026-06-10', 'betrag' => -40.0, 'empfaenger' => 'Finanzamt'],
|
||||||
|
[
|
||||||
|
['kategorie_id' => $this->einkauf, 'betrag' => -25.0, 'notiz' => 'Einkauf'],
|
||||||
|
['kategorie_id' => $this->ruecklage, 'betrag' => -15.0, 'notiz' => 'Rücklage aufbauen'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Auflösung eines Teils der Rücklage – hier ist es tatsächlich eine
|
||||||
|
// Einnahme.
|
||||||
|
Buchung::anlegen(['konto_id' => $this->giro, 'datum' => '2026-06-20', 'betrag' => 6.0,
|
||||||
|
'empfaenger' => 'Finanzamt', 'kategorie_id' => $this->ruecklage]);
|
||||||
|
|
||||||
|
$bericht = Auswertung::bericht([
|
||||||
|
'typ' => 'summenbericht', 'zeitraum' => 'benutzerdefiniert',
|
||||||
|
'von' => '2026-06-01', 'bis' => '2026-06-30',
|
||||||
|
], self::HEUTE);
|
||||||
|
|
||||||
|
$ausgaben = $this->abschnitt($bericht, 'ausgabe');
|
||||||
|
$einnahmen = $this->abschnitt($bericht, 'einnahme');
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
15.0,
|
||||||
|
$this->zeile($ausgaben, 'Auswertungsrücklage')['summe'],
|
||||||
|
'Der negative Split zählt als Ausgabe, unabhängig von der Kategorie-Art'
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
6.0,
|
||||||
|
$this->zeile($einnahmen, 'Auswertungsrücklage')['summe'],
|
||||||
|
'Der positive Betrag auf derselben Kategorie zählt als Einnahme'
|
||||||
|
);
|
||||||
|
$this->assertEquals(40.0, $ausgaben['summe'], 'Ausgabensumme enthält Einkauf und Rücklagenaufbau');
|
||||||
|
$this->assertEquals(6.0, $einnahmen['summe'], 'Einnahmensumme enthält nur die Auflösung');
|
||||||
|
$this->assertEquals(-34.0, $bericht['gesamt']['summe'], 'Gesamtsumme rechnet mit den echten Vorzeichen');
|
||||||
|
|
||||||
|
// Der Drilldown filtert ebenfalls nach dem Geldfluss der Bewegung.
|
||||||
|
$filter = ['typ' => 'summenbericht', 'zeitraum' => 'benutzerdefiniert',
|
||||||
|
'von' => '2026-06-01', 'bis' => '2026-06-30'];
|
||||||
|
$alsAusgabe = Auswertung::zeilenbuchungen(
|
||||||
|
$filter, 'kategorie:' . $this->ruecklage, '', false, self::HEUTE, 'ausgabe'
|
||||||
|
);
|
||||||
|
$this->assertEquals(1, count($alsAusgabe['buchungen']), 'Nur der negative Split gehört zu den Ausgaben');
|
||||||
|
$this->assertEquals(-15.0, $alsAusgabe['summe'], 'Mit buchhalterischem Vorzeichen');
|
||||||
|
|
||||||
|
$alsEinnahme = Auswertung::zeilenbuchungen(
|
||||||
|
$filter, 'kategorie:' . $this->ruecklage, '', false, self::HEUTE, 'einnahme'
|
||||||
|
);
|
||||||
|
$this->assertEquals(1, count($alsEinnahme['buchungen']), 'Nur die Auflösung gehört zu den Einnahmen');
|
||||||
|
$this->assertEquals(6.0, $alsEinnahme['summe'], 'Die Einnahme behält ihr Vorzeichen');
|
||||||
|
}
|
||||||
|
|
||||||
// ── Weitere Berichtstypen ────────────────────────────────────────────────
|
// ── Weitere Berichtstypen ────────────────────────────────────────────────
|
||||||
|
|
||||||
private function buchungsbericht(): void
|
private function buchungsbericht(): void
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue