Budgetplaner mit Monatswerten je Kategorie, Monatsabschluss mit Prüflauf, Snapshot und Buchungssperre. Dazu drei Vorarbeiten in der Oberfläche. Budgetplaner - Migration 004: budgets, budget_positionen, monatsabschluesse - Zeilen sind der Kategoriebaum, Spalten die Monate; die ganze Tabelle wird in einem Formular gespeichert, damit mehrere Änderungen zusammen ankommen - Zwei Ansichten: Verlauf (Jahressumme, abgelaufene Monate zusammengefasst, laufender Monat mit Budget/Ist/Saldo, danach Folgemonate) und alle Monate - Ausgaben ohne Vorzeichen eingeben, es kommt aus der Kategorieart. Saldo ist Ist minus Budget: positiv heißt besser als geplant, negativ ist die Überschreitung und wird rot ausgewiesen - Übergeordnete Kategorien summieren ihre Nachfahren und sind nicht beplanbar - Ein Monat ohne Position ist "nicht geplant" und damit etwas anderes als "mit 0,00 geplant" - Wert auf Folgemonate übertragen, Budget als Kopie ins neue Jahr Monatsabschluss - Prüflauf über nicht kategorisierte Buchungen, nicht abgeglichene Umsätze und Splitsummen-Differenzen; er hält niemanden auf, sondern zeigt den Stand - Snapshot der Kontosalden und Kategoriesummen als JSON, bleibt auch nach einer Wiedereröffnung stehen - Abgeschlossene Monate sperren Buchungen in beide Richtungen: weder hinein noch heraus verschieben. Abschaltbar über monatsabschluss_sperrt_buchungen Vorarbeiten - .knopf.primaer trug einen eigenen margin-top und stand dadurch in jeder Knopfleiste tiefer als seine Nachbarn - sichtbar an "Abbrechen" neben "Konto anlegen". Der Abstand liegt jetzt allein bei der Knopfleiste - Kontengruppen werden wie Konten und Kategorien auf einer eigenen Formularseite gepflegt statt inline; dort hängt auch die Zuordnung der Konten (ankreuzen statt jedes Konto einzeln zu öffnen) - Der QIF-Export enthält keine Kontengruppen: kein Feld im !Account-Eintrag, nichts in der QSD-Datei. Import-Oberfläche und Doku sagen das jetzt - Die Baum-Einrückung lief über ein style-Attribut und wurde von der Content-Security-Policy verworfen; sie steht jetzt als data-ebene im Markup. Aus demselben Grund blendete app.js Erfolgsmeldungen nie aus Tests: 11_BudgetTest, 12_MonatsabschlussTest (76 Prüfungen), E2E planung.spec.js. Einzelheiten in docs/planung.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
3.6 KiB
SQL
69 lines
3.6 KiB
SQL
-- Phase 3: Budgetplaner und Monatsabschluss.
|
||
--
|
||
-- Ein Budget gilt für genau ein Jahr; mehrere Budgets pro Jahr sind erlaubt
|
||
-- („2027-sparsam“ neben „2027-normal“), eines davon ist das aktive. Die Werte
|
||
-- stehen monatsweise je Kategorie – das entspricht dem Budgetplaner des
|
||
-- FinanzManagers, in dem jede Kategoriezeile zwölf Monatsspalten hat.
|
||
|
||
CREATE TABLE IF NOT EXISTS budgets (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
benutzer_id INT UNSIGNED NOT NULL,
|
||
name VARCHAR(120) NOT NULL,
|
||
jahr SMALLINT UNSIGNED NOT NULL,
|
||
beschreibung VARCHAR(255) NOT NULL DEFAULT '',
|
||
-- Genau ein Budget je Benutzer ist aktiv; es öffnet sich beim Aufruf des
|
||
-- Budgetplaners und liefert die Werte für Auswertungen (Phase 4).
|
||
aktiv TINYINT(1) NOT NULL DEFAULT 0,
|
||
erstellt_am DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
geaendert_am DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_budget_name (benutzer_id, name),
|
||
KEY idx_budget_jahr (benutzer_id, jahr),
|
||
CONSTRAINT fk_budget_benutzer FOREIGN KEY (benutzer_id)
|
||
REFERENCES benutzer (id) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- Eine Zeile je Kategorie und Monat. Nicht geplante Monate haben keine Zeile –
|
||
-- das hält die Tabelle klein und macht „kein Budget“ von „Budget 0,00“
|
||
-- unterscheidbar. Das Vorzeichen folgt der Buchhaltung: Ausgaben negativ,
|
||
-- Einnahmen positiv (Budget::positionSetzen dreht die Eingabe entsprechend).
|
||
CREATE TABLE IF NOT EXISTS budget_positionen (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
budget_id INT UNSIGNED NOT NULL,
|
||
kategorie_id INT UNSIGNED NOT NULL,
|
||
monat TINYINT UNSIGNED NOT NULL,
|
||
betrag DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_budget_position (budget_id, kategorie_id, monat),
|
||
KEY idx_position_kategorie (kategorie_id),
|
||
CONSTRAINT fk_position_budget FOREIGN KEY (budget_id)
|
||
REFERENCES budgets (id) ON DELETE CASCADE,
|
||
CONSTRAINT fk_position_kategorie FOREIGN KEY (kategorie_id)
|
||
REFERENCES kategorien (id) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- Ein abgeschlossener Monat sperrt Buchungen in seinem Zeitraum. Der Snapshot
|
||
-- hält Kontosalden und Kategoriesummen als JSON fest, damit später
|
||
-- nachvollziehbar bleibt, mit welchen Zahlen abgeschlossen wurde – auch wenn
|
||
-- der Monat wiedereröffnet und nachgebucht wird.
|
||
CREATE TABLE IF NOT EXISTS monatsabschluesse (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
benutzer_id INT UNSIGNED NOT NULL,
|
||
jahr SMALLINT UNSIGNED NOT NULL,
|
||
monat TINYINT UNSIGNED NOT NULL,
|
||
status VARCHAR(20) NOT NULL DEFAULT 'abgeschlossen',
|
||
notiz VARCHAR(255) NOT NULL DEFAULT '',
|
||
snapshot LONGTEXT NULL,
|
||
abgeschlossen_am DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
abgeschlossen_von VARCHAR(120) NOT NULL DEFAULT '',
|
||
wiedereroeffnet_am DATETIME NULL,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_monatsabschluss (benutzer_id, jahr, monat),
|
||
CONSTRAINT fk_abschluss_benutzer FOREIGN KEY (benutzer_id)
|
||
REFERENCES benutzer (id) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
INSERT INTO einstellungen (schluessel, wert, bereich) VALUES
|
||
('budget_alarm_ab_prozent', '100', 'buchhaltung'),
|
||
('monatsabschluss_sperrt_buchungen', '1', 'buchhaltung')
|
||
ON DUPLICATE KEY UPDATE schluessel = schluessel;
|