Damit ist der geplante Funktionsumfang beisammen. Phase 4 abgeschlossen - Konfigurierbare Cockpit-Kacheln; abgewählte werden nicht berechnet - Einnahmen/Ausgaben je Monat als Balkenpaare mit Saldolinie, aufgesetzt auf den Summenbericht statt auf eine eigene Abfrage - Meine Ausgaben als Ring auf der obersten Kategorieebene - Offene Vorgänge aus allen Modulen Phase 5 – Online-Banking - nemiah/php-fints als Fork auf Codeberg, psr/log direkt eingebaut: die Anwendung hängt an keinem fremden Update-Zyklus - PIN AES-256-GCM-verschlüsselt; Schlüssel aus APP_KEY oder aus data/schluessel/app_key, den der Entrypoint einmalig erzeugt - TAN-Dialog über mehrere Requests (FinTs::persist plus serialisierte Aktion in der Sitzung) – ein wartender Prozess wäre mit php-fpm der falsche Weg - Abgleich statt Direktbuchung: verbinden, übernehmen oder verwerfen - Regeln mit vier Vergleichsarten, Betragsgrenzen und Split-Schema Phase 6 – Wertpapiere - Depotbuchung und Geldbuchung als zwei Seiten eines Geschäfts; betrag ist der Bruttowert, Nebenkosten stehen daneben - Einstand nach gleitendem Durchschnitt, realisierte Gewinne, Erträge - Kursabruf über Leeway oder FMP, täglicher Lauf per Cron - QIF-Import für !Type:Invst Dabei behoben: Der Import buchte den Geldfluss jedes Wertpapiergeschäfts als Abgang – auch bei Verkäufen und Dividenden; und er erkannte das Verrechnungskonto nicht, wenn dem Konto im L-Feld eine Kategorie vorangeht (bei Verkäufen also immer). Phase 7 – Nebenmodule und Zahlungsverkehr - Buchungsvorlagen inklusive QIF-Import, Splits werden mitskaliert - Regelmäßige Buchungen mit Fälligkeitslauf, Finanzkalender, Erinnerungen - Adressen mit IBAN-Prüfung, Verträge mit Kündigungsfrist, Sparziele - Kredite mit gerechnetem Tilgungsplan - Überweisungen über FinTS; die Buchung entsteht erst nach Annahme durch die Bank. Die pain.001-Nachricht erzeugt SepaXml selbst Nebenbei: .dockerignore ergänzt (ohne sie brach der Build an data/mariadb ab), PlatzhalterController entfernt, zwei Inline-Handler beseitigt, die die Content-Security-Policy ohnehin blockierte. 888 PHP-Prüfungen und 45 E2E-Tests grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
125 lines
3.7 KiB
PHP
125 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Finanzmanager\Controllers;
|
|
|
|
use Finanzmanager\Models\Buchungsvorlage;
|
|
use Finanzmanager\Models\Kategorie;
|
|
use Finanzmanager\Models\Klasse;
|
|
use Finanzmanager\Models\Konto;
|
|
use Finanzmanager\View;
|
|
|
|
/**
|
|
* Buchungsvorlagen: suchen, buchen, pflegen.
|
|
*/
|
|
class VorlagenController extends BaseController
|
|
{
|
|
public function index(): void
|
|
{
|
|
$this->verlangeAnmeldung();
|
|
|
|
$suche = $this->query('suche');
|
|
|
|
$this->render('vorlagen/index.php', [
|
|
'titel' => 'Buchungsvorlagen',
|
|
'vorlagen' => Buchungsvorlage::alle($suche),
|
|
'suche' => $suche,
|
|
'anzahl' => Buchungsvorlage::anzahl(),
|
|
'konten' => Konto::alle(true),
|
|
'kategorien' => Kategorie::baumFlach(null, true),
|
|
'klassen' => Klasse::alle(),
|
|
]);
|
|
}
|
|
|
|
public function anlegen(): void
|
|
{
|
|
$this->verlangeAnmeldung();
|
|
|
|
try {
|
|
Buchungsvorlage::anlegen($this->formulardaten());
|
|
} catch (\Throwable $e) {
|
|
View::redirect('/vorlagen', $e->getMessage(), 'fehler');
|
|
return;
|
|
}
|
|
|
|
View::redirect('/vorlagen', 'Vorlage angelegt.');
|
|
}
|
|
|
|
/** @param array<string,string> $params */
|
|
public function speichern(array $params): void
|
|
{
|
|
$this->verlangeAnmeldung();
|
|
|
|
try {
|
|
Buchungsvorlage::speichern((int)$params['id'], $this->formulardaten());
|
|
} catch (\Throwable $e) {
|
|
View::redirect('/vorlagen', $e->getMessage(), 'fehler');
|
|
return;
|
|
}
|
|
|
|
View::redirect('/vorlagen', 'Vorlage gespeichert.');
|
|
}
|
|
|
|
/** @param array<string,string> $params */
|
|
public function loeschen(array $params): void
|
|
{
|
|
$this->verlangeAnmeldung();
|
|
|
|
Buchungsvorlage::loeschen((int)$params['id']);
|
|
|
|
View::redirect('/vorlagen', 'Vorlage gelöscht.');
|
|
}
|
|
|
|
/** @param array<string,string> $params */
|
|
public function buchen(array $params): void
|
|
{
|
|
$this->verlangeAnmeldung();
|
|
|
|
try {
|
|
$buchungId = Buchungsvorlage::buchen((int)$params['id'], [
|
|
'datum' => $this->post('datum') ?: date('Y-m-d'),
|
|
'betrag' => $this->post('betrag'),
|
|
'konto_id' => $this->post('konto_id'),
|
|
]);
|
|
} catch (\Throwable $e) {
|
|
View::redirect('/vorlagen', $e->getMessage(), 'fehler');
|
|
return;
|
|
}
|
|
|
|
View::redirect('/buchungen/' . $buchungId, 'Buchung aus der Vorlage angelegt.');
|
|
}
|
|
|
|
/** Aus einer vorhandenen Buchung eine Vorlage machen. */
|
|
public function ausBuchung(): void
|
|
{
|
|
$this->verlangeAnmeldung();
|
|
|
|
$buchungId = (int)$this->post('buchung_id');
|
|
|
|
try {
|
|
Buchungsvorlage::ausBuchung($buchungId, $this->post('name'));
|
|
} catch (\Throwable $e) {
|
|
View::redirect('/buchungen/' . $buchungId, $e->getMessage(), 'fehler');
|
|
return;
|
|
}
|
|
|
|
View::redirect('/buchungen/' . $buchungId, 'Vorlage aus dieser Buchung angelegt.');
|
|
}
|
|
|
|
/** @return array<string,mixed> */
|
|
private function formulardaten(): array
|
|
{
|
|
return [
|
|
'name' => $this->post('name'),
|
|
'konto_id' => $this->post('konto_id'),
|
|
'betrag' => str_replace(',', '.', $this->post('betrag')),
|
|
'empfaenger' => $this->post('empfaenger'),
|
|
'buchungstext' => $this->post('buchungstext'),
|
|
'nummer' => $this->post('nummer'),
|
|
'kategorie_id' => $this->post('kategorie_id'),
|
|
'klasse_id' => $this->post('klasse_id'),
|
|
'gegenkonto_id' => $this->post('gegenkonto_id'),
|
|
];
|
|
}
|
|
}
|