Finanzmanager/src/Controllers/BaseController.php
fds2610-bot 851e8204e9 Phase 3: Budgetplaner und Monatsabschluss
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>
2026-08-11 07:31:25 +02:00

58 lines
1.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Finanzmanager\Controllers;
use Finanzmanager\Auth;
use Finanzmanager\View;
abstract class BaseController
{
protected View $view;
public function __construct()
{
$this->view = new View();
}
/** Seiten hinter der Anmeldung rufen das zuerst auf. */
protected function verlangeAnmeldung(): void
{
Auth::verlange();
}
protected function render(string $template, array $daten = []): void
{
$daten['csrfToken'] = Auth::csrfToken();
$daten['benutzer'] = Auth::benutzer();
$this->view->render($template, $daten);
}
protected function post(string $feld, string $standard = ''): string
{
$wert = $_POST[$feld] ?? $standard;
return is_string($wert) ? trim($wert) : $standard;
}
/**
* Mehrfachauswahl aus dem Formular (Ankreuzfelder mit Namen wie „konten[]“).
*
* @return list<int>
*/
protected function postIds(string $feld): array
{
$werte = $_POST[$feld] ?? [];
if (!is_array($werte)) {
return [];
}
return array_values(array_map('intval', array_filter($werte, 'is_scalar')));
}
protected function query(string $feld, string $standard = ''): string
{
$wert = $_GET[$feld] ?? $standard;
return is_string($wert) ? trim($wert) : $standard;
}
}