# Auswertungen Der Bereich *Auswertungen* baut die Berichte des FinanzManagers nach: fünf Berichtstypen, eine Filterleiste, gespeicherte Berichte in Gruppen, Drilldown in die Buchungen und CSV-Export. Ein Bericht wird **nie gerechnet gespeichert**, sondern immer nur seine Frage. Die Zahlen entstehen bei jedem Aufruf neu aus den Buchungen. Ein Bericht mit der Zeitraumvorgabe „Letzter Monat“ zeigt im August den Juli und nicht für immer den Monat seiner Entstehung. ## Was gezählt wird Grundlage sind die **Bewegungen**: nicht gesplittete Buchungen mit ihrem Betrag, gesplittete über ihre Splitzeilen. Sonst zählte eine Splitbuchung doppelt oder gar nicht. **Umbuchungen bleiben außen vor.** Sie verschieben Vermögen zwischen eigenen Konten und sind weder Einnahme noch Ausgabe – dieselbe Regel wie im Budgetplaner. Allein der Buchungsbericht kann sie über den Schalter *Umbuchungen mitzählen* mitführen; dann weicht seine Summe naturgemäß vom Summenbericht ab. **Nicht kategorisierte Buchungen verschwinden nicht.** Sie stehen als eigene Zeile *Nicht kategorisiert* am Ende ihres Abschnitts. Geld, das keiner Kategorie zugeordnet ist, fiele sonst lautlos aus der Summe. Ob eine Bewegung zu den Einnahmen oder den Ausgaben zählt, entscheidet die **Art ihrer Kategorie**, nicht das Vorzeichen: Eine Erstattung ist eine negative Ausgabe und gehört unter die Ausgaben. Nur wo keine Kategorie steht, bleibt das Vorzeichen als einziger Anhaltspunkt. Aggregiert wird in PHP, nicht in SQL. Die Datenbank liefert die Bewegungen des Zeitraums, das Einsortieren in Zeilen und Spalten passiert in `Auswertung`. Bei Zehntausenden Buchungen ist das Millisekundensache, und Baumsummen über Kategorien, Vorzeichenregeln und Spaltenraster wären in SQL erheblich schwerer nachzulesen. ## Vorzeichen Intern gilt durchgehend die Buchhaltung: Ausgaben negativ. In der **Anzeige** dreht der Ausgabenabschnitt sein Vorzeichen – dort steht 636,39 statt −636,39, wie im FinanzManager; die Überschrift sagt ja bereits, worum es geht. Die Schlusszeile *Gesamt Einnahmen − Ausgaben* rechnet wieder mit den echten Werten. Zwei Ausnahmen führen das Vorzeichen mit, weil sie keine Abschnitte haben: der **Buchungsbericht** (eine Buchungsliste, kein Summenbericht) und der **Budgetbericht** (Vorzeichen wie im Budgetplaner). Der Drilldown zeigt ebenfalls die echten Vorzeichen. ## Die fünf Berichtstypen | Typ | Zeilen | Spalten | |---|---|---| | **Summenbericht** | Zeilen-Summe, nach Einnahmen und Ausgaben getrennt | Zeitraum, je nach Spalten-Aufteilung | | **Buchungsbericht** | Einzelbuchungen, gruppiert nach Zeilen-Summe | feste Buchungsspalten | | **Vergleichsbericht** | wie Summenbericht | Zeitraum, Vorjahreszeitraum, Differenz, Veränderung | | **Kontostandsbericht** | Konten | Salden zu den Enden der Spaltenzeiträume | | **Budgetbericht** | Kategoriebaum | Budget, Ist, Saldo | ### Summenbericht Bei der Zeilen-Summe *Kategorie* entsteht der eingerückte Baum: Jede Kategorie zeigt ihre **eigenen** Werte, Kategorien mit Nachfahren bekommen dahinter eine Zeile *Gesamt <Name>* mit der Summe des Astes. Eine Elternkategorie ohne eigene Buchungen steht deshalb als bloße Kopfzeile da – genau wie im Original. Der Schalter *mit Einrückung* schaltet auf eine flache Liste mit vollem Kategoriepfad um. Dort zählt jede Kategorie nur sich selbst, und es gibt keine Astsummen; sonst stünde eine Summe wie ein gleichrangiger Posten neben ihren eigenen Bestandteilen. Bei *Klasse*, *Konto* und *Empfänger* ist die Liste flach und alphabetisch. Die Aufteilung in Einnahmen und Ausgaben bleibt: Eine Klasse mit beidem erscheint in beiden Abschnitten. ### Vergleichsbericht Verglichen wird gegen **denselben Zeitraum ein Jahr früher**. Die Spalten-Aufteilung spielt hier keine Rolle – die Spalten gibt der Vergleich vor. Ohne Vorjahreswert bleibt die Prozentspalte leer: „unendlich viel mehr“ ist keine Aussage, die in eine Spalte gehört. Ein Monatsende bleibt beim Rückrechnen ein Monatsende, damit der 28.02. nicht auf einen 29.02. trifft und der Vergleichszeitraum einen Tag zu lang wird. ### Kontostandsbericht Anders als die übrigen Berichte zählt hier nicht die Bewegung im Zeitraum, sondern der **Stand**: alle Buchungen bis zum Stichtag, auch die vor dem Berichtszeitraum, und die Gegenseiten von Umbuchungen. Konten, die im ganzen Zeitraum auf null standen, fallen weg – dieselbe Regel wie in der Cockpit-Kachel. Die Summe zählt alle gezeigten Konten, unabhängig vom Σ-Kennzeichen der Kontenübersicht. Die Null wird hier ausgeschrieben: Ein Konto, das auf null steht, ist eine Aussage. ### Budgetbericht Gerechnet wird über die **vollen Monate**, die der Zeitraum berührt. Ein Budget ist ein Monatswert, und ein halber Monat hat kein halbes Budget; anders wären Budget und Ist nicht vergleichbar und die Saldospalte bedeutungslos. Der Berichtskopf nennt deshalb den Monatsbereich. Geht der Zeitraum über den Jahreswechsel, gilt je Jahr dessen eigenes aktives Budget (`Budget::aktivesFuerJahr()`). Vorzeichen und Saldo folgen dem Budgetplaner: Ausgaben negativ, Saldo ist `ist − budget`, positiv heißt besser als geplant. Übergeordnete Kategorien zeigen die Summe ihres Astes. ## Filterleiste | Feld | Wirkung | |---|---| | Zeitraum | Vorgabe oder *Benutzerdefiniert*; von/bis sind immer gefüllt und zeigen, was die Vorgabe gerade bedeutet | | Bericht anzeigen als | wechselt den Berichtstyp, ohne den übrigen Filter zu verlieren | | Zeilen-Summe | Kategorie, Klasse, Konto oder Empfänger | | Spalten-Aufteilung | Keine, Monat, Quartal, Jahr | | mit Einrückung | Kategoriebaum oder flache Liste mit Pfad | | Suche | Empfänger oder Buchungstext | | Einschränken | Konten, Kategorien, Klassen (Mehrfachauswahl) | Eine gewählte Kategorie **schließt ihre Unterkategorien ein** – wer „400 - Leben“ filtert, meint den ganzen Ast. Nichts ausgewählt heißt alles. Zwei Berichte bestimmen ihre Zeilen selbst und sperren das Feld: der Kontostandsbericht führt immer Konten, der Budgetbericht immer Kategorien. Zwei bestimmen ihre Spalten selbst: Vergleichs- und Budgetbericht. Die Filterleiste sendet per **GET**. Jeder Zwischenstand ist damit eine Adresse, die man sich merken, weitergeben und mit *Speichern unter* festhalten kann. ## Gespeicherte Berichte und Gruppen Ein gespeicherter Bericht ist Name, Typ und Filter – mehr nicht. Der Filter liegt als JSON in einer Spalte und wird beim Lesen immer durch `Auswertung::normalisiere()` geschickt: Was dort nicht vorgesehen ist, fällt weg. Ein alter Bericht kann nach einer Programmänderung höchstens eine Einstellung verlieren, aber nichts Unerwartetes in die Abfrage tragen. *Speichern unter* legt unter neuem Namen an und kann die Berichtsgruppe gleich mit anlegen – wer sie erst anderswo erzeugen müsste, verlöre den eingestellten Filter. *Speichern* überschreibt den geöffneten Bericht. **Berichtsgruppen** sind die Kacheln der Übersicht, wie „Bankgeschäfte“ oder „Steuern“ im Original. Wird eine Gruppe gelöscht, bleiben ihre Berichte erhalten und rücken unter *Nicht gruppiert*: Ein Bericht ist Arbeit, eine Gruppe nicht. Leere Gruppen bleiben in der Übersicht stehen. Sie sind angelegt worden, um befüllt zu werden, und ohne Kachel gäbe es keinen Ort, an den ein Bericht könnte. ## Drilldown Jeder Zeilenname und jede Zahl im Summen-, Vergleichs- und Budgetbericht ist ein Link auf die Buchungen dahinter. Eine Zahl schränkt zusätzlich auf ihre Spalte ein. Gefiltert wird nicht, indem die Zeile in einen neuen Filter übersetzt wird, sondern indem **dieselben Bewegungen nachgesiebt** werden, aus denen die Zelle entstanden ist. Nur so trifft der Drilldown auch das, was ein Filter gar nicht ausdrücken könnte: die Zeile *Nicht kategorisiert* etwa, oder eine Astsumme über mehrere Unterkategorien. ## CSV-Export Dieselben Zeilen, dieselben Zahlen, dieselben Vorzeichen wie am Bildschirm – wer den Export mit der Anzeige vergleicht, soll nicht rechnen müssen. Deutsches Tabellenkalkulations-CSV: Semikolon als Trenner, Komma als Dezimalzeichen, kein Tausenderpunkt (der machte aus der Zahl einen Text), CRLF als Zeilenende und ein vorangestelltes BOM – sonst zeigen Excel und LibreOffice beim Doppelklick „Übrige“ statt „Übrige“. Die Einrückung des Kategoriebaums steht als führende Leerzeichen im Namensfeld, sonst wäre die Hierarchie verloren. PDF gibt es bewusst nicht (siehe `PLAN.md`); Papier läuft über die Druckfunktion des Browsers. ## Dateien | Datei | Inhalt | |---|---| | `src/Services/Auswertung.php` | die Rechenmaschine: Bewegungen, die fünf Berichtstypen, Drilldown | | `src/Services/Zeitraum.php` | Zeitraumvorgaben und Spaltenraster, reine Kalenderrechnung ohne Datenbank | | `src/Services/BerichtExport.php` | CSV | | `src/Models/Bericht.php` | gespeicherte Berichte, Filter-JSON | | `src/Models/Berichtsgruppe.php` | Gruppen | | `src/Controllers/AuswertungenController.php` | Übersicht, Berichtsansicht, Drilldown, Export | | `src/Views/auswertungen/` | Übersicht, Filterleiste, ein Teiltemplate je Darstellung | | `migrations/005_berichte.sql` | `berichte`, `berichtsgruppen` | ## Tests * `tests/14_AuswertungTest.php` – Zeitraumvorgaben und Spaltenraster, Filterprüfung, alle fünf Berichtstypen, Astsummen, Splitbuchungen, Ausschluss der Umbuchungen, unkategorisierte Buchungen, Einschränkungen, Drilldown, CSV, gespeicherte Berichte * `tests/e2e/specs/auswertungen.spec.js` – Übersicht und Standardvorlagen, die fünf Tabellen, Spalten-Aufteilung, Drilldown und zurück, Speichern/Wiederfinden/Löschen, CSV-Download