Steuerkram/Changes.md

47 KiB
Raw Blame History

Changelog


2026-06-11 – Fix: Direktabruf springt nach Abschluss zurück zu „Bank buchen" (Issue #101)

  • src/Views/bank/fints.php: Nach erfolgreichem Direktabruf (FinTS) führt der „Schließen"-Button im Abruf-Log-Modal jetzt zu einem Redirect auf /bank ("Bank buchen"); bei Abbruch oder Fehler bleibt die Anzeige wie bisher auf /bank/direkt, damit der Abruf wiederholt werden kann

2026-06-08 – Fix: KI-Verbindungstest mit Diagnoseinformationen (Issue #55)

  • LlmService: Neue Methode testConnection() gibt detaillierte Diagnose zurück (cURL-Fehlernummer/-meldung, HTTP-Code, Antwortzeit, verfügbare Modelle)
  • LlmService: probeOllama() schreibt bei cURL-Fehlern jetzt einen Eintrag ins PHP-Fehlerlog (docker compose logs web)
  • Einstellungsseite: Neuer Button „Verbindung testen" im KI-Abschnitt; zeigt bei Erfolg verfügbare Modelle, bei Fehler cURL-Fehler, URL und Firewall-Hinweis an
  • Route: POST /settings/llm-test → SettingsController::llmTest()
  • BelegController: Bei Verbindungsfehler wird jetzt [] statt null gespeichert (verhindert endlose Auto-Retry-Schleife); Fehlermeldung differenziert zwischen „Ollama nicht erreichbar" und „kein Vorschlag generiert"
  • Beleg-Detailseite: Zeigt bei Verbindungsfehler spezifische Meldung „Ollama nicht erreichbar" mit Link zu den Einstellungen statt der generischen Warnung

2026-06-01 – Fix: EN16931-Validierungsfehler in ZUGFeRD-Rechnungen

  • [BR-FX-EN-04] behoben: ZugferdService setzt jetzt BT-72 (Liefer-/Leistungsdatum) via setDocumentSupplyChainEvent(); das Datum wird aus dem Feld leistungszeitraum geparst (Format DD.MM.YYYY → direkt; Format MM.YYYY → letzter Tag des Monats; sonst Fallback auf Rechnungsdatum)
  • [PEPPOL-EN16931-R008] behoben: Leere Strings in optionalen Adressfeldern (Straße, PLZ, Ort) werden als null übergeben, sodass keine leeren XML-Elemente entstehen

2026-05-28 – Feature: Buchungsvorlagen im Buchungsdialog

  • Datenbank: 3 neue Tabellen buchungsvorlagen, buchungsvorlage_felder, buchungsvorlage_regeln (Migrationen 078–080); initiale Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" per Migration 080 eingespielt
  • Buchungsdialog (/belege/{id}): Neues Vorlagen-Badge (gelb) zwischen Bank-Badge und Buchungsformular; Auswahlbox mit aktiven Vorlagen; Vorlage auswählen öffnet modalen Dialog mit Felder-Gruppen und Live-USt-Berechnung
  • Modal: Feldgruppe 1 (Metadaten: Lieferant, Rechnungsnr., Belegdatum, Brutto-Anzeige), Feldgruppe 2 (USt-Zeilen mit Netto↔Brutto-Live-Berechnung), Feldgruppe 3 (Zahlungskonto; 1200 vorausgewählt wenn Bankbuchung, sonst 1210)
  • Buchungslogik: VorlageBuchungsService interpretiert JSON-Buchungsregeln und ruft Booking::create() direkt auf (keine automatischen Kindzeilen, da Konten explizit); Metafelder werden über Beleg::updateMeta() gespeichert
  • Pflege-UI: /einstellungen/buchungsvorlagen – CRUD-Oberfläche für Vorlagen, Felder und Buchungsregeln; Navigationslink unter Einstellungen
  • Test 42: 42_BuchungsvorlageTest.php prüft CRUD, Buchungsausführung, korrekte Konten und neq_zero-Bedingung

2026-05-24 – Fix: EÜR-Zeilennummern auf amtliche Anlage EÜR 2025 korrigiert

  • migrations/075_euer_zeilen_korrektur.sql: alle euer_zeile-Werte in accounts gemäß amtlicher Anlage EÜR 2025 neu zugeordnet (zuvor internes Schema ohne Bezug zum amtlichen Formular)
  • EuerCalculator.php: Sonderbehandlung für nicht abziehbare BA von euer_zeile='51' auf '74' umgestellt (Zeile 74 = „Nicht abziehbare Beträge" der amtlichen Anlage EÜR)
  • accounts/form.php: $euerZeilen-Array vollständig durch amtliche Zeilen 12–72 und 74 ersetzt; alle Beschriftungen entsprechen exakt dem Formulartext der Anlage EÜR 2025

2026-05-24 – Feature: EÜR Anlageliste CSV/PDF-Export

  • EÜR-Ansicht: Kopfzeile der Anlageliste-Karte enthält jetzt rechtsbündig „Herunterladen: [CSV] [PDF]"
  • CSV-Export: GET /tax/euer/{year}/anlageliste/csv – alle 9 Spalten mit UTF-8 BOM (Excel-kompatibel), Semikolon-getrennt, inkl. Summenzeile
  • PDF-Export: GET /tax/euer/{year}/anlageliste/pdf – A4 Querformat, enge Spaltenbreiten sodass alle 9 Spalten auf eine Seite passen; neuer PdfAnlagelisteService
  • EÜR-Karte: heller „PDF herunterladen"-Button entfernt; Topbar-Button umbenannt zu „PDF"

2026-05-24 – Feature: AFA-Buchung stornieren/löschen in AfA-Tabelle

  • AfA-Tabelle im Asset-Edit-Modal: Gebuchte Zeilen zeigen neben dem grünen Haken einen Storno-Button (Undo-Pfeil, alle Modi) und im Testmodus zusätzlich einen Papierkorb-Button
  • Storno legt eine Gegenbuchung (buchungstyp=AfA, is_reversal=1, negativer Betrag) an und setzt afa_booking_id auf NULL → der Pfeil-aus-Box-Button erscheint wieder
  • Löschen (Testmodus) löscht die AFA-Buchung direkt und setzt afa_booking_id auf NULL
  • Neuer Controller: POST /assets/{id}/depreciation/{rowId}/reverse und …/delete
  • AssetDepreciation::setBookingId() akzeptiert jetzt ?int (null erlaubt)

2026-05-24 – Feature: Buchungsjournal-Filter Buchungstyp + EÜR-Anlageliste

  • Buchungsjournal: neues Filterfeld „Buchungstyp" (Einnahme / Ausgabe / AfA); vorbelegt mit „Alle Typen"
  • Buchungsjournal: AfA-Buchungen (ohne Beleg) werden jetzt korrekt angezeigt (LEFT JOIN belege); Beleg-Zelle zeigt „–" wenn kein Beleg
  • Buchungsjournal: Badge für Buchungstyp AfA in grau (badge-gray)
  • EÜR-Ansicht: neue Tabelle „Anlagegüter {Jahr}" unterhalb der EÜR mit Spalten Anlage-ID, Bezeichnung, Anschaffungsdatum, Anschaffungskosten, Nutzungsdauer, AfA Vorjahre (kumulierte gebuchte AfA-Buchungen), Restbuchwert Vorjahr, AfA {Jahr} (gebuchte AfA des Jahres), Restbuchwert 31.12.{Jahr}; Summenzeile am Ende
  • Asset::anlageliste(int $year) als neue Modell-Methode (single query mit Subqueries)

2026-05-24 – Feature: AfA-Tabelle anteilig nach Anschaffungsmonat

  • Das erste Abschreibungsjahr wird anteilig nach Restmonaten berechnet: der Anschaffungsmonat zählt voll (Januar = 12 Monate, April = 9 Monate usw.)
  • Das letzte Jahr erhält automatisch die verbleibenden Monate (12 − Monate des ersten Jahres); bei Januar-Kauf entfällt das extra letzte Jahr
  • Die Cent-Option (cent_im_ersten_jahr) bleibt davon unberührt: der Cent-Rest geht weiterhin vollständig ins erste Jahr, ohne Aufteilung auf das letzte Jahr
  • Sofortabschreibung (nutzungsdauer = 0) ist unverändert
  • Neuer Test 41_AfaAnteiligTest prüft April-, Oktober-, Juli-, Dezember- und Januar-Käufe sowie die Cent-Option mit anteiligem Jahr

2026-05-22 – Feature: „Abrufen ab"-Auswahl für Direktverbindungen

  • Im Bearbeiten-Dialog jeder FinTS- bzw. API-Direktverbindung gibt es ein neues Dropdown Abrufen ab mit den Optionen Ab letztem Abruf (00:00 Uhr) (Default), Letzte 7 Tage, Aktueller Monat (ab 01.), Letzte 30 Tage, Ohne Datum (letzte 365 Tage)
  • Die Auswahl gilt nur für den nächsten Abruf: nach erfolgreichem Lauf setzt BankSource::updateLastFetched() fetch_range wieder auf 'last_fetched' zurück
  • Migration 072_bank_sources_fetch_range.sql ergänzt die neue ENUM-Spalte (Default 'last_fetched', bestehende Verbindungen verhalten sich unverändert)
  • Logik in BankSource::computeStartDate() zentralisiert; FinTsFetchService und PayPalNvpFetchService nutzen sie. Neuer Test 39_BankFetchRangeTest deckt alle fünf Range-Werte plus Fallbacks ab

2026-05-22 – Fix: FinTS-Konto-Auswahl wird jetzt gespeichert + Bearbeiten-Dialog mit Checkboxen

  • Bug: Beim ersten Abruf erschien das Konto-Auswahl-Modal, das Speichern blieb aber hängen. Ursache war PHP-Session-Locking: der SSE-Stream /bank/direkt/{id}/run hielt die Session-Datei während des awaitAccountSelection()-Polling-Loops gesperrt, der parallele POST /bank/direkt/{id}/accounts blockierte beim session_start() → Deadlock bis Timeout
  • Fix: Im SSE-Endpoint session_write_close() direkt nach dem Auth-Check; entstört zugleich die analog gelagerte TAN-Eingabe
  • UI: Im Bearbeiten-Dialog einer FinTS-Verbindung erscheinen die gespeicherten Konten jetzt als Checkbox-Liste (statt nur als Text). Abhaken entfernt den Identifier beim Speichern aus account_filter; alle abgehakt verhält sich wie der Reset-Toggle
  • Filter-Berechnung als BankSource::computeFilterFromPost() extrahiert, neuer Test 38_BankSourceFilterFromPostTest deckt Reset, Teilauswahl, leere Auswahl und Schutz gegen Unterschieben fremder Identifier ab

2026-05-22 – Feature: APP_KEY Status & Generator in den Einstellungen

  • Neuer Settings-Bereich unter dem Betriebsmodus zeigt Status des Verschlüsselungsschlüssels (APP_KEY): Gesetzt (grün, 64 Hex-Zeichen valide), Ungültig (falsches Format) oder Fehlt (leer)
  • Bei fehlendem oder ungültigem Schlüssel: Button „Neuen Schlüssel generieren" → POST /settings/generate-app-key liefert bin2hex(random_bytes(32)), Anzeige im Code-Block mit Copy-Button
  • Schlüssel wird nicht persistiert (Container hat keinen Schreibzugriff auf .env); Anleitung im UI: kopieren → in .env eintragen → docker compose restart web

2026-05-22 – UI: Einheitliche Icon-Buttons für Bearbeiten/Ansehen/Löschen

  • Bleistift-Icon (transparent, ohne Hintergrund – Stil der Direktverbindungs-Kacheln) ersetzt alle „Bearbeiten"- und „Öffnen"-Buttons in accounts/list, customers/show, customers/list, suppliers/list, useradmin/list, assets/list, belege/list, invoices/list, invoices/show
  • Auge-Icon (Kästchen mit Auge) ersetzt die PDF-Buttons in invoices/list (PDF), invoices/show (PDF herunterladen) sowie den „Ansehen"-Button in tax/ustva_index, um „nur ansehen" visuell vom „bearbeiten" abzugrenzen
  • Papierkorb-Icon (transparent, Danger-Farbe) ersetzt alle „Löschen"-Buttons in accounts/list, invoices/list, useradmin/list, suppliers/list, assets/list, belege/detail, settings/bankimport, bank/fints und settings/form
  • Plus-Icon (rund, btn-primary, 1,8rem) ersetzt alle „Neu anlegen/erstellen/hochladen"-Buttons – Topbars (bank/fints, Kunden, Lieferanten, Rechnungen, Belege, Wirtschaftsgüter, Konten), Dashboard-Schnellzugriff, Card-Header in customers/show, Aktionsspalte in customers/list und „Position hinzufügen" im Rechnungsformular
  • bank/index.php: Button „Öffnen" → „Aktivieren" (Status-Toggle, semantisch eindeutiger)

2026-05-21 – Feature: FinTS-Direktverbindung + Vereinheitlichung der Bank-Importquellen

  • FinTS-Abruf für Comdirect, DKB und weitere Banken über nemiah/php-fints (PHP-Lib für HBCI/FinTS 3.0). Leseabruf mit PIN; TAN-pflichtige Aktionen werden mit klarer Fehlermeldung abgebrochen
  • Verschlüsselung sensibler Felder: Neuer Crypto-Service (AES-256-GCM, Magic-Prefix enc:v1:) verschlüsselt PayPal-Signature und FinTS-PIN. Schlüssel aus APP_KEY in .env – im Backup mitsichern, Verlust = Verlust aller verschlüsselten Werte
  • Datenmodell-Fusion: Neue Tabelle bank_sources ersetzt bank_import_formats + bank_connections mit type-Spalte (csv/api/fints). bank_import_batches.source_id löst format_id/connection_id ab (alte Spalten bleiben vorerst bestehen für rollback-Sicherheit)
  • Route-Umbenennung: /bank/fints* → /bank/direkt* (semantisch korrekt – PayPal ist keine FinTS-Verbindung). Topbar in /bank vereinheitlicht zu einer „Importieren"-Schaltfläche
  • NEU/Edit-Modal zeigt typabhängig API-Felder (PayPal: App-Name, Kennwort, Signature, Sandbox) oder FinTS-Felder (BLZ, Benutzerkennung, PIN, optional FinTS-URL und IBAN-Filter)
  • FinTsFetchService: Login → SEPA-Konten abrufen → Statements seit last_fetched_at (00:00) → Buchungen mit Hash-basierter external_id (IBAN+Datum+Betrag+Verwendungszweck) deduplizieren
  • Migrationen 068 (bank_sources + Backfill), 069 (default_fints_url auf bank_providers für Comdirect/DKB)
  • scripts/encrypt_bank_secrets.php – einmaliges idempotentes Verschlüsseln der Klartext-Werte nach Backfill
  • Neue Tests 36 (Crypto-Roundtrip) und 37 (BankSource CRUD über alle drei Typen)

2026-05-17 – Feature: Automatischer Format-Vorschlag beim Bank-Import

  • Format-Vorschlag: Wenn eine hochgeladene CSV keinem bekannten Format eindeutig entspricht, analysiert BankImportParser::suggestFormat() die Datei automatisch (Headerzeilen-Erkennung bei skip_rows 0–10, Delimiter-Erkennung, Keyword-basiertes Spalten-Mapping)
  • Session-gestützter Vorschlags-Flow: Klick auf „Formate bearbeiten" speichert den Vorschlag via AJAX in der Session und öffnet die Einstellungsseite
  • Vorschlags-Card: Auf /settings/bankimport erscheint der Vorschlag oberhalb bestehender Formate als ausfüllbares Formular mit vorausgefüllten Feldern (skip_rows, Delimiter, Spalten-Mapping mit erkannten Headernamen)
  • Explizites Speichern: Neues Format wird erst nach Klick auf „Speichern" in der DB angelegt (POST /settings/bankimport/create); Verwerfen löscht die Session-Suggestion
  • Neue Routen: POST /settings/bankimport/suggest, POST /settings/bankimport/create, POST /settings/bankimport/dismiss-suggestion
  • Neues Model: BankImportFormat::create(); neuer Test 35

2026-05-17 – Feature: Automatische Format-Erkennung beim Bank-Import

  • Format-Erkennung: Hochgeladene Datei wird automatisch gegen alle gespeicherten Formate geprüft; bei eindeutigem Match wird sofort importiert
  • Vorschau-Panel: Wenn kein Format passt, zeigt die Upload-Seite Überschriften-Zeile, erste Werte-Zeile und die Spalten-Zuordnung (Wertstellung, Buchungstext, Wert) für das gewählte Format an; wechselt live beim Umschalten der Formatauswahl
  • „Formate bearbeiten"-Button oben rechts verlinkt direkt auf die Einstellungsseite für Bankimport-Formate
  • Neuer AJAX-Endpunkt POST /bank/detect-format in BankController; neue Methoden peekRows() und isFormatMatch() in BankImportParser

2026-05-17 – Feature: DKB-Importformat für Bankbuchungen

  • Neues Format „DKB Bank": 4 Skip-Zeilen, Semikolon-getrennt, Anführungszeichen-eingeschlossen
  • Buchungstext wird konditionell zusammengesetzt: bei negativem Betrag aus Zahlungsempfänger + Verwendungszweck, sonst aus Zahlungspflichtiger + Verwendungszweck
  • Migration 054 ergänzt drei neue Nullable-Spalten in bank_import_formats (col_zahlungspflichtiger, col_zahlungsempfaenger, col_verwendungszweck)

2026-05-16 – Refactor: Code-Qualität, Sicherheit und Konsistenz

  • CSRF-Schutz: Auth::generateCsrfToken() / validateCsrfToken() neu; Router validiert Token bei allen POST/PUT/DELETE-Requests; base.php injiziert Token in Formulare und fetch-Aufrufe via JS; login.php erhält hidden Input
  • Path Traversal in BelegController::serveFile() abgesichert (realpath() + Prefix-Check gegen Upload-Basisverzeichnis)
  • mime_content_type() (deprecated) durch finfo_file(finfo_open(FILEINFO_MIME_TYPE), ...) in BelegController, SettingsController, BankController und ImageCropService ersetzt
  • XSS in topbarActions: View::buildQuery() (neuer Helper) statt rohem http_build_query($_GET)
  • @-Unterdrückung in SettingsController entfernt (ersetzt durch file_exists()-Prüfung)
  • BaseController: gemeinsame renderView()-Methode zentralisiert; alle 13 Controller erben davon; lokale Duplikate entfernt
  • DB-Transaktionen: Booking::create() und Booking::reverse() laufen jetzt in atomaren Transaktionen; Database::beginTransaction/commit/rollBack unterstützt verschachtelte Aufrufe via Tiefenzähler (TestCase-Isolation bleibt intakt)
  • src/Constants.php: Buchungstypen und Steuerkontonummern (SKR03) als benannte Konstanten; Magic Strings in Booking.php ersetzt
  • Dokumentation: docs/funktionen.md – Abschnitt „Bank buchen" ergänzt; UStVA-Kennzahlen (81, 89, 66, 61, 83) korrigiert; Eigenanteil-Konten (4920/4925) korrigiert
  • Tests: 32_BankTransactionTest (linkBeleg, unlinkBeleg, recalcStatus, findDuplicates) und 33_BankImportParserTest (CSV-Parsing, BOM, Tausendertrenner, Fehlerfall) neu

2026-05-15 – Feature: Bankbuchung auf mehrere Belege aufteilen

  • Migration 053: Junction-Tabelle bank_transaction_belege (bank_tx_id, beleg_id, betrag); bank_transactions.beleg_id entfernt; Status-ENUM um teilweise erweitert; bestehende Verknüpfungen automatisch migriert
  • Neuer Status teilweise: wird gesetzt wenn mind. ein Beleg verknüpft ist, aber noch Restbetrag offen bleibt
  • Standardfilter in der Bankübersicht zeigt jetzt „Offen & Teilweise"
  • bank/show.php: Sektion „Verknüpfte Belege" mit Betrag je Beleg und Entfernen-Button; Restsaldo-Anzeige; Betrag-Eingabefeld pro Beleg in der Offene-Belege-Liste
  • Beim Verknüpfen wird der zugeordnete Betrag an die Buchungsmaske weitergegeben (alloc_betrag)
  • BankTransaction::linkBeleg() schreibt jetzt in Junction-Tabelle mit Betrag; recalcStatus() setzt Status automatisch; unlinkBeleg() entfernt Verknüpfung; getLinkedBelege() / getRemainingBetrag() neu
  • Neue Route POST /bank/{id}/unlink

2026-05-15 – Feature: Dublettenprüfung beim Bank-Import

  • Nach dem Upload wird geprüft, welche Buchungen bereits in der DB vorhanden sind (Abgleich über Buchungstag, Wertstellung, Betrag, Buchungstext)
  • Werden Dubletten gefunden, erscheint eine Prüfseite mit zwei Tabellen: erkannte Dubletten (per Checkbox auswählbar) und neue Buchungen (werden immer importiert)
  • „Alle auswählen / abwählen"-Buttons + Gesamtzähler zeigen an, wie viele Buchungen importiert werden
  • Erst nach Bestätigung wird importiert; ohne Auswahl wird der Import übersprungen
  • Migration 052: UNIQUE-Constraint auf bank_transactions entfernt (UI-Prüfung ist die primäre Schutzschicht)
  • BankTransaction::findDuplicates(): neue Methode mit Batch-Abfrage gegen die DB
  • BankController::doImport(): gemeinsame Import-Logik extrahiert (wird von upload() und uploadConfirm() genutzt)

2026-05-15 – Fix: Bank-Import-Duplikate verhindern

  • Migration 051: UNIQUE-Constraint (buchungstag, wertstellung, wert, buchungstext(200)) auf bank_transactions; bestehende Duplikate wurden dabei bereinigt
  • BankController::upload(): Import läuft jetzt in einer DB-Transaktion – bei Fehler wird alles zurückgerollt statt einen unvollständigen Batch zu hinterlassen
  • BankController::upload(): Dateiname-Prüfung vor dem Import – erneuter Upload derselben Datei wird mit Fehlermeldung abgelehnt
  • BankTransaction::filenameExists(): neue Hilfsmethode zur Duplikat-Prüfung anhand Dateiname

2026-05-15 – Fix: Netto-Neuberechnung bei Kategorie-Wechsel in Bank-Buchungsmaske

  • IIFE-Wrapper für updateAutoUst in einen DOMContentLoaded-Listener verschoben, damit er erst nach der Funktionsdefinition (späteres <script>-Tag) gesetzt wird und nicht sofort von ihr überschrieben wird.

2026-05-14 – Feature: Bank buchen

  • Navigation: neuer Eintrag „Bank buchen" unter Belege & Buchungen
  • Migration 049: Tabellen bank_import_formats, bank_import_batches, bank_transactions; Comdirect-Format als erster Eintrag
  • BankImportParser: Parst CSV/TXT (quoted, Semikolon-getrennt) und XLSX (via ZipArchive/SimpleXML, kein Composer-Paket)
  • Liste /bank: Suche + Filter (Jahr, Monat, Einnahme/Ausgabe, Status); Standard-Filter: offen; Einnahmen grün, Ausgaben rot
  • Upload /bank/upload: Drag-&-Drop-Zone für CSV/TXT/XLSX + Format-Auswahl
  • Detail /bank/{id}: Bank-Zeile oben; Beleg-Upload; Liste offener Belege zum Verknüpfen
  • Status-Aktionen: „Ignorieren" / „Wieder öffnen"; Verknüpfen eines Belegs setzt Status auf „gebucht"

2026-05-14 – Feature: UStVA Kz 83 = ust81 + ust89 − Kz66 − Kz61

  • UstvaCalculator: Kz 83 wird nun als ust81 + ust89 − Kz66 − Kz61 berechnet (nicht mehr kontobasiert via ustva_kz='83')
  • Test 29: angepasst (7%-Buchung auf korrektes Konto 8300; delta83-Erwartung aktualisiert)

2026-05-14 – Feature: UStVA Kz 61 aus ust89 abgeleitet (ReverseCharge-Symmetrie)

  • UstvaCalculator: Kz 61 = ust89 (nicht mehr kontobasiert via Konto 1574) – fachlich korrekt, da VSt ig. Erwerb = USt ig. Erwerb
  • Booking::reverse(): Hauptstornobuchung überträgt jetzt steuerart der Originalbuchung (fehlte bisher, wurde durch Kz-61-Kontoberechnung kaschiert)

2026-05-14 – Feature: UStVA Kz 81/89 auf volle Euro abgerundet

  • UstvaCalculator: Kz 81 und 89 werden mit floor() auf volle Euro abgerundet; USt wird auf dem gerundeten Wert berechnet
  • Darstellung: Kz 81/89 zeigen "1.234,- €" statt "1.234,00 €" (in Tabelle und Zusammenfassung)
  • USt-Felder (ust81, ust89) bleiben als Dezimalzahl unverändert
  • Test 31: prüft floor-Verhalten für Kz 81 und 89

2026-05-14 – Refactor: UStVA auf 5-Kennzahlen-Schema vereinfacht

  • Migration 048: Kontenrahmen bereinigt – nur noch ustva_kz ∈ {81, 83, 61, 66} aktiv; 1571/1576 → 66, 1574 → 61, 1771/1774 → 83, alle anderen auf NULL
  • UstvaCalculator: Nur noch Kz 81, 89, 66, 61, 83 + zwei Anzeigefelder (ust81, ust89 = Kz × 0,19, kein XML)
  • Kz 83 ist jetzt „Vorauszahlung / Überschuss" = (USt-Konten) − Kz 66 − Kz 61
  • ElsterXmlService: Export nur Kz 81/89 (ganzzahlig) + 66/61/83 (2 Dez); Kz 83 nur bei positivem Wert
  • View ustva_show.php: Neue Sektionsgliederung, Zusammenfassungsbox aktualisiert
  • Tests 5, 7, 13, 18, 28, 29, 30 auf neues Schema angepasst

2026-05-10 – Feature: ig. Erwerb 19 % ReverseCharge über Kindzeilen

  • Migration 047: ustva_kz='91' für Konto 1774; Kindzeilen (1574/1774) für bestehende ig_erwerb_19-Buchungen
  • Booking::create(): steuerart=ig_erwerb_19 erzeugt zwei Kindzeilen – VSt auf 1574 (Kz 67), USt auf 1774 (Kz 91)
  • UstvaCalculator: Kz 67/91 jetzt kontobasiert via 1574/1774; Kz 93/94 (ig_erwerb_7) entfernt
  • Buchungsformular: Option „ig. Erwerb 7 %" entfernt
  • Test 7 auf neue Logik angepasst; Test 30 neu

2026-05-10 – Feature: USt-Buchungszeilen für Ausgangsrechnungen

  • Migration 046: Konten 1771 (USt 7 %) und 1776 (USt 19 %) erhalten ustva_kz='84'/'83'`; bestehende Einnahme-Buchungen mit USt erhalten nachträglich USt-Kindzeilen
  • Booking::create(): Bei Einnahme-Buchungen mit 7/19 % und steuerart=normal wird analog zur VSt-Kindzeile eine USt-Zeile auf 1771/1776 angelegt
  • UstvaCalculator: Kz 83/84 jetzt kontobasiert via 1771/1776 (betrag_netto), nicht mehr via betrag_ust der Erlöskonten; KZ_ACCOUNT_MAP aktualisiert
  • Invoice::cancel(): Nur Hauptbuchungen (parent_booking_id IS NULL) werden direkt storniert; Kindzeilen werden von Booking::reverse() mitaufgehoben (verhindert Doppelstorno)
  • Tests 10 und 27 an geänderte Buchungsstruktur angepasst; Test 29 neu

2026-05-05 – Feature: Stornorechnung (§ 14 UStG)

Hinzugefügt

  • migrations/042_invoice_storno_of_id.sql: Neue Spalte storno_of_id in invoices (FK auf Original)
  • Invoice::createCancellation(): Legt Stornorechnung mit negierten Beträgen an, setzt Original auf „Storniert", erzeugt GoBD-konforme Stornobuchungen
  • Storno-Button in Rechnungsübersicht (list.php) und Detailansicht (show.php)
  • Querverweise Original ↔ Stornorechnung in der Detailansicht
  • PDF-Anpassung: Titel „STORNORECHNUNG", Referenzzeile, kein Zahlungshinweis, angepasster Dateiname
  • Test 27_StornorechnungTest.php

2026-04-28 – Feature: E-Rechnung / ZUGFeRD EN16931

Hinzugefügt

  • src/Services/ZugferdService.php: Erzeugt ZUGFeRD-konformes EN16931-XML und bettet es in den PDF-String ein (via horstoeko/zugferd)
  • src/Services/PdfInvoiceService.php: PDF wird nach der mPDF-Generierung durch ZugferdService::attachToPdf() geleitet; Ausgabe erfolgt jetzt manuell per Header/echo statt mpdf->Output('D')
  • Alle Ausgangsrechnungs-PDFs sind ab sofort gültige E-Rechnungen (ZUGFeRD EN16931 / Factur-X)

2026-04-27 – Feature: Neues Rechnungsnummernformat (PPPYYYYMM-nn)

Geändert

  • src/Models/Invoice.php: generateRechnungsNr() erzeugt jetzt das Format PPPYYYYMM-nn (Prefix + Jahr + Monat + zweistellige Sequenz, die bei Bedarf wächst); Zähler wird monatlich zurückgesetzt
  • migrations/038_invoice_nr_month.sql: Neue Spalte invoice_nr_month in company_settings

2026-04-26 – Fix: Eigenanteil-Buchung als Einnahme statt Ausgabe

Geändert

  • src/Models/Booking.php: upsertKorrekturbuchung() setzt buchungstyp jetzt korrekt auf Einnahme (war fälschlich Ausgabe)

2026-04-26 – Feature #57: Lineare Abschreibungstabelle für Anlagegüter

Hinzugefügt

  • migrations/035_assets_abschreibung_flags.sql: Neue Spalten automatisch_berechnet und cent_im_ersten_jahr in assets
  • migrations/036_asset_depreciation_schedule.sql: Neue Tabelle asset_depreciation_schedule (Jahr, Abschreibungsbetrag, Restwert)
  • src/Models/AssetDepreciation.php: Berechnung (linear, Sofortabschreibung, Cent-Option), Persistenz
  • tests/26_AbschreibungstabelleTest.php: 22 Tests für alle AfA-Szenarien

Geändert

  • src/Models/Asset.php: create() und update() speichern automatisch_berechnet und cent_im_ersten_jahr
  • src/Controllers/AssetController.php: Abschreibungstabelle wird nach Speichern automatisch generiert; neue Endpunkte /assets/depreciation-preview (AJAX-Vorschau) und /assets/{id}/depreciation (manuelle Speicherung)
  • src/Views/assets/form.php: Nutzungsdauer-Dropdown (sofort, 1–10, 12, 13, 15, 20, 25, 50 Jahre + individuell), Cent-Option, „AfA-Tabelle"-Button, Modal mit Auto/Manuell-Toggle und editierbarer Tabelle
  • public/index.php: Neue Routen für Depreciation-Preview und -Speicherung

2026-04-26 – KI-Diagnose: Erreichbarkeitsprüfung und Fehlerlog für Ollama

Geändert

  • src/Services/LlmService.php: Neue Methode isReachable() für Diagnosezwecke; Fehlerlog in callOllama() bei cURL-Fehler oder leerer Antwort
  • src/Views/settings/form.php: Einstellungsseite prüft jetzt aktiv, ob der Ollama-Server erreichbar ist (nicht nur ob er konfiguriert ist); zeigt bei Verbindungsfehler einen konkreten Hinweis auf OLLAMA_HOST=0.0.0.0:11434

2026-04-26 – Leistungszeitraum als freies Textfeld

Geändert

  • migrations/034_leistungszeitraum_text.sql: Spalten leistungszeitraum_von (DATE) und leistungszeitraum_bis (DATE) wurden durch eine einzige Textspalte leistungszeitraum (VARCHAR 255) ersetzt; bestehende Datumswerte werden automatisch migriert
  • src/Views/invoices/form.php: Zwei Datumsfelder durch ein Freitextfeld „Leistungszeitraum" ersetzt, Grid von 4 auf 3 Spalten angepasst
  • src/Models/Invoice.php: INSERT/UPDATE verwenden jetzt leistungszeitraum statt leistungszeitraum_von/leistungszeitraum_bis
  • src/Controllers/InvoiceController.php: Datums-Defaults für leistungszeitraum_von/leistungszeitraum_bis entfernt
  • src/Views/invoices/show.php: Leistungszeitraum-Anzeige vereinfacht (kein Datumsformat, direkter Textausgabe)
  • src/Services/PdfInvoiceService.php: Leistungszeitraum-Ausgabe vereinfacht

2026-04-15 – KI-Erkennung: automatischer Aufruf aus Belegansicht entfernt

Geändert

  • src/Views/belege/detail.php: KI-Analyse wird nicht mehr automatisch beim Öffnen eines Belegs ausgelöst; stattdessen wird ein Hinweis "KI-Analyse wird im Hintergrund durchgeführt …" mit einem "Jetzt generieren"-Button angezeigt, wenn noch kein Vorschlag vorhanden ist
  • Hintergrund: Die Analyse läuft bereits beim Nextcloud-Import (ki-batch.php); ein doppelter Aufruf aus der UI war überflüssig

2026-04-12 – Anlagevermögen: Anzeige-Fix und Daten-Backfill

Fix

  • Buchungstabellen (Beleg-Detail, Journal, UStVA-Drill-down, EÜR-Drill-down): Anlage-Spalte zeigt jetzt auch die Bezeichnung als Fallback, wenn anlage_nr leer ist
  • migrations/032_anlage_nr_backfill.sql: Anlage-Nummern für bestehende Anlagegüter ohne anlage_nr werden nachgeneriert

2026-04-12 – Anlagevermögen (Wirtschaftsgüter)

Neu

  • Navigation: neuer Abschnitt „Betriebsvermögen" mit Menüpunkt „Anlagevermögen"
  • migrations/028_assets_anlagevermoegen.sql: neue Tabelle assets für Wirtschaftsgüter
  • src/Models/Asset.php: CRUD-Model mit automatischer laufender Nummer und Geschäftsjahrzuordnung
  • src/Controllers/AssetController.php: Liste, Anlegen, Bearbeiten, Löschen
  • src/Views/assets/list.php: Anlagenspiegel-Tabelle mit Bleistift- und Papierkorb-Aktionen
  • src/Views/assets/form.php: Formular für Wirtschaftsgut (Bezeichnung, Anschaffungsdatum, Kosten, Zugänge, Abgänge, AfA, Nutzungsdauer, Notizen)
  • tests/20_AnlagevermoegensTest.php: 14 Tests für CRUD-Operationen

2026-04-12 – EÜR-Korrekturen: Gewerbesteuer + Bewirtungskonten ohne VSt

Geändert

  • migrations/028_euer_4320_bewirtung_ohne_vst.sql: Gewerbesteuer (4320) von Z. 52 auf Z. 51 (§ 4 Abs. 5b EStG, KZ 165 nicht abzugsfähig)
  • migrations/028_euer_4320_bewirtung_ohne_vst.sql: Konten 4652 (Bewirtung 70 % ohne VSt, Z. 44) und 4657 (Bewirtung 30 % ohne VSt, Z. 51) ergänzt
  • docs/kontenrahmen.md: Dokumentation entsprechend aktualisiert

2026-04-12 – Klasse-0-Konten als Anlagevermögen klassifiziert

Geändert

  • docs/kontenrahmen.md: Alle 10 Klasse-0-Konten (0027–0480) von Zahlungskonto auf Anlagevermögen korrigiert
  • migrations/027_anlagevermögen_kontenart.sql: Migration war bereits vorhanden und setzt die DB-Änderung beim nächsten Container-Start um

2026-04-12 – Backup: smarte Rotation und Lock-Schutz

Geändert

  • scripts/backup.sh: Rotation auf 7 Tages- / 4 Wochen- / 12 Monats-Buckets umgestellt (statt pauschaler 90-Tage-Löschung)
  • scripts/backup.sh: flock-Lock verhindert parallele Läufe bei Verzögerungen
  • scripts/backup.sh: Pfade sind absolut (Script funktioniert auch aus Cron ohne Verzeichniswechsel)

2026-04-12 – Uploads: named Volume → Bind Mount

Geändert

  • docker-compose.yml: Upload-Volume von named Volume (steuerkram_uploads) auf Bind Mount (./uploads/) umgestellt – konsistent mit ./data/mariadb/
  • scripts/migrate-uploads-to-bindmount.sh: Einmalige Migration hinzugefügt

Update auf Produktiv-System

Vor docker compose up einmalig ausführen:

./scripts/migrate-uploads-to-bindmount.sh

Das Script kopiert alle Dateien aus dem named Volume in ./uploads/, ist idempotent und gibt am Ende den Befehl zum Löschen des alten Volumes aus.


2026-04-11 – Buchungsbasierte Vorsteuer Kz 61/62 in UStVA

Geändert

  • UstvaCalculator: Kz 61 und 62 werden nicht mehr über accounts.ustva_kz geroutet, sondern direkt aus bookings.ust_satz ermittelt (buchungstyp='Ausgabe', betrag_ust != 0). Damit reicht ein einziges Aufwandskonto für beide USt-Sätze – separate VSt19-/VSt7-Konten sind nicht mehr erforderlich
  • fetchBookingsForKz: Drill-down für Kz 61/62 nutzt jetzt ebenfalls buchungsbasierte Filterung
  • BERICHTE.md: Routing-Logik für Kz 61/62 dokumentiert

2026-04-10 – Nextcloud-Belegimport via WebDAV

Neu

  • NextcloudImportService: importiert Belege aus einem Nextcloud-Ordner via WebDAV (PROPFIND → GET → MOVE/DELETE); Duplikat-Erkennung via SHA-256; JPEG/PNG werden nach dem Download automatisch zugeschnitten
  • scripts/nextcloud-import.php: CLI-Einstiegspunkt für Cron-Betrieb
  • Migration 023: Nextcloud-Zugangsdaten (nextcloud_url, nextcloud_user, nextcloud_pass, nextcloud_folder, nextcloud_done) in company_settings; Konfiguration über Einstellungen → Nextcloud-Belegimport in der UI

2026-04-10 – UStVA Vorsteuer-Kz-Aufteilung (Migration 022)

Fix

  • Migration 022: Vorsteuer-Konten von ustva_kz='66' auf '61' (VSt19) bzw. '62' (VSt7) aufgeteilt – Kz 61, 62 und 66 wurden zuvor stets als 0 ausgewiesen
  • UstvaCalculator: zweite Abfrage für steuerart-basierte EU-Kennzahlen (ig. Lieferung → Kz 41, Ausfuhr → Kz 44, ig. Erwerb → Kz 89/91/93/94); verhindert Doppelzählung gegenüber kontobasierter Berechnung
  • fetchBookingsForKz: UNION-Abfrage aus Konto-Kz und steuerart für korrekten Drill-down
  • Tests 4, 5, 6, 9: Kontonummern auf tatsächliche SKR03-Nummern korrigiert (8000→8400, 1400→1200)

2026-04-10 – Upload-Limit auf 20 MB erhöht

Geändert

  • php/uploads.ini: upload_max_filesize und post_max_size auf 20 MB gesetzt (zuvor PHP-Standard 2 MB)
  • Dockerfile: bindet php/uploads.ini als PHP-Konfiguration ein

2026-04-10 – Belegtext-Speicherung für spätere Volltextsuche

Neu

  • Migration 021: Spalte beleg_text MEDIUMTEXT in belege – speichert den per pdftotext oder Tesseract-OCR extrahierten Volltext
  • KontierungsvorschlagService::extractText(): neue public Methode zur Textextraktion (PDF + Bild), unabhängig vom KI-Vorschlag nutzbar
  • Beim Generieren des KI-Vorschlags wird beleg_text automatisch befüllt (einmalig, nur wenn noch leer)
  • Beleg::saveBelegText(): neue Methode im Model

2026-04-10 – OCR-Schalter unabhängig vom KI-Schalter

Neu

  • Einstellungen: separater Schalter „OCR-Texterkennung" (ocr_aktiv) zum unabhängigen Ein-/Ausschalten der Tesseract-OCR bei Bildbelegen (Migration 020)
  • KI-Schalter und OCR-Schalter arbeiten nun vollständig unabhängig voneinander
  • KontierungsvorschlagService::isOcrEnabled(): neue Methode, prüft OCR-Einstellung
  • Bildbeleg-OCR wird nur noch ausgeführt, wenn ocr_aktiv = 1; PDF-Textextraktion via pdftotext läuft unabhängig davon

2026-04-02 – Kontenrahmen: Dokumentation und finale Korrekturen

Neu

  • Kontenrahmen.md: Vollständige Dokumentation aller SKR03-Systemkonten mit UStVA-Kennzahlen und EÜR-Zeilennummern
  • Verweis auf Kontenrahmen.md in README.md ergänzt

Geändert (Navigation)

  • Kontenrahmen (/accounts) als eingerückter Untermenüpunkt unter „Einstellungen" in der Seitenleiste
  • Konten-Tabelle aus /settings entfernt (war redundant zu /accounts)

Geändert (UStVA-Kennzahlen, Migration 017)

  • KZ 61 → 66 für alle VSt19-Konten (normale Inlands-Vorsteuer, § 15 Abs. 1 Nr. 1 UStG)
  • KZ 62 → 66 für alle VSt7-Konten
  • KZ 35 → 48 für 8100/8105/8110 (steuerfreie Umsätze ohne VoSt-Abzug)
  • KZ 35 → 43 für 8120 (Ausfuhrlieferungen § 4 Nr. 1a UStG)

Geändert (EÜR-Zeilennummern, Migration 019)

  • 8400/8570/8720: Z. 14 → Z. 16 (19 %-Erlöse netto; Z. 14 = Kleinunternehmer brutto)
  • 8120/8125: Z. 16 → Z. 18 (Ausfuhr/ig. Lieferungen)
  • 8950: Z. 18 → Z. 21 (nicht steuerbare Innenumsätze)
  • 4672: Z. 43 → Z. 51 (nicht abziehbarer Anteil Unternehmerreisekosten, § 4 Abs. 5 EStG)
  • 4288: Z. 52 → Z. 65 (häusl. Arbeitszimmer abziehbar, eigene Zeile seit EÜR 2023)
  • 4287: Z. 52 → Z. 66 (Tagespauschale häusl. Wohnung, eigene Zeile seit EÜR 2023)
  • 4856: Z. 49 → Z. 37 (Sonderabschreibungen § 7b EStG)

Kanonischer Seed (Migration 018)

  • 018_seed_kontenrahmen_skr03_final.sql: Alle 146 Systemkonten mit bereits korrekten UStVA-KZ und EÜR-Zeilen; Neuinstallationen erhalten den vollständigen aktuellen Stand ohne weitere Korrekturen

2026-04-01 – Feature: EÜR-Zeile in Konten-Übersicht anzeigen

Neu

  • Spalte „EÜR-Zeile" in der Konten-Liste (/accounts) ergänzt
  • Zeigt den Wert euer_zeile je Konto an (z.B. 14, 26, 51, 52 oder „–" wenn leer)

2026-04-01 – Feature: Bewirtungsbelege (Konten 4650/4651) mit automatischem Split

Neu

  • Buchungen auf Konto 4650 (Bewirtungskosten VSt. 19%) oder 4651 (Bewirtungskosten VSt. 7%) werden automatisch aufgeteilt: 70 % auf das gewählte Konto, 30 % auf das Abzugskonto (4654 bzw. 4656)
  • Neue Felder bewirtungsgrund und teilnehmerliste in der bookings-Tabelle (Migration 016)
  • Im Buchungsformular erscheinen die beiden Felder automatisch, wenn 4650/4651 als Kategorie gewählt wird
  • Vorhandene Buchungen zeigen Bewirtungsgrund und Teilnehmerliste in der Buchungsübersicht an

2026-04-01 – Bugfix: Nicht abzugsfähige Kosten (4654/4656) separat in EÜR unter KZ 165

Behoben

  • Konten mit euer_zeile = '51' (4654, 4656, 4635, 4636, 4289) fließen nicht mehr in total_ausgaben und gewinn ein
  • Sie erscheinen in einem eigenen Abschnitt „Nicht abzugsfähige Betriebsausgaben (KZ 165)" in Web und PDF
  • Migration 015 setzt euer_zeile = '51' für Konto 4656 (fehlte bisher)

2026-03-30 – Bugfix: 30 % Eigenanteil fließt jetzt korrekt in UStVA KZ 81/83

Behoben

  • Booking::upsertEigenanteil30: statt zwei Buchungen (8922 Netto + 1776 USt-Korrektur) wird nur noch eine einzige Buchung auf 8922 mit echtem ust_satz und betrag_ust erzeugt
  • upsertKorrekturbuchung: neue Parameter ustSatz und betragUst; UPDATE und INSERT setzen jetzt betrag_ust und betrag_brutto korrekt
  • Vorher: betrag_ust = 0 auf 8922 → KZ 83 blieb leer; 1776-Buchung hatte keine UStVA-Wirkung

2026-03-30 – Kontenrahmen-Reset: DATEV SKR03 2026 (IST-Versteuerung)

Geändert

  • Alle Buchungen und Belege gelöscht (Testdaten)
  • Gesamter Kontenrahmen durch DATEV SKR03 2026 (gültig ab 2026-01-01) ersetzt
  • Neue Spalte euer_zeile in Tabelle accounts: Zeilennummer der Anlage EÜR
  • 145 Konten neu angelegt: Klassen 0, 1, 3, 4, 8 (ohne Klasse 9 / ohne Verbindlichkeiten)
  • Verfahren: IST-Versteuerung; Konto 1390 „Verrechnungskonto Ist-Versteuerung" enthalten
  • UStVA-Kennzeichen korrekt nach DATEV: 81/86 (Umsätze), 61/62 (Vorsteuer), 35/41 (steuerfrei)
  • Migration: 013_reset_kontenrahmen_skr03_2026.sql

2026-03-30 – KI-gestützte Belegerkennung (experimentell) + 30 % Eigenanteil Telefon/Internet

Neu

  • Eigenanteil von 30 % bei Buchungen auf Telefon- und Internetkosten-Konten (4920/4925) wählbar
  • Experimentelle KI-Beleganalyse: erkennt Buchungstyp, Betrag, Konto und Lieferant aus PDF/Bild-Belegen
    • Setzt lokales LLM (z. B. Ollama/Mistral) oder Remote-API-Schlüssel voraus
    • Hoher Ressourcenbedarf bei lokaler Ausführung; Ergebnisqualität mit Mistral bisher mäßig
    • Getestet mit ollama run mistral

Betrifft

  • src/Services/KontierungsvorschlagService.php
  • src/Services/LlmService.php
  • src/Views/belege/detail.php, list.php
  • Dockerfile, docker-compose.yml

2026-03-30 – Fix: Lieferant-Eingabe in Metadaten-Leiste speichert korrekt

Geändert

  • supplier-persistent-input: Nach erfolgreichem AJAX-Speichern wird das Texteingabefeld durch den Inline-Trigger-Span ersetzt – visuelle Bestätigung, dass der Lieferant gespeichert wurde
  • Fehlerbehandlung (try/catch) hinzugefügt: bei fehlgeschlagenem Speichern bleibt das Feld editierbar
  • Das versteckte Metaformular (supplier_name_input) wird nach AJAX-Speichern synchronisiert, damit ein späteres Absenden des Metaformulars den Lieferanten nicht überschreibt

Betrifft

  • src/Views/belege/detail.php

2026-03-30 – Lieferant inline editierbar + KI-Lieferantenerkennung

Geändert

  • Lieferant in der Beleg-Info-Bar ist jetzt direkt inline editierbar (Klick auf ✎), wie Belegdatum und Rechnungsnr.
  • KI-Kontierungsvorschlag extrahiert nun auch den Lieferantennamen aus dem Beleg
  • Nach KI-Analyse: bekannter Lieferant wird automatisch eingetragen; unbekannter Lieferant öffnet das Lieferantenfeld sofort mit Fokus
  • KI-Badge zeigt Lieferantenname an, unbekannte Lieferanten werden als „(neu – bitte prüfen)" markiert
  • Validierung in KontierungsvorschlagService prüft zahlungskonto_id und kategorie_konto_id jetzt gegen die korrekte Kontenart statt gegen alle Konten

Betrifft

  • src/Services/KontierungsvorschlagService.php
  • src/Views/belege/detail.php
  • public/static/js/app.js

2026-03-29 – EÜR: Spaltenauswahl nach Kontenart statt Buchungstyp

Geändert

  • EuerCalculator::calculate() wertet accounts.kontenart aus statt buchungstyp
  • Betriebseinnahme → Einnahmen-Spalte, Betriebsausgabe → Ausgaben-Spalte
  • Privat, Zahlungskonto, Verbindlichkeit als Kategorie-Konto werden nicht in der EÜR ausgewiesen
  • Vorzeichen von betrag_netto werden beibehalten (kein abs() mehr) – negative Beträge mindern die jeweilige Spalte
  • Buchungen desselben Kontos werden unabhängig vom buchungstyp zu einem Eintrag zusammengefasst

Betrifft

  • src/Services/EuerCalculator.php
  • BERICHTE.md (EÜR-Kapitel aktualisiert)

2026-03-29 – UStVA: kontonummernbasierte Kennzahlenberechnung

Geändert

  • UstvaCalculator::calculate() wertet ausschließlich accounts.ustva_kz des Kategorie-Kontos aus – buchungstyp und steuerart werden nicht mehr benötigt
  • UstvaCalculator::fetchBookingsForKz() filtert über k.ustva_kz IN (...) statt über Buchungsfelder
  • Kz 83 und 84 kommen jetzt direkt aus betrag_ust der Erlöskonten (statt Kz81 × 19 %)
  • Kz 91 und 94 kommen direkt aus betrag_ust der ig.-Erwerb-Konten (statt abgeleitet)

Betrifft

  • src/Services/UstvaCalculator.php
  • Migration 010_ustva_kz_konto_mapping.sql
  • BERICHTE.md (UStVA-Kapitel vollständig neu)

Migration 010 – Kontenanpassungen

  • Alle Betriebsausgabe-Konten mit steuercode='VSt19': ustva_kz von '66' auf '61'
  • Alle Betriebsausgabe-Konten mit steuercode='VSt7': ustva_kz von '66' auf '62'
  • Neue Konten: 3425 „Innergemeinschaftliche Erwerbe 19 %" (ustva_kz='89'), 3420 „Innergemeinschaftliche Erwerbe 7 %" (ustva_kz='93')

2026-03-28 – 30% Eigenanteil-Kennzeichnung und Korrekturbuchungen

Hinzugefügt

  • Checkbox „30% Eigenanteil buchen" in der Buchungszeilen-Erfassung (zwischen Nettobetrag und Submit-Button)
  • Neues Feld eigenanteil_30 TINYINT(1) in der belege-Tabelle (Migration 009_beleg_eigenanteil_30.sql)
  • Der Checkbox-Wert wird beim Speichern einer Buchung in die Beleg-Metadaten übernommen
  • Bei gesetzter Checkbox werden automatisch zwei Korrekturbuchungen angelegt oder aktualisiert:
    • 30% des Nettobetrags an Konto 8922 (nicht abzugsfähiger Eigenanteil), Zahlungskonto 1800
    • 30% der errechneten USt an Konto 1776 (Vorsteuerkorrektur), Zahlungskonto 1800 – nur wenn USt-Satz > 0
  • Im Testmodus: bestehende Korrekturbuchungen werden direkt überschrieben
  • Im Produktivmodus: bestehende Korrekturbuchungen werden GoBD-konform storniert und neu angelegt

Betrifft

  • src/Views/belege/detail.php
  • src/Controllers/BookingController.php
  • src/Models/Booking.php (neue Methoden upsertEigenanteil30, upsertKorrekturbuchung)
  • Migration: 009_beleg_eigenanteil_30.sql

2026-03-27 – DATEV-konformer SKR03 Kontenrahmen (#11)

Geändert

  • Kontenrahmen: Bisherige ~80 Konten durch DATEV-konformen SKR03 ersetzt (Migration 008_skr03_vollstaendig.sql)
  • Umfang: 157 Systemkonten aus Klassen 0 (Anlagevermögen), 1 (Zahlungsmittel, Vorsteuer, USt, Privat), 2 (Eigenkapital), 4 (Betriebsausgaben), 8 (Betriebseinnahmen)
  • EÜR-Fokus: Keine Forderungs- oder Verbindlichkeitskonten (nicht bilanzierend)
  • Kompatibilität: Alte Konten bleiben mit is_system = 0 erhalten – bestehende Buchungen sind nicht betroffen

Betrifft

  • Migration: 008_skr03_vollstaendig.sql

2026-03-27 – Ausgangsrechnungen in Dashboard/EÜR/UStVA (#8)

Behoben

  • Seed-Skript: scripts/seed-testdata.php rief Invoice::finalize() auf, ohne anschließend Beleg und Buchungen anzulegen – Ausgangsrechnungen fehlten daher in allen Auswertungen
  • Ursache: Invoice::finalize() (Model) setzt nur Status und Rechnungsnummer; die Buchungserstellung liegt in InvoiceController::createBelegAndBookings() und wurde im Seed nicht aufgerufen
  • Fix: Seed-Skript legt nach Invoice::finalize() nun Beleg und zugehörige Buchungen an (analog zur Controller-Logik), sodass Ausgangsrechnungen korrekt in EÜR, UStVA und Dashboard erscheinen

Betrifft

  • Skript: scripts/seed-testdata.php
  • Test: tests/09_InvoiceToReportsTest.php (neu – End-to-End-Test Ausgangsrechnung → EÜR/UStVA/Dashboard)

2026-03-26 – Lieferantenmanagement (#7)

Neu

  • Lieferantenverwaltung: Neue Seite /suppliers zum Anlegen, Bearbeiten und Löschen von Lieferanten
  • Lieferant am Beleg: Im Metadaten-Formular der Belegdetailseite kann ein Lieferant per Dropdown/Freitexteingabe ausgewählt werden; unbekannte Namen werden beim Speichern automatisch angelegt
  • Datenbank: Tabelle suppliers (id, name) und Fremdschlüssel supplier_id in belege
  • Navigation: Neuer Menüpunkt "Lieferanten" im Bereich Belege & Buchungen

Betrifft

  • Migration: 007_suppliers.sql
  • Model: Supplier.php (neu), Beleg.php (JOIN + updateMeta)
  • Controller: SupplierController.php (neu), BelegController.php
  • Views: suppliers/list.php, suppliers/form.php (neu), belege/detail.php, layout/nav.php
  • Routes: public/index.php
  • Test: 08_LieferantTest.php

2026-03-26 – EÜR-Buchungsmodell (Soll/Haben → Einnahme/Ausgabe)

Geändert

  • Buchungsmodell: Doppelte Buchführung (Soll-Konto/Haben-Konto) durch reines EÜR-Modell ersetzt – jede Buchung hat nun buchungstyp (Einnahme/Ausgabe), kategorie_konto_id (Was?) und zahlungskonto_id (Wie bezahlt?)
  • Kontenarten: Umbenannt von Aktiv/Passiv/Aufwand/Ertrag/Neutral zu Betriebseinnahme/Betriebsausgabe/Zahlungskonto/Verbindlichkeit/Privat
  • EÜR-Berechnung: Vereinfacht – gruppiert direkt nach buchungstyp statt komplexer Soll/Haben-Ableitung
  • UStVA-Berechnung: Verwendet buchungstyp statt Kontenart-Ableitung für USt/VSt-Zuordnung
  • UI-Terminologie: Alle Bezeichnungen in Views, Journal, Dashboard und Formularen von Soll/Haben auf Typ/Kategorie/Zahlungskonto umgestellt
  • CSV-Export: Spalten an neues Modell angepasst (Typ, Kategorie-Kto., Zahlungskonto-Kto.)

Betrifft

  • Schema (001_initial_schema.sql), Seed (002_seed_skr03.sql)
  • Models: Booking.php, Account.php
  • Services: EuerCalculator.php, UstvaCalculator.php
  • Controllers: BookingController.php, AccountController.php, InvoiceController.php
  • Views: dashboard.php, journal.php, detail.php, accounts/form.php, accounts/list.php
  • JavaScript: app.js
  • Tests: 02, 04, 05 aktualisiert + neuer Test 06 (EÜR-Buchungsmodell)

2026-03-25 – Session-Authentifizierung & Benutzerverwaltung

Features

  • Session-Authentifizierung: HTTP Basic Auth durch cookie-basierte Session-Authentifizierung ersetzt; Sessions laufen nach 24 Stunden absolut ab
  • Benutzerverwaltung (/useradmin): Benutzer anlegen, bearbeiten (Benutzername und Passwort), deaktivieren und löschen; Passwörter mit bcrypt gehasht
  • Ersteinrichtungsflow: Beim ersten Start ohne Benutzer ermöglicht /login das Anlegen des ersten Administrator-Accounts
  • Abmelden-Button in der Seitenleiste

Geändert

  • AUTH_USER und AUTH_PASS entfernt – Zugangsdaten werden ausschließlich in der Datenbank verwaltet
  • Neue Datenbanktabelle users (Migration 005_users.sql)

Behoben

  • Fehler in BelegController behoben

2026-03-25 – Sicherheit, UX-Verbesserungen & Bugfixes

Sicherheit

  • Timing-sicherer Login: Passwort- und Benutzernamevergleich auf hash_equals() umgestellt (verhindert Timing-Angriffe)
  • SVG-Upload gesperrt: Logo-Upload akzeptiert nur noch PNG und JPEG – SVG wurde entfernt (XSS-Risiko)
  • CSV-Injection-Schutz: Felder im Buchungsjournal-CSV-Export werden gegen Formula-Injection (=, +, -, @) abgesichert

Features

  • Inline-Editing: Belegdatum und Rechnungsnr. können direkt in der Beleg-Detailansicht per Klick bearbeitet werden (kein Seitenreload)
  • Belegart-Filter: Neue Filteroption in der Belegliste zum Filtern nach Belegart (Eingangsrechnung, Ausgangsrechnung, Quittung etc.)
  • Favicon & App-Icon: Favicon für Browser-Tabs, Apple Touch Icon und Web-App-Manifest eingebunden

Robustheit

  • Datenbankfehler-Handling: PDO-Exceptions in Invoice-, Booking- und BelegController werden separat abgefangen und geloggt statt als generische Fehler zu erscheinen

2026-03-24 – Initiales Release

Features

  • Basis-System: MVC-Framework, Routing, Authentifizierung, Datenbank-Migrations-System
  • Ausgangsrechnungen: Erstellen, Verwalten und PDF-Export von Ausgangsrechnungen
  • EÜR-Vorbereitung: Einnahmen-Überschuss-Rechnung als PDF-Export
  • UStVA-Vorbereitung: Umsatzsteuer-Voranmeldung inkl. XML-Export für elster.de