Merge pull request 'Docs: Dokumentation komplett überarbeitet' (#35) from fds2610-bot/Steuerkram:main into main
Reviewed-on: https://codeberg.org/fds2610/Steuerkram/pulls/35
This commit is contained in:
commit
5f512c7a6a
17 changed files with 919 additions and 431 deletions
|
|
@ -4,9 +4,6 @@ DB_NAME=steuerkram
|
|||
DB_USER=steuerkram
|
||||
DB_PASS=steuerkram
|
||||
|
||||
# App
|
||||
APP_SECRET=change-this-to-a-random-string
|
||||
|
||||
# KI-Kontierungsvorschlag (optional)
|
||||
# Wenn nichts konfiguriert wird, sucht die App automatisch nach einem lokalen Ollama auf localhost:11434.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -42,8 +42,10 @@ $this->assertNotEmpty($wert, 'Beschreibung');
|
|||
| Datei | Wann aktualisieren |
|
||||
|---|---|
|
||||
| `Changes.md` | Bei jedem Feature, Bugfix oder strukturellen Änderung (nicht bei reinen Test- oder Doku-Commits) |
|
||||
| `README.md` | Wenn sich der Funktionsumfang, Tech Stack oder die Installationsanleitung ändert |
|
||||
| `BERICHTE.md` | Bei jeder Änderung an `EuerCalculator.php` oder `UstvaCalculator.php` (Zuordnungsregeln, neue Kennzahlen, geänderte Bedingungen) |
|
||||
| `README.md` | Wenn sich der Funktionsumfang oder der Tech Stack grundlegend ändert |
|
||||
| `docs/funktionen.md` | Wenn ein neues Feature hinzukommt oder ein bestehendes wesentlich geändert wird |
|
||||
| `docs/berechnungslogik.md` | Bei jeder Änderung an `EuerCalculator.php` oder `UstvaCalculator.php` (Zuordnungsregeln, neue Kennzahlen, geänderte Bedingungen) |
|
||||
| `docs/anlagevermögen.md` | Bei Änderungen am Anlagevermögens-Workflow oder den Asset-Modellen |
|
||||
|
||||
## Datenbankmigrationen
|
||||
|
||||
|
|
|
|||
406
README.md
406
README.md
|
|
@ -1,396 +1,62 @@
|
|||
# Steuerkram
|
||||
|
||||
Self-hosted Buchhaltungs- und Steueranwendung für deutsche Freiberufler und Kleinunternehmer. Entwickelt als datensouveräne Alternative zu SaaS-Diensten.
|
||||
Self-hosted Buchhaltungs- und Steueranwendung für deutsche Freiberufler und Kleinunternehmer. Entwickelt als datensouveräne Alternative zu SaaS-Diensten – mit Unterstützung von [Claude Code](https://claude.ai/code).
|
||||
|
||||

|
||||

|
||||

|
||||
[](LICENSE.md)
|
||||
|
||||
---
|
||||
|
||||
## Funktionsumfang
|
||||
|
||||
- **Kontenrahmen SKR03** – DATEV-konformer SKR03 mit 157 Systemkonten (Klassen 0, 1, 2, 4, 8); zugeschnitten auf EÜR-Buchhalter ohne Bilanzierung (CRUD)
|
||||
- **Belegverwaltung** – Upload von PDF, PNG, TIFF und ZUGFeRD-XML; SHA-256 Integritätsprüfung; automatischer Weißrand-Zuschnitt bei JPEG/PNG via GD
|
||||
- **Buchungen** – EÜR-Buchungsmodell (Einnahme/Ausgabe) mit Kategorie- und Zahlungskonto; GoBD-konforme Trigger verhindern nachträgliche Manipulation
|
||||
- **Kundenverwaltung** – CRUD
|
||||
- **Ausgangsrechnungen** – DIN 5008 Layout, PDF-Export via mPDF
|
||||
- **UStVA** – Kennzahlen-Berechnung aus Buchungen, ELSTER XML-Export
|
||||
- **EÜR** – Jahresauswertung mit PDF-Export
|
||||
- **Einstellungen** – Firmendaten, Logo, ELSTER-Steuernummer
|
||||
- **Benutzerverwaltung** – Benutzer anlegen, bearbeiten, deaktivieren und löschen; session-basierte Authentifizierung mit 24 h Timeout
|
||||
|
||||
## Tech Stack
|
||||
|
||||
Dieses Projekt wurden mit Unterstützung von [Claude Code](https://claude.ai/code) entwickelt.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
| Schicht | Technologie |
|
||||
| Bereich | Beschreibung |
|
||||
|---|---|
|
||||
| Webserver | Apache 2.4 |
|
||||
| Backend | PHP 8.3 (MVC, kein Framework) |
|
||||
| Datenbank | MariaDB 11 |
|
||||
| PDF-Generierung | mPDF 8.x |
|
||||
| Frontend | HTML, CSS, JavaScript (keine Bibliotheken) |
|
||||
| Deployment | Docker / Docker Compose |
|
||||
| **Kontenrahmen SKR03** | DATEV-konform, 157 Konten, mit UStVA-Kennzahlen und EÜR-Zeilennummern |
|
||||
| **Belegverwaltung** | PDF, PNG, TIFF, ZUGFeRD-XML; SHA-256 Integritätsprüfung; optionale KI-Kontierung |
|
||||
| **Buchungen** | EÜR-Modell (Einnahme/Ausgabe); GoBD-konforme Trigger; Stornobuchungen; Journal |
|
||||
| **Anlagevermögen** | Anlagenspiegel; automatische Anlagen-Nummerierung; Buchungsworkflow mit Asset-Verknüpfung |
|
||||
| **Ausgangsrechnungen** | DIN 5008, PDF-Export via mPDF |
|
||||
| **UStVA** | Kennzahlen-Berechnung, ELSTER XML-Export, Drill-down |
|
||||
| **EÜR** | Jahresauswertung, PDF-Export, Drill-down |
|
||||
| **Kundenverwaltung** | CRUD |
|
||||
| **Einstellungen** | Firmendaten, Logo, ELSTER-Steuernummer, Nummernkreise |
|
||||
| **Benutzerverwaltung** | Mehrbenutzer, Session-Auth mit 24 h Timeout |
|
||||
|
||||
## Voraussetzungen
|
||||
---
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/) ≥ 24
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/) ≥ 2.20 (in neueren Docker-Versionen enthalten)
|
||||
- Git
|
||||
|
||||
## Installation
|
||||
|
||||
### Automatische Installation
|
||||
|
||||
Das Script `install.sh` übernimmt die gesamte Installation: es erkennt die Linux-Distribution, installiert git, curl und Docker, klont das Repository in das gewünschte Verzeichnis und legt die `.env`-Datei an.
|
||||
|
||||
Das Script muss **vor** dem Klonen des Repositories heruntergeladen werden – es erledigt das Klonen selbst:
|
||||
## Schnellstart
|
||||
|
||||
```bash
|
||||
curl -fsSL https://codeberg.org/fds2610/Steuerkram/raw/branch/main/install.sh -o install.sh
|
||||
sudo bash install.sh
|
||||
```
|
||||
|
||||
> Das Script muss als root ausgeführt werden, da es Pakete installiert und ggf. den Docker-Dienst aktiviert. Mit `sudo bash install.sh` funktioniert das ohne dauerhaft als root angemeldet zu sein.
|
||||
|
||||
Nach der Installation die `.env`-Datei im gewählten Installationsverzeichnis anpassen (siehe Hinweis am Ende des Scripts) und anschließend die Container starten:
|
||||
|
||||
```bash
|
||||
cd /opt/Steuerkram # oder das gewählte Verzeichnis
|
||||
cd /opt/Steuerkram
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Manuelle Installation
|
||||
|
||||
#### 1. Repository klonen
|
||||
|
||||
```bash
|
||||
git clone <repository-url> steuerkram
|
||||
cd steuerkram
|
||||
```
|
||||
|
||||
#### 2. Konfiguration anpassen
|
||||
|
||||
Kopiere `.env.example` nach `.env` und passe die Werte an:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
```dotenv
|
||||
DB_PASS=sicheres-passwort # Datenbankpasswort – in docker-compose.yml spiegeln
|
||||
APP_SECRET=zufaelliger-string # Zufälligen langen String eintragen (für Sessions)
|
||||
```
|
||||
|
||||
Außerdem in `docker-compose.yml` das `MARIADB_PASSWORD` im `db`-Service auf denselben Wert wie `DB_PASS` setzen.
|
||||
|
||||
#### 3. Container starten
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Beim ersten Start werden automatisch:
|
||||
- die Datenbank initialisiert (`migrations/001_initial_schema.sql`)
|
||||
- der SKR03-Kontenrahmen eingespielt (`migrations/002_seed_skr03.sql`)
|
||||
- das Docker-Image mit PHP-Abhängigkeiten (mPDF) gebaut
|
||||
|
||||
#### 4. Anwendung aufrufen
|
||||
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
Beim ersten Aufruf erscheint die **Ersteinrichtung**: dort den ersten Benutzer-Account anlegen. Danach ist die Anwendung passwortgeschützt.
|
||||
|
||||
Weitere Benutzer können nach dem Login unter **Benutzer** in der Seitenleiste verwaltet werden.
|
||||
|
||||
#### 5. KI-Beleganalyse einrichten (optional)
|
||||
|
||||
Die KI-gestützte Belegerkennung ist standardmäßig deaktiviert. Sie kann unter **Einstellungen → KI-Kontierungsvorschlag** aktiviert werden, sobald ein LLM erreichbar ist.
|
||||
|
||||
**Option A – Lokales Ollama** (kein API-Schlüssel nötig, aber hoher Ressourcenbedarf):
|
||||
|
||||
```bash
|
||||
ollama pull mistral # oder llama3.2 etc.
|
||||
```
|
||||
|
||||
In `.env` ist keine weitere Konfiguration nötig – die App erkennt Ollama auf `localhost:11434` automatisch. Modell und URL können optional überschrieben werden:
|
||||
|
||||
```dotenv
|
||||
OLLAMA_URL=http://localhost:11434
|
||||
OLLAMA_MODEL=mistral
|
||||
```
|
||||
|
||||
**Option B – Remote-API** (OpenAI-kompatibel, z. B. OpenAI, OpenRouter, LM Studio):
|
||||
|
||||
```dotenv
|
||||
LLM_API_URL=https://api.openai.com/v1
|
||||
LLM_API_KEY=sk-...
|
||||
LLM_MODEL=gpt-4o-mini
|
||||
```
|
||||
|
||||
> **Hinweis:** Die Ergebnisqualität hängt stark vom gewählten Modell ab. Tests mit `mistral` (lokal via Ollama) lieferten bisher mäßige Ergebnisse.
|
||||
|
||||
#### 6. Firmendaten hinterlegen
|
||||
|
||||
Nach dem ersten Login unter **Einstellungen** Firmendaten, Logo und ELSTER-Steuernummer eintragen. Diese Angaben erscheinen auf Ausgangsrechnungen und im EÜR-Export.
|
||||
|
||||
## Port ändern
|
||||
|
||||
Der Standard-Port ist `8080`. Um ihn zu ändern, passe in `docker-compose.yml` die `ports`-Zeile an:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "9090:80" # Beispiel: Port 9090 auf dem Host
|
||||
```
|
||||
|
||||
## Upload-Limit anpassen
|
||||
|
||||
Die maximale Dateigröße für Beleganhänge ist auf **20 MB** voreingestellt (`php/uploads.ini`). Um das Limit zu ändern, die Werte in dieser Datei anpassen und den Container neu bauen:
|
||||
|
||||
```ini
|
||||
upload_max_filesize = 20M
|
||||
post_max_size = 20M
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
## Belege automatisch aus Nextcloud importieren
|
||||
|
||||
Belege können automatisch aus einem Nextcloud-Ordner via WebDAV importiert werden. Das CLI-Skript `scripts/nextcloud-import.php` liest alle unterstützten Dateien (PDF, JPEG, PNG, TIFF, XML) aus dem konfigurierten Ordner, legt sie als Belege an und verschiebt sie anschließend in einen Erledigte-Ordner (oder löscht sie, wenn kein Ziel-Ordner konfiguriert ist).
|
||||
|
||||
### Konfiguration
|
||||
|
||||
Die Zugangsdaten werden in der Steuerkram-UI gepflegt: **Einstellungen → Nextcloud-Belegimport**.
|
||||
|
||||
Empfehlung: Ein Nextcloud-App-Passwort verwenden (Nextcloud → Einstellungen → Sicherheit → App-Passwörter).
|
||||
|
||||
### Manueller Aufruf
|
||||
|
||||
```bash
|
||||
docker compose exec web php scripts/nextcloud-import.php
|
||||
```
|
||||
|
||||
### Automatisch per Cron (auf dem Host)
|
||||
|
||||
```cron
|
||||
*/15 * * * * docker compose -f /opt/steuerkram/docker-compose.yml exec -T web \
|
||||
php scripts/nextcloud-import.php >> /var/log/steuerkram-import.log 2>&1
|
||||
```
|
||||
|
||||
Das Skript gibt beim Start eine Zusammenfassung aus (importiert / übersprungen / Fehler) und beendet sich mit Exit-Code 1 bei Fehlern.
|
||||
|
||||
## Datenpersistenz
|
||||
|
||||
| Pfad | Inhalt |
|
||||
|---|---|
|
||||
| `./data/mariadb/` | MariaDB-Datenbankdateien |
|
||||
| Docker Volume `uploads` | Hochgeladene Belege |
|
||||
|
||||
Beide Pfade liegen außerhalb des Containers und bleiben bei `docker compose down` erhalten.
|
||||
|
||||
## Systemd-Service einrichten
|
||||
|
||||
Damit Steuerkram automatisch beim Systemstart startet und als Dienst verwaltet werden kann, liegt im Repository die Datei `steuerkram.service`.
|
||||
|
||||
#### 1. Service-Datei installieren
|
||||
|
||||
```bash
|
||||
sudo cp steuerkram.service /etc/systemd/system/steuerkram.service
|
||||
```
|
||||
|
||||
Die Datei setzt `WorkingDirectory=/opt/Steuerkram` voraus. Falls das Repository in ein anderes Verzeichnis geklont wurde, den Pfad in der Service-Datei anpassen:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/steuerkram.service
|
||||
# WorkingDirectory= auf das tatsächliche Installationsverzeichnis setzen
|
||||
```
|
||||
|
||||
#### 2. Service aktivieren und starten
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable steuerkram # automatisch beim Systemstart
|
||||
sudo systemctl start steuerkram
|
||||
```
|
||||
|
||||
#### 3. Status prüfen
|
||||
|
||||
```bash
|
||||
sudo systemctl status steuerkram
|
||||
journalctl -u steuerkram -f # Live-Log inkl. Migrations-Ausgabe
|
||||
```
|
||||
|
||||
#### Wichtige Service-Befehle
|
||||
|
||||
| Befehl | Wirkung |
|
||||
|---|---|
|
||||
| `sudo systemctl start steuerkram` | Container starten |
|
||||
| `sudo systemctl stop steuerkram` | Container stoppen |
|
||||
| `sudo systemctl restart steuerkram` | Neustart (z.B. nach Update) |
|
||||
| `sudo systemctl status steuerkram` | Aktueller Status |
|
||||
|
||||
## Backup
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
```
|
||||
|
||||
Das Skript erstellt ein Dump der Datenbank sowie ein Archiv der Uploads im Verzeichnis `backups/`.
|
||||
|
||||
## Update
|
||||
|
||||
Seit dem 11.04.2026 bin ich mit meiner Software für mich selber produktiv. Ab diesem Zeitpunkt sollten keine breaking changes mehr vorkommen.
|
||||
|
||||
Datenbankmigrationen werden **automatisch** beim nächsten Container-Start eingespielt – kein manueller Eingriff nötig. Das Script `scripts/migrate.php` prüft beim Start, welche Migrations-Dateien noch nicht angewendet wurden, und führt sie der Reihe nach aus.
|
||||
|
||||
### Vollständige Update-Anleitung
|
||||
|
||||
Die folgenden Schritte sichern einen vollständigen und sicheren Update-Ablauf. Alle Befehle im Steuerkram-Verzeichnis ausführen.
|
||||
|
||||
#### Schritt 1 – Datenbank sichern
|
||||
|
||||
Vor jedem Update ein Backup erstellen:
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
```
|
||||
|
||||
Das Backup landet in `backups/`. Alternativ manuell:
|
||||
|
||||
```bash
|
||||
docker compose exec db mariadb-dump -u steuerkram -psteuerkram steuerkram \
|
||||
> ~/steuerkram_backup_$(date +%Y%m%d_%H%M).sql
|
||||
```
|
||||
|
||||
#### Schritt 2 – Aktuellen Code holen
|
||||
|
||||
```bash
|
||||
git pull
|
||||
```
|
||||
|
||||
Prüfen, ob neue Migrations-Dateien enthalten sind:
|
||||
|
||||
```bash
|
||||
git log --oneline -5
|
||||
```
|
||||
|
||||
#### Schritt 3 – Container neu bauen und starten
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Dieser Befehl baut das PHP-Image neu (falls sich `Dockerfile` oder `composer.json` geändert haben) und startet alle Container. Der Web-Container führt beim Start automatisch `scripts/migrate.php` aus.
|
||||
|
||||
#### Schritt 4 – Migrationen prüfen
|
||||
|
||||
```bash
|
||||
docker compose logs web | grep migrate
|
||||
```
|
||||
|
||||
Erwartete Ausgabe bei erfolgreicher Migration:
|
||||
|
||||
```
|
||||
[migrate] Starte Migrations-Prüfung...
|
||||
[migrate] Führe aus: NNN_beschreibung.sql
|
||||
[migrate] N Migration(en) erfolgreich angewendet.
|
||||
```
|
||||
|
||||
Oder wenn alles bereits aktuell ist:
|
||||
|
||||
```
|
||||
[migrate] Datenbank ist aktuell – keine Migrationen notwendig.
|
||||
```
|
||||
|
||||
Falls die Ausgabe einen Fehler enthält, das Backup aus Schritt 1 einspielen:
|
||||
|
||||
```bash
|
||||
docker compose exec -T db mariadb -u steuerkram -psteuerkram steuerkram \
|
||||
< ~/steuerkram_backup_YYYYMMDD_HHMM.sql
|
||||
```
|
||||
|
||||
#### Schritt 5 – Anwendung prüfen
|
||||
|
||||
```bash
|
||||
docker compose ps # alle Container müssen "running" sein
|
||||
docker compose logs web # keine PHP-Fehler oder Exceptions
|
||||
```
|
||||
|
||||
Anschließend im Browser unter `http://localhost:8080` (oder dem konfigurierten Port) einloggen und stichprobenartig Belege und Buchungen prüfen.
|
||||
Anwendung aufrufen: `http://localhost:8080`
|
||||
|
||||
---
|
||||
|
||||
#### Ohne Systemd-Service (Kurzform)
|
||||
## Dokumentation
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
docker compose logs web | grep migrate
|
||||
```
|
||||
| Dokument | Inhalt |
|
||||
|---|---|
|
||||
| [Installation](docs/installation.md) | Docker-Setup, Systemd-Service, Port, Upload-Limit |
|
||||
| [Konfiguration](docs/konfiguration.md) | Firmendaten, Nummernkreise, KI-Beleganalyse, Nextcloud-Import |
|
||||
| [Funktionen](docs/funktionen.md) | Alle Features im Detail |
|
||||
| [Anlagevermögen](docs/anlagevermögen.md) | Anlagenspiegel, Buchungsworkflow, Nummernkreis |
|
||||
| [Update & Backup](docs/update-backup.md) | Update-Anleitung, Backup, Datenpersistenz |
|
||||
| [Automatisierung](docs/automatisierung.md) | Automatisierungsagent, Ideenagent, Support |
|
||||
| [Datenbankstruktur](docs/datenbankstruktur.md) | Tabellen, Spalten, Fremdschlüssel, GoBD-Mechanismen |
|
||||
| [Berechnungslogik](docs/berechnungslogik.md) | UStVA-Kennzahlen und EÜR-Zuordnungsregeln |
|
||||
| [Kontenrahmen](docs/kontenrahmen.md) | Vollständige SKR03-Kontenliste |
|
||||
|
||||
#### Mit Systemd-Service (Kurzform)
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
git pull
|
||||
docker compose build
|
||||
sudo systemctl restart steuerkram
|
||||
journalctl -u steuerkram | grep migrate
|
||||
```
|
||||
---
|
||||
|
||||
## GoBD-Hinweise
|
||||
|
||||
- Gebuchte Sätze können nicht geändert oder gelöscht werden (MariaDB `BEFORE UPDATE/DELETE` Trigger).
|
||||
- Korrekturen erfolgen ausschließlich über Stornobuchungen.
|
||||
- Jeder hochgeladene Beleg erhält einen SHA-256 Hash zur Integritätsprüfung.
|
||||
|
||||
## Kontenrahmen SKR03
|
||||
|
||||
Der enthaltene Kontenrahmen basiert auf dem DATEV SKR03 2026, zugeschnitten auf EÜR-Buchhalter (IST-Versteuerung). Alle Konten sind mit geprüften UStVA-Kennzahlen (ELSTER) und EÜR-Zeilennummern (Anlage EÜR 2024) hinterlegt.
|
||||
|
||||
Vollständige Dokumentation: [`Kontenrahmen.md`](Kontenrahmen.md)
|
||||
|
||||
## Berechnungslogik UStVA und EÜR
|
||||
|
||||
Detaillierte Informationen darüber, welche Buchungsattribute und Konten in welche Positionen der UStVA (ELSTER-Kennzahlen) bzw. der EÜR einfließen, sind in [`BERICHTE.md`](BERICHTE.md) dokumentiert.
|
||||
|
||||
## Support
|
||||
|
||||
Issues können im [Codeberg-Repo](https://codeberg.org/fds2610/Steuerkram/issues) gemeldet werden. Mit dem Label **`automate`** werden sie automatisch verarbeitet.
|
||||
|
||||
### Automatisierter Agent
|
||||
|
||||
Ein stündlich per Cron gestarteter Agent (Claude CLI) verarbeitet Issues mit dem Label `automate` nacheinander – mit Lockfile-Schutz gegen Parallelläufe. Mehrere offene Tickets werden in einer Sitzung sequenziell abgearbeitet.
|
||||
|
||||
#### Ablauf je Ticket
|
||||
|
||||
1. Issue-Body und alle Kommentare laden (inkl. Diskussionsergebnisse früherer Rückfragen)
|
||||
2. Relevante Codebase-Dateien lesen
|
||||
3. **Klarheitscheck**: Sind die Anforderungen eindeutig? Falls nicht → Rückfragen als Kommentar posten, `automate`-Label entfernen, warten
|
||||
4. Analyse mit Claude Opus (Ursache, Lösungsplan, Risiken)
|
||||
5. Lösung implementieren
|
||||
6. Tests ausführen (`php tests/run.php`), Fehler beheben
|
||||
7. Commit & Push: `Fix #NR: Kurzbeschreibung`
|
||||
8. Kommentar mit Zusammenfassung im Issue posten
|
||||
9. Labels aktualisieren, Issue offen lassen
|
||||
|
||||
#### Label-Ausgänge
|
||||
|
||||
| Ergebnis | `automate` | gesetztes Label |
|
||||
|---|---|---|
|
||||
| Erfolgreich umgesetzt | entfernt | `testing` |
|
||||
| Unklar / Rückfrage offen | entfernt | *(keins)* |
|
||||
| Zu riskant / abgelehnt | entfernt | `abgelehnt` |
|
||||
|
||||
## Lizenz
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
Dieses Projekt steht unter der MIT-Lizenz – siehe [LICENSE.md](LICENSE.md) für Details.
|
||||
|
|
|
|||
69
docs/anlagevermögen.md
Normal file
69
docs/anlagevermögen.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# Anlagevermögen
|
||||
|
||||
## Überblick
|
||||
|
||||
Der Bereich **Betriebsvermögen → Anlagevermögen** führt einen Anlagenspiegel für abnutzbare Wirtschaftsgüter. Jedes Wirtschaftsgut ist mit einem Anlagevermögenskonto des SKR03 verknüpft und erhält eine eindeutige Anlagen-Nummer.
|
||||
|
||||
---
|
||||
|
||||
## Anlagen-Nummernkreis
|
||||
|
||||
Anlagen-Nummern werden automatisch im Format `{Präfix}-{Jahr}-{laufende Nummer}` vergeben, z.B. `ANL-2026-0001`.
|
||||
|
||||
Der Präfix ist unter **Einstellungen → Nummernkreise → Anlagen-Präfix** konfigurierbar (Standard: `ANL`).
|
||||
|
||||
---
|
||||
|
||||
## Anlagenspiegel
|
||||
|
||||
Die Liste unter **Anlagevermögen** zeigt alle erfassten Wirtschaftsgüter mit folgenden Spalten:
|
||||
|
||||
| Spalte | Beschreibung |
|
||||
|---|---|
|
||||
| Nr. | Anlagen-Nummer (automatisch vergeben) |
|
||||
| Anschaffungsdatum | Datum der Anschaffung |
|
||||
| Anlageart | Verknüpftes SKR03-Anlagevermögenskonto |
|
||||
| Wirtschaftsgut | Bezeichnung |
|
||||
| Anschaffungskosten | Nettobetrag der Anschaffung |
|
||||
| Zugänge | Nachträgliche Anschaffungskosten |
|
||||
| Abgänge | Wertminderungen durch Verkauf/Abgang |
|
||||
| Abschreibungen | AfA des laufenden Wirtschaftsjahres |
|
||||
|
||||
Über das Bleistift-Symbol gelangt man zur Bearbeitungsmaske, über das Papierkorb-Symbol kann ein Wirtschaftsgut gelöscht werden (nur wenn keine Buchungen verknüpft sind).
|
||||
|
||||
---
|
||||
|
||||
## Buchungsworkflow
|
||||
|
||||
Wird beim Erfassen einer Buchung ein **Anlagevermögenskonto** als Kategorie gewählt, öffnet sich automatisch ein Dialog:
|
||||
|
||||
**Option 1 – Neues Wirtschaftsgut anlegen**
|
||||
Das System legt automatisch ein neues Anlagegut an:
|
||||
- Bezeichnung ← Buchungstext
|
||||
- Anschaffungsdatum ← Buchungsdatum
|
||||
- Anschaffungskosten ← Nettobetrag
|
||||
|
||||
**Option 2 – Bestehendes Wirtschaftsgut auswählen**
|
||||
Es wird die Liste der Wirtschaftsgüter angezeigt, die mit dem gewählten Anlagevermögenskonto verknüpft sind. Nach der Auswahl wird die Buchung mit dem vorhandenen Anlagegut verknüpft.
|
||||
|
||||
In beiden Fällen wird die `asset_id` in der Buchungszeile gespeichert.
|
||||
|
||||
---
|
||||
|
||||
## Anzeige in Buchungstabellen
|
||||
|
||||
In allen Buchungsübersichten (Beleg-Detail, Journal, UStVA-Drill-down, EÜR-Drill-down) erscheint eine **Anlage**-Spalte. Sie zeigt die Anlagen-Nummer als direkten Link zur Bearbeitungsmaske des Wirtschaftsguts. Falls für ein älteres Wirtschaftsgut keine Anlagen-Nummer hinterlegt ist, wird stattdessen die Bezeichnung angezeigt.
|
||||
|
||||
---
|
||||
|
||||
## Anlagen-Stammdaten bearbeiten
|
||||
|
||||
Folgende Felder können nachträglich angepasst werden:
|
||||
|
||||
- Bezeichnung
|
||||
- Anlageart (SKR03-Konto)
|
||||
- Anschaffungsdatum und -kosten
|
||||
- Zugänge und Abgänge
|
||||
- Abschreibung laufendes Jahr
|
||||
- Nutzungsdauer (in Jahren)
|
||||
- Notizen
|
||||
50
docs/automatisierung.md
Normal file
50
docs/automatisierung.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Automatisierung & Support
|
||||
|
||||
## Automatisierungsagent
|
||||
|
||||
Issues mit dem Label **`automate`** im [Codeberg-Repo](https://codeberg.org/fds2610/Steuerkram/issues) werden automatisch durch einen stündlich per Cron gestarteten Agenten (Claude CLI) verarbeitet. Mehrere offene Tickets werden in einer Sitzung sequenziell abgearbeitet. Ein Lockfile verhindert parallele Läufe.
|
||||
|
||||
### Ablauf je Ticket
|
||||
|
||||
1. Issue-Body und alle Kommentare laden (inkl. Diskussionsergebnisse früherer Rückfragen)
|
||||
2. Relevante Codebase-Dateien lesen
|
||||
3. **Klarheitscheck**: Sind die Anforderungen eindeutig? Falls nicht → Rückfragen als Kommentar posten, `automate`-Label entfernen, warten
|
||||
4. Analyse (Ursache, Lösungsplan, Risiken)
|
||||
5. Lösung implementieren
|
||||
6. Tests ausführen (`php tests/run.php`), Fehler beheben
|
||||
7. Commit & Push: `Fix #NR: Kurzbeschreibung`
|
||||
8. Kommentar mit Zusammenfassung im Issue posten
|
||||
9. Labels aktualisieren, Issue offen lassen
|
||||
|
||||
### Label-Ausgänge
|
||||
|
||||
| Ergebnis | `automate` | gesetztes Label |
|
||||
|---|---|---|
|
||||
| Erfolgreich umgesetzt | entfernt | `testing` |
|
||||
| Unklar / Rückfrage offen | entfernt | *(keins)* |
|
||||
| Zu riskant / abgelehnt | entfernt | `abgelehnt` |
|
||||
|
||||
### Manuell starten
|
||||
|
||||
```bash
|
||||
/home/fds/projects/Steuerkram/.claude/automate-run.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ideenagent
|
||||
|
||||
Ein separater Agent sammelt und bewertet Ideen zur Weiterentwicklung. Er läuft ebenfalls per Cron.
|
||||
|
||||
```bash
|
||||
/home/fds/projects/Steuerkram/.claude/ideenagent-run.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
Issues können im [Codeberg-Repo](https://codeberg.org/fds2610/Steuerkram/issues) gemeldet werden.
|
||||
|
||||
- Mit dem Label **`automate`** werden sie automatisch verarbeitet (siehe oben).
|
||||
- Ohne Label landen sie in der normalen Issue-Queue.
|
||||
284
docs/datenbankstruktur.md
Normal file
284
docs/datenbankstruktur.md
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
# Datenbankstruktur
|
||||
|
||||
MariaDB 11, Engine InnoDB, Zeichensatz `utf8mb4_unicode_ci`. Das Schema wird durch nummerierte Migrations-Dateien in `migrations/` verwaltet und beim Container-Start automatisch eingespielt.
|
||||
|
||||
---
|
||||
|
||||
## Übersicht
|
||||
|
||||
| Tabelle | Zweck |
|
||||
|---|---|
|
||||
| `fiscal_years` | Geschäftsjahre |
|
||||
| `accounts` | Kontenrahmen SKR03 |
|
||||
| `company_settings` | Firmendaten und Einstellungen (Singleton) |
|
||||
| `customers` | Kundenstammdaten |
|
||||
| `belege` | Belegdokumente |
|
||||
| `bookings` | Buchungszeilen (EÜR-Journal) |
|
||||
| `invoices` | Ausgangsrechnungen |
|
||||
| `invoice_lines` | Rechnungspositionen |
|
||||
| `users` | Benutzerkonten |
|
||||
| `ustva_submissions` | UStVA-Einreichungen |
|
||||
| `audit_log` | GoBD-Audit-Log |
|
||||
| `schema_migrations` | Protokoll angewendeter Migrationen |
|
||||
|
||||
---
|
||||
|
||||
## Tabellen im Detail
|
||||
|
||||
### `fiscal_years` – Geschäftsjahre
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `year` | SMALLINT UNSIGNED UNIQUE | Jahreszahl (z.B. 2026) |
|
||||
| `start_date` | DATE | Beginn des Geschäftsjahres |
|
||||
| `end_date` | DATE | Ende des Geschäftsjahres |
|
||||
| `locked` | TINYINT(1) | `1` = Jahr abgeschlossen, keine neuen Buchungen möglich |
|
||||
| `created_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `accounts` – Kontenrahmen SKR03
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `kontonummer` | VARCHAR(10) UNIQUE | DATEV-Kontonummer |
|
||||
| `bezeichnung` | VARCHAR(255) | Kontobezeichnung |
|
||||
| `kontenart` | ENUM | `Betriebseinnahme`, `Betriebsausgabe`, `Anlagevermögen`, `Zahlungskonto`, `Verbindlichkeit`, `Privat` |
|
||||
| `beschreibung` | TEXT | Erläuterungstext |
|
||||
| `steuercode` | VARCHAR(20) | `USt19`, `USt7`, `VSt19`, `VSt7` oder leer |
|
||||
| `ustva_kz` | VARCHAR(10) | ELSTER-Kennzahl (z.B. `81`, `35`) |
|
||||
| `euer_zeile` | VARCHAR(5) | Zeilennummer Anlage EÜR (z.B. `14`, `51`) |
|
||||
| `is_system` | TINYINT(1) | `1` = SKR03-Standardkonto |
|
||||
| `aktiv` | TINYINT(1) | `0` = deaktiviert |
|
||||
| `created_at` / `updated_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `company_settings` – Firmendaten (Singleton, id=1)
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | Immer `1` |
|
||||
| `firma` | VARCHAR(255) | Firmenname |
|
||||
| `inhaber` | VARCHAR(255) | Inhabername |
|
||||
| `strasse`, `plz`, `ort` | VARCHAR | Adresse |
|
||||
| `telefon`, `email`, `website` | VARCHAR | Kontaktdaten |
|
||||
| `ust_id` | VARCHAR(20) | Umsatzsteuer-ID (DE...) |
|
||||
| `steuernummer` | VARCHAR(30) | Steuernummer beim Finanzamt |
|
||||
| `finanzamt` | VARCHAR(255) | Zuständiges Finanzamt |
|
||||
| `iban`, `bic`, `bank_name` | VARCHAR | Bankverbindung |
|
||||
| `logo_path` | VARCHAR(500) | Pfad zum Logo-PNG |
|
||||
| `ustva_steuernummer` | VARCHAR(20) | ELSTER-Format: `FFFBBBBBBUUUUP` |
|
||||
| `ustva_bundesland` | VARCHAR(2) | Bundesland-Kürzel (z.B. `BY`) |
|
||||
| `invoice_nr_prefix` | VARCHAR(10) | Präfix Rechnungsnummer (Standard: `AR`) |
|
||||
| `invoice_nr_next` | INT UNSIGNED | Nächste Rechnungsnummer |
|
||||
| `invoice_nr_year` | SMALLINT UNSIGNED | Jahresstand des Rechnungszählers |
|
||||
| `beleg_nr_prefix` | VARCHAR(10) | Präfix Belegnummer (Standard: `BLG`) |
|
||||
| `beleg_nr_next` | INT UNSIGNED | Nächste Belegnummer |
|
||||
| `anlage_nr_prefix` | VARCHAR(10) | Präfix Anlagen-Nummer (Standard: `ANL`) |
|
||||
| `anlage_nr_next` | INT UNSIGNED | Nächste Anlagen-Nummer |
|
||||
| `payment_days_default` | INT UNSIGNED | Standard-Zahlungsziel in Tagen |
|
||||
| `ki_vorschlag_aktiv` | TINYINT(1) | KI-Kontierungsvorschlag aktiviert |
|
||||
| `nextcloud_url` | VARCHAR(500) | WebDAV-URL der Nextcloud-Instanz |
|
||||
| `nextcloud_user` | VARCHAR(255) | Nextcloud-Benutzername |
|
||||
| `nextcloud_pass` | VARCHAR(500) | Nextcloud-Passwort / App-Passwort |
|
||||
| `nextcloud_folder` | VARCHAR(500) | Import-Quellordner (Standard: `/Belege/Import`) |
|
||||
| `nextcloud_done` | VARCHAR(500) | Zielordner nach erfolgreichem Import |
|
||||
| `updated_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `customers` – Kundenstammdaten
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `kundennummer` | VARCHAR(20) UNIQUE | |
|
||||
| `firma` | VARCHAR(255) | Firmenname (optional) |
|
||||
| `anrede`, `vorname`, `nachname` | VARCHAR | Ansprechpartner |
|
||||
| `strasse`, `plz`, `ort`, `land` | VARCHAR | Adresse |
|
||||
| `email`, `telefon` | VARCHAR | Kontakt |
|
||||
| `ust_id` | VARCHAR(20) | USt-ID des Kunden (B2B) |
|
||||
| `steuernummer` | VARCHAR(30) | |
|
||||
| `payment_days` | INT UNSIGNED | Zahlungsziel in Tagen |
|
||||
| `notes` | TEXT | Interne Notizen |
|
||||
| `archived` | TINYINT(1) | `1` = archiviert |
|
||||
| `created_at` / `updated_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `belege` – Belegdokumente
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `beleg_nr` | VARCHAR(30) UNIQUE | Automatisch vergeben (z.B. `BLG-2026-0001`) |
|
||||
| `filename` | VARCHAR(500) | Originaldateiname |
|
||||
| `storage_path` | VARCHAR(500) | Pfad unter `public/static/uploads/` |
|
||||
| `mime_type` | VARCHAR(100) | MIME-Typ der Datei |
|
||||
| `file_hash` | VARCHAR(64) | SHA-256 für GoBD-Integritätsprüfung |
|
||||
| `beleg_datum` | DATE | Datum auf dem Dokument |
|
||||
| `rechnungs_nr` | VARCHAR(100) | Rechnungsnummer des Lieferanten |
|
||||
| `betrag_brutto` | DECIMAL(12,2) | Bruttobetrag laut Dokument |
|
||||
| `belegtyp` | ENUM | `Eingangsrechnung`, `Ausgangsrechnung`, `Quittung`, `Kontoauszug`, `Sonstiges` |
|
||||
| `notes` | TEXT | Interne Notizen |
|
||||
| `bewirtungsgrund` | TEXT | Anlass der Bewirtung (§ 4 Abs. 5 Nr. 2 EStG) |
|
||||
| `teilnehmerliste` | TEXT | Teilnehmer der Bewirtung |
|
||||
| `eigenanteil_30` | TINYINT(1) | `1` = 30%-Eigenanteil beim Buchen markiert |
|
||||
| `ki_vorschlag` | JSON | KI-Kontierungsvorschlag |
|
||||
| `ki_vorschlag_at` | TIMESTAMP | Zeitpunkt der KI-Analyse |
|
||||
| `beleg_text` | MEDIUMTEXT | Extrahierter OCR-Text |
|
||||
| `locked` | TINYINT(1) | GoBD: mit Geschäftsjahr gesperrt |
|
||||
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
|
||||
| `created_at` / `updated_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `bookings` – Buchungszeilen (EÜR-Journal)
|
||||
|
||||
GoBD-gesichert: MariaDB-Trigger verhindern Änderungen und Löschungen gesperrter Buchungen.
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `buchungs_nr` | VARCHAR(30) UNIQUE | Automatisch vergeben |
|
||||
| `beleg_id` | INT UNSIGNED FK | → `belege.id` |
|
||||
| `asset_id` | INT UNSIGNED FK | → `assets.id` (nur bei Anlagevermögen-Buchungen) |
|
||||
| `buchungs_datum` | DATE | |
|
||||
| `buchungstyp` | ENUM | `Einnahme`, `Ausgabe` |
|
||||
| `kategorie_konto_id` | INT UNSIGNED FK | → `accounts.id` (Was?) |
|
||||
| `zahlungskonto_id` | INT UNSIGNED FK | → `accounts.id` (Wie bezahlt?) |
|
||||
| `betrag_netto` | DECIMAL(12,2) | |
|
||||
| `ust_satz` | DECIMAL(5,2) | Steuersatz in % (0, 7, 19) |
|
||||
| `steuerart` | ENUM | `normal`, `ig_lieferung`, `export`, `ig_erwerb_19`, `ig_erwerb_7` |
|
||||
| `betrag_ust` | DECIMAL(12,2) | |
|
||||
| `betrag_brutto` | DECIMAL(12,2) | |
|
||||
| `buchungstext` | VARCHAR(500) | |
|
||||
| `is_reversal` | TINYINT(1) | `1` = Stornobuchung |
|
||||
| `reversed_by` | INT UNSIGNED | ID der zugehörigen Stornobuchung |
|
||||
| `locked` | TINYINT(1) | GoBD: unveränderlich |
|
||||
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
|
||||
| `created_at` | DATETIME | |
|
||||
|
||||
> **Hinweis:** Die Spalte `asset_id` existiert nur nach Migration 030 (Feature-Branch `Betriebsvermögen`).
|
||||
|
||||
---
|
||||
|
||||
### `assets` – Anlagegüter (Wirtschaftsgüter)
|
||||
|
||||
> Diese Tabelle existiert nur nach Migration 028 (Feature-Branch `Betriebsvermögen`).
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `lfd_nr` | INT UNSIGNED | Laufende Nummer |
|
||||
| `anlage_nr` | VARCHAR(30) | Anlagen-Nummer (z.B. `ANL-2026-0001`) |
|
||||
| `bezeichnung` | VARCHAR(255) | Bezeichnung des Wirtschaftsguts |
|
||||
| `account_id` | INT UNSIGNED FK | → `accounts.id` (Anlageart) |
|
||||
| `anschaffungsdatum` | DATE | |
|
||||
| `anschaffungskosten` | DECIMAL(12,2) | Netto-Anschaffungskosten |
|
||||
| `zugaenge` | DECIMAL(12,2) | Nachträgliche Anschaffungskosten |
|
||||
| `abgaenge` | DECIMAL(12,2) | Wertminderungen |
|
||||
| `abschreibung_jahr` | DECIMAL(12,2) | AfA laufendes Wirtschaftsjahr |
|
||||
| `nutzungsdauer` | INT UNSIGNED | Nutzungsdauer in Jahren |
|
||||
| `notizen` | TEXT | |
|
||||
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
|
||||
| `created_at` / `updated_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `invoices` – Ausgangsrechnungen
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `rechnungs_nr` | VARCHAR(30) UNIQUE | `NULL` solange Entwurf |
|
||||
| `customer_id` | INT UNSIGNED FK | → `customers.id` |
|
||||
| `betreff` | VARCHAR(500) | |
|
||||
| `leistungszeitraum_von` / `_bis` | DATE | |
|
||||
| `rechnungs_datum` | DATE | |
|
||||
| `faellig_datum` | DATE | |
|
||||
| `status` | ENUM | `Entwurf`, `Gesendet`, `Bezahlt`, `Storniert` |
|
||||
| `betrag_netto` / `_ust` / `_brutto` | DECIMAL(12,2) | Summenspalten |
|
||||
| `beleg_id` | INT UNSIGNED FK | → `belege.id` |
|
||||
| `notes` | TEXT | |
|
||||
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
|
||||
| `created_at` / `updated_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `invoice_lines` – Rechnungspositionen
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `invoice_id` | INT UNSIGNED FK | → `invoices.id` (CASCADE DELETE) |
|
||||
| `position` | SMALLINT UNSIGNED | Positionsnummer |
|
||||
| `bezeichnung` | VARCHAR(500) | |
|
||||
| `menge` | DECIMAL(10,3) | |
|
||||
| `einheit` | VARCHAR(20) | z.B. `Stk.`, `h` |
|
||||
| `einzelpreis` | DECIMAL(12,2) | Netto-Einzelpreis |
|
||||
| `ust_satz` | DECIMAL(5,2) | |
|
||||
| `betrag_netto` / `_ust` / `_brutto` | DECIMAL(12,2) | |
|
||||
|
||||
---
|
||||
|
||||
### `users` – Benutzerkonten
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `username` | VARCHAR(64) UNIQUE | |
|
||||
| `password_hash` | VARCHAR(255) | bcrypt |
|
||||
| `active` | TINYINT(1) | `0` = deaktiviert |
|
||||
| `created_at` | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
### `ustva_submissions` – UStVA-Einreichungen
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | INT UNSIGNED PK | |
|
||||
| `year` | SMALLINT UNSIGNED | Meldejahr |
|
||||
| `month` | TINYINT UNSIGNED | Meldemonat (1–12) |
|
||||
| `xml_content` | MEDIUMTEXT | Generiertes ELSTER-XML |
|
||||
| `field_values` | JSON | Kennzahlen als JSON |
|
||||
| `submitted_at` | DATETIME | `NULL` = noch nicht eingereicht |
|
||||
| `status` | ENUM | `Erstellt`, `Eingereicht` |
|
||||
| `created_at` | DATETIME | |
|
||||
|
||||
UNIQUE KEY auf `(year, month)`.
|
||||
|
||||
---
|
||||
|
||||
### `audit_log` – GoBD-Audit-Log
|
||||
|
||||
| Spalte | Typ | Beschreibung |
|
||||
|---|---|---|
|
||||
| `id` | BIGINT UNSIGNED PK | |
|
||||
| `timestamp` | DATETIME | |
|
||||
| `table_name` | VARCHAR(50) | Betroffene Tabelle |
|
||||
| `record_id` | INT UNSIGNED | Betroffener Datensatz |
|
||||
| `action` | ENUM | `INSERT`, `UPDATE`, `DELETE`, `LOCK` |
|
||||
| `old_values` | JSON | Werte vor der Änderung |
|
||||
| `new_values` | JSON | Werte nach der Änderung |
|
||||
| `ip_address` | VARCHAR(45) | |
|
||||
| `user_agent` | VARCHAR(500) | |
|
||||
|
||||
---
|
||||
|
||||
## GoBD-Mechanismen
|
||||
|
||||
- **Trigger `bookings_before_update` / `bookings_before_delete`**: Jeder Versuch, eine gesperrte Buchung (`locked = 1`) zu ändern oder zu löschen, wird mit einem SQL-Fehler abgewiesen.
|
||||
- **`file_hash` in `belege`**: SHA-256-Prüfsumme jedes Belegdokuments; erlaubt nachträgliche Integritätsprüfung.
|
||||
- **`audit_log`**: Protokolliert alle Datenbankänderungen mit alten und neuen Werten.
|
||||
- **Stornobuchungen** statt Löschungen: Korrekturen erzeugen eine Gegenbuchung, die ursprüngliche Buchung bleibt erhalten.
|
||||
|
||||
---
|
||||
|
||||
## Migrationen
|
||||
|
||||
Schemaänderungen kommen ausschließlich als nummerierte SQL-Dateien in `migrations/` und werden vom Script `scripts/migrate.php` beim Container-Start automatisch eingespielt. Die Tabelle `schema_migrations` protokolliert, welche Dateien bereits angewendet wurden.
|
||||
91
docs/funktionen.md
Normal file
91
docs/funktionen.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Funktionen
|
||||
|
||||
## Kontenrahmen SKR03
|
||||
|
||||
DATEV-konformer SKR03 2026 mit 157 Systemkonten (Klassen 0, 1, 2, 4, 8), zugeschnitten auf EÜR-Buchhalter ohne Bilanzierungspflicht. Alle Konten sind mit geprüften UStVA-Kennzahlen (ELSTER) und EÜR-Zeilennummern hinterlegt.
|
||||
|
||||
Vollständige Kontenliste: [kontenrahmen.md](kontenrahmen.md)
|
||||
|
||||
---
|
||||
|
||||
## Belegverwaltung
|
||||
|
||||
- Upload von PDF, PNG, JPEG, TIFF und ZUGFeRD-XML
|
||||
- SHA-256 Integritätsprüfung je Datei
|
||||
- Automatischer Weißrand-Zuschnitt bei JPEG/PNG via GD
|
||||
- KI-gestützter Kontierungsvorschlag (optional, siehe [konfiguration.md](konfiguration.md))
|
||||
- Nextcloud-Import via WebDAV (optional)
|
||||
- Belege können nicht gelöscht werden, solange Buchungen darauf verweisen (GoBD)
|
||||
|
||||
---
|
||||
|
||||
## Buchungen
|
||||
|
||||
EÜR-Buchungsmodell (Einnahme/Ausgabe) mit Kategorie- und Zahlungskonto.
|
||||
|
||||
- **Steuerarten** für Auslandsumsätze: Inland, steuerfreie ig. Lieferung (Kz 41), steuerfreie Ausfuhr (Kz 44), ig. Erwerb 19 % (Kz 89/91), ig. Erwerb 7 % (Kz 93/94)
|
||||
- **Bewirtungsausgaben**: automatischer Split 70 %/30 % bei Konten 4650, 4651, 4652
|
||||
- **Eigenanteil** (30 %) bei Telefon/Internet (Konto 4940): optional zubuchbar
|
||||
- **Stornobuchungen**: GoBD-konforme Gegenbuchung statt Löschung
|
||||
- **GoBD-Schutz**: MariaDB `BEFORE UPDATE/DELETE`-Trigger verhindern nachträgliche Manipulation gebuchter Sätze
|
||||
- **Journal**: gefilterte Übersicht aller Buchungen mit CSV-Export
|
||||
|
||||
---
|
||||
|
||||
## Anlagevermögen
|
||||
|
||||
Anlagenspiegel für abnutzbare Wirtschaftsgüter – siehe [anlagevermögen.md](anlagevermögen.md).
|
||||
|
||||
---
|
||||
|
||||
## Kundenverwaltung
|
||||
|
||||
CRUD für Kundenstammdaten. Kunden werden beim Erstellen von Ausgangsrechnungen ausgewählt.
|
||||
|
||||
---
|
||||
|
||||
## Ausgangsrechnungen
|
||||
|
||||
- DIN 5008-konformes Layout
|
||||
- PDF-Export via mPDF
|
||||
- Automatische Rechnungsnummer (konfiguriertes Präfix + Jahrgang + laufende Nummer)
|
||||
- Direkte Verknüpfung mit Belegverwaltung
|
||||
|
||||
---
|
||||
|
||||
## UStVA (Umsatzsteuervoranmeldung)
|
||||
|
||||
- Monatliche Kennzahlen-Berechnung aus Buchungen (Kz 81, 83, 86, 84, 35, 41, 44, 61, 62, 67, 66, 69)
|
||||
- ELSTER XML-Export
|
||||
- Drill-down: Klick auf eine Kennzahl zeigt alle zugehörigen Buchungszeilen
|
||||
|
||||
Zuordnungsregeln: [berechnungslogik.md](berechnungslogik.md)
|
||||
|
||||
---
|
||||
|
||||
## EÜR (Einnahmen-Überschuss-Rechnung)
|
||||
|
||||
- Jahresauswertung: Einnahmen, Ausgaben, Gewinn je Kategorie-Konto
|
||||
- Nicht abzugsfähige Betriebsausgaben (§ 4 Abs. 5 EStG, EÜR-Zeile 51) in separatem Abschnitt
|
||||
- PDF-Export
|
||||
- Drill-down: Klick auf ein Konto zeigt alle zugehörigen Buchungszeilen
|
||||
|
||||
Zuordnungsregeln: [berechnungslogik.md](berechnungslogik.md)
|
||||
|
||||
---
|
||||
|
||||
## Einstellungen
|
||||
|
||||
- Firmendaten und Logo (erscheinen auf Rechnungen und im EÜR/UStVA-Export)
|
||||
- ELSTER-Steuernummer
|
||||
- Nummernkreis-Präfixe für Belege, Rechnungen und Anlagen
|
||||
- KI-Kontierungsvorschlag (Ollama oder OpenAI-kompatible API)
|
||||
- Nextcloud-Belegimport (WebDAV-Zugangsdaten)
|
||||
|
||||
---
|
||||
|
||||
## Benutzerverwaltung
|
||||
|
||||
- Benutzer anlegen, bearbeiten, deaktivieren und löschen
|
||||
- Session-basierte Authentifizierung mit 24 h Timeout
|
||||
- Erste Benutzeranlage über Ersteinrichtungs-Dialog beim ersten Aufruf
|
||||
139
docs/installation.md
Normal file
139
docs/installation.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# Installation
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/) ≥ 24
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/) ≥ 2.20 (in neueren Docker-Versionen enthalten)
|
||||
- Git
|
||||
|
||||
---
|
||||
|
||||
## Automatische Installation
|
||||
|
||||
Das Script `install.sh` übernimmt die gesamte Installation: es erkennt die Linux-Distribution, installiert git, curl und Docker, klont das Repository in das gewünschte Verzeichnis und legt die `.env`-Datei an.
|
||||
|
||||
Das Script muss **vor** dem Klonen des Repositories heruntergeladen werden – es erledigt das Klonen selbst:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://codeberg.org/fds2610/Steuerkram/raw/branch/main/install.sh -o install.sh
|
||||
sudo bash install.sh
|
||||
```
|
||||
|
||||
> Das Script muss als root ausgeführt werden, da es Pakete installiert und ggf. den Docker-Dienst aktiviert.
|
||||
|
||||
Nach der Installation die `.env`-Datei im gewählten Installationsverzeichnis anpassen und die Container starten:
|
||||
|
||||
```bash
|
||||
cd /opt/Steuerkram # oder das gewählte Verzeichnis
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manuelle Installation
|
||||
|
||||
### 1. Repository klonen
|
||||
|
||||
```bash
|
||||
git clone <repository-url> steuerkram
|
||||
cd steuerkram
|
||||
```
|
||||
|
||||
### 2. Konfiguration anpassen
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
```dotenv
|
||||
DB_PASS=sicheres-passwort # Datenbankpasswort – in docker-compose.yml spiegeln
|
||||
```
|
||||
|
||||
Außerdem in `docker-compose.yml` das `MARIADB_PASSWORD` im `db`-Service auf denselben Wert wie `DB_PASS` setzen.
|
||||
|
||||
### 3. Container starten
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Beim ersten Start werden automatisch:
|
||||
- die Datenbank initialisiert
|
||||
- der SKR03-Kontenrahmen eingespielt
|
||||
- das Docker-Image mit PHP-Abhängigkeiten (mPDF) gebaut
|
||||
|
||||
### 4. Anwendung aufrufen
|
||||
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
Beim ersten Aufruf erscheint die **Ersteinrichtung**: dort den ersten Benutzer-Account anlegen. Danach ist die Anwendung passwortgeschützt.
|
||||
|
||||
---
|
||||
|
||||
## Port ändern
|
||||
|
||||
Der Standard-Port ist `8080`. Um ihn zu ändern, die `ports`-Zeile in `docker-compose.yml` anpassen:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "9090:80" # Beispiel: Port 9090 auf dem Host
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Upload-Limit anpassen
|
||||
|
||||
Die maximale Dateigröße für Beleganhänge ist auf **20 MB** voreingestellt (`php/uploads.ini`). Um das Limit zu ändern:
|
||||
|
||||
```ini
|
||||
upload_max_filesize = 20M
|
||||
post_max_size = 20M
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Systemd-Service einrichten
|
||||
|
||||
Damit Steuerkram automatisch beim Systemstart startet, liegt im Repository die Datei `steuerkram.service`.
|
||||
|
||||
### 1. Service-Datei installieren
|
||||
|
||||
```bash
|
||||
sudo cp steuerkram.service /etc/systemd/system/steuerkram.service
|
||||
```
|
||||
|
||||
Die Datei setzt `WorkingDirectory=/opt/Steuerkram` voraus. Falls das Repository woanders liegt, den Pfad anpassen:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/steuerkram.service
|
||||
```
|
||||
|
||||
### 2. Service aktivieren und starten
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable steuerkram
|
||||
sudo systemctl start steuerkram
|
||||
```
|
||||
|
||||
### 3. Status prüfen
|
||||
|
||||
```bash
|
||||
sudo systemctl status steuerkram
|
||||
journalctl -u steuerkram -f # Live-Log inkl. Migrations-Ausgabe
|
||||
```
|
||||
|
||||
### Wichtige Befehle
|
||||
|
||||
| Befehl | Wirkung |
|
||||
|---|---|
|
||||
| `sudo systemctl start steuerkram` | Container starten |
|
||||
| `sudo systemctl stop steuerkram` | Container stoppen |
|
||||
| `sudo systemctl restart steuerkram` | Neustart (z.B. nach Update) |
|
||||
| `sudo systemctl status steuerkram` | Aktueller Status |
|
||||
88
docs/konfiguration.md
Normal file
88
docs/konfiguration.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Konfiguration
|
||||
|
||||
## Firmendaten hinterlegen
|
||||
|
||||
Nach dem ersten Login unter **Einstellungen** Firmendaten, Logo und ELSTER-Steuernummer eintragen. Diese Angaben erscheinen auf Ausgangsrechnungen und im EÜR/UStVA-Export.
|
||||
|
||||
---
|
||||
|
||||
## Nummernkreise
|
||||
|
||||
Unter **Einstellungen → Nummernkreise** können Präfixe für die automatisch vergebenen Nummern konfiguriert werden:
|
||||
|
||||
| Nummernkreis | Standard | Beispiel |
|
||||
|---|---|---|
|
||||
| Belege | `BLG` | `BLG-2026-0001` |
|
||||
| Ausgangsrechnungen | `RE` | `RE-2026-0001` |
|
||||
| Anlagen | `ANL` | `ANL-2026-0001` |
|
||||
|
||||
Das Format ist immer `{Präfix}-{Jahr}-{laufende Nummer}`. Die laufende Nummer wird automatisch hochgezählt und kann nicht zurückgesetzt werden (GoBD).
|
||||
|
||||
---
|
||||
|
||||
## KI-Beleganalyse einrichten
|
||||
|
||||
Die KI-gestützte Belegerkennung ist standardmäßig deaktiviert. Sie kann unter **Einstellungen → KI-Kontierungsvorschlag** aktiviert werden, sobald ein LLM erreichbar ist.
|
||||
|
||||
### Option A – Lokales Ollama
|
||||
|
||||
Kein API-Schlüssel nötig, aber hoher Ressourcenbedarf:
|
||||
|
||||
```bash
|
||||
ollama pull mistral # oder llama3.2 etc.
|
||||
```
|
||||
|
||||
In `.env` ist keine weitere Konfiguration nötig – die App erkennt Ollama auf `localhost:11434` automatisch. Modell und URL können optional überschrieben werden:
|
||||
|
||||
```dotenv
|
||||
OLLAMA_URL=http://localhost:11434
|
||||
OLLAMA_MODEL=mistral
|
||||
```
|
||||
|
||||
### Option B – Remote-API (OpenAI-kompatibel)
|
||||
|
||||
z.B. OpenAI, OpenRouter, LM Studio:
|
||||
|
||||
```dotenv
|
||||
LLM_API_URL=https://api.openai.com/v1
|
||||
LLM_API_KEY=sk-...
|
||||
LLM_MODEL=gpt-4o-mini
|
||||
```
|
||||
|
||||
> **Hinweis:** Die Ergebnisqualität hängt stark vom gewählten Modell ab. Tests mit `mistral` (lokal via Ollama) lieferten bisher mäßige Ergebnisse.
|
||||
|
||||
---
|
||||
|
||||
## Nextcloud-Import einrichten
|
||||
|
||||
Belege können automatisch aus einem Nextcloud-Ordner via WebDAV importiert werden. Das CLI-Skript `scripts/nextcloud-import.php` liest alle unterstützten Dateien (PDF, JPEG, PNG, TIFF, XML) aus dem konfigurierten Ordner, legt sie als Belege an und verschiebt sie anschließend in einen Erledigte-Ordner.
|
||||
|
||||
### Zugangsdaten konfigurieren
|
||||
|
||||
Die Zugangsdaten werden in der Steuerkram-UI gepflegt: **Einstellungen → Nextcloud-Belegimport**.
|
||||
|
||||
Empfehlung: Ein Nextcloud-App-Passwort verwenden (Nextcloud → Einstellungen → Sicherheit → App-Passwörter).
|
||||
|
||||
### Manueller Aufruf
|
||||
|
||||
```bash
|
||||
docker compose exec web php scripts/nextcloud-import.php
|
||||
```
|
||||
|
||||
### Automatisch per Cron
|
||||
|
||||
Cron-Eintrag auf dem Host anlegen (`crontab -e`):
|
||||
|
||||
```cron
|
||||
*/15 * * * * docker compose -f /opt/Steuerkram/docker-compose.yml exec -T web \
|
||||
php scripts/nextcloud-import.php >> /var/log/steuerkram-import.log 2>&1
|
||||
```
|
||||
|
||||
> Das `-T`-Flag ist bei Cron zwingend erforderlich – ohne TTY schlägt `docker compose exec` sonst still fehl.
|
||||
|
||||
Damit `docker compose exec` ohne `sudo` funktioniert, muss der User in der Docker-Gruppe sein:
|
||||
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
# Danach neu einloggen
|
||||
```
|
||||
106
docs/update-backup.md
Normal file
106
docs/update-backup.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Update & Backup
|
||||
|
||||
## Backup
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
```
|
||||
|
||||
Das Skript erstellt einen Dump der Datenbank sowie ein Archiv der Uploads im Verzeichnis `backups/`. Die Rotation erfolgt nach folgendem Schema:
|
||||
|
||||
- 7 Tages-Backups
|
||||
- 4 Wochen-Backups
|
||||
- 12 Monats-Backups
|
||||
|
||||
Ein `flock`-Lock verhindert parallele Läufe bei Verzögerungen.
|
||||
|
||||
### Manuelles Backup
|
||||
|
||||
```bash
|
||||
docker compose exec db mariadb-dump -u steuerkram -psteuerkram steuerkram \
|
||||
> ~/steuerkram_backup_$(date +%Y%m%d_%H%M).sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Datenpersistenz
|
||||
|
||||
| Pfad | Inhalt |
|
||||
|---|---|
|
||||
| `./data/mariadb/` | MariaDB-Datenbankdateien |
|
||||
| Docker Volume `uploads` | Hochgeladene Belege |
|
||||
|
||||
Beide Pfade liegen außerhalb des Containers und bleiben bei `docker compose down` erhalten.
|
||||
|
||||
---
|
||||
|
||||
## Update
|
||||
|
||||
Datenbankmigrationen werden **automatisch** beim nächsten Container-Start eingespielt. Das Script `scripts/migrate.php` prüft beim Start, welche Migrations-Dateien noch nicht angewendet wurden, und führt sie der Reihe nach aus.
|
||||
|
||||
### Vollständige Update-Anleitung
|
||||
|
||||
#### Schritt 1 – Datenbank sichern
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh
|
||||
```
|
||||
|
||||
#### Schritt 2 – Aktuellen Code holen
|
||||
|
||||
```bash
|
||||
git pull
|
||||
```
|
||||
|
||||
#### Schritt 3 – Container neu bauen und starten
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Dieser Befehl baut das PHP-Image neu (falls sich `Dockerfile` oder `composer.json` geändert haben) und startet alle Container. Der Web-Container führt beim Start automatisch `scripts/migrate.php` aus.
|
||||
|
||||
#### Schritt 4 – Migrationen prüfen
|
||||
|
||||
```bash
|
||||
docker compose logs web | grep migrate
|
||||
```
|
||||
|
||||
Erwartete Ausgabe:
|
||||
|
||||
```
|
||||
[migrate] Starte Migrations-Prüfung...
|
||||
[migrate] Führe aus: NNN_beschreibung.sql
|
||||
[migrate] N Migration(en) erfolgreich angewendet.
|
||||
```
|
||||
|
||||
Falls ein Fehler auftritt, das Backup aus Schritt 1 einspielen:
|
||||
|
||||
```bash
|
||||
docker compose exec -T db mariadb -u steuerkram -psteuerkram steuerkram \
|
||||
< ~/steuerkram_backup_YYYYMMDD_HHMM.sql
|
||||
```
|
||||
|
||||
#### Schritt 5 – Anwendung prüfen
|
||||
|
||||
```bash
|
||||
docker compose ps # alle Container müssen "running" sein
|
||||
docker compose logs web # keine PHP-Fehler oder Exceptions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Kurzform ohne Systemd
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh && git pull && docker compose up -d --build
|
||||
docker compose logs web | grep migrate
|
||||
```
|
||||
|
||||
### Kurzform mit Systemd
|
||||
|
||||
```bash
|
||||
bash scripts/backup.sh && git pull && docker compose build
|
||||
sudo systemctl restart steuerkram
|
||||
journalctl -u steuerkram | grep migrate
|
||||
```
|
||||
|
|
@ -15,7 +15,6 @@ class Config
|
|||
'db_name' => $_ENV['DB_NAME'] ?? getenv('DB_NAME') ?: 'steuerkram',
|
||||
'db_user' => $_ENV['DB_USER'] ?? getenv('DB_USER') ?: 'steuerkram',
|
||||
'db_pass' => $_ENV['DB_PASS'] ?? getenv('DB_PASS') ?: 'steuerkram',
|
||||
'app_secret' => $_ENV['APP_SECRET'] ?? getenv('APP_SECRET') ?: 'dev-secret',
|
||||
'upload_dir' => dirname(__DIR__) . '/public/static/uploads',
|
||||
'base_url' => '',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -18,17 +18,16 @@ class BelegUploadTest extends TestCase
|
|||
$datum = date('Y-m-d');
|
||||
|
||||
$id = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => $belegNr,
|
||||
'filename' => 'test-rechnung.pdf',
|
||||
'storage_path' => 'static/uploads/test/test-rechnung.pdf',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', $belegNr),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'rechnungs_nr' => 'RE-TEST-001',
|
||||
'betrag_brutto' => 119.00,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
'notes' => 'Automatisch erstellt (Test)',
|
||||
'beleg_nr' => $belegNr,
|
||||
'filename' => 'test-rechnung.pdf',
|
||||
'storage_path' => 'static/uploads/test/test-rechnung.pdf',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', $belegNr),
|
||||
'beleg_datum' => $datum,
|
||||
'rechnungs_nr' => 'RE-TEST-001',
|
||||
'betrag_brutto' => 119.00,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
'notes' => 'Automatisch erstellt (Test)',
|
||||
]);
|
||||
|
||||
$this->assertGreaterThan(0, $id, 'Beleg wurde in der DB angelegt (ID > 0)');
|
||||
|
|
@ -51,7 +50,8 @@ class BelegUploadTest extends TestCase
|
|||
$this->assert($found, 'Beleg erscheint in Beleg::all() (Belegübersicht)');
|
||||
$this->assertGreaterThan(0, $result['total'], 'Belegübersicht enthält mindestens 1 Eintrag');
|
||||
|
||||
// Betrag korrekt gespeichert
|
||||
$this->assertEquals(119.00, (float)($beleg['betrag_brutto'] ?? 0), 'Betrag brutto korrekt gespeichert');
|
||||
// Betrag korrekt gespeichert (direkt aus belege, nicht die berechnete Buchungssumme)
|
||||
$raw = \Steuerkram\Database::fetchOne('SELECT betrag_brutto FROM belege WHERE id = ?', [$id]);
|
||||
$this->assertEquals(119.00, (float)($raw['betrag_brutto'] ?? 0), 'Betrag brutto korrekt gespeichert');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ class KontierungsvorschlagTest extends TestCase
|
|||
private function createTestBeleg(): int
|
||||
{
|
||||
Database::execute(
|
||||
"INSERT INTO belege (beleg_nr, filename, storage_path, mime_type, file_hash, eingangs_datum, belegtyp)
|
||||
"INSERT INTO belege (beleg_nr, filename, storage_path, mime_type, file_hash, belegtyp)
|
||||
VALUES ('TEST-KI-0001', 'test.pdf', 'static/uploads/test/test.pdf', 'application/pdf',
|
||||
SHA2('test', 256), CURDATE(), 'Eingangsrechnung')"
|
||||
SHA2('test', 256), 'Eingangsrechnung')"
|
||||
);
|
||||
return (int)Database::lastInsertId();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,15 +31,18 @@ class BewirtungssplitTest extends TestCase
|
|||
|
||||
// ── Test 1: Split bei Konto 4650 ─────────────────────────────
|
||||
$beleg1 = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-BEW-4650-' . uniqid(),
|
||||
'filename' => 'test.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'bew4650' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
'beleg_nr' => 'TEST-BEW-4650-' . uniqid(),
|
||||
'filename' => 'test.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'bew4650' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
\Steuerkram\Database::execute(
|
||||
'UPDATE belege SET bewirtungsgrund = ?, teilnehmerliste = ? WHERE id = ?',
|
||||
['Kundengespräch', 'Max Mustermann, Erika Mustermann', $beleg1]
|
||||
);
|
||||
|
||||
// Bewirtungssplit direkt über Booking::create + zweite Buchung simulieren
|
||||
// (wie BookingController::bucheBewirtungssplit() es tut)
|
||||
|
|
@ -57,8 +60,6 @@ class BewirtungssplitTest extends TestCase
|
|||
'betrag_netto' => $netto70,
|
||||
'ust_satz' => $ustSatz,
|
||||
'buchungstext' => 'Bewirtung Test 70%',
|
||||
'bewirtungsgrund' => 'Kundengespräch',
|
||||
'teilnehmerliste' => 'Max Mustermann, Erika Mustermann',
|
||||
]);
|
||||
|
||||
$id1b = \Steuerkram\Models\Booking::create([
|
||||
|
|
@ -70,8 +71,6 @@ class BewirtungssplitTest extends TestCase
|
|||
'betrag_netto' => $netto30,
|
||||
'ust_satz' => $ustSatz,
|
||||
'buchungstext' => 'Bewirtung Test 30%',
|
||||
'bewirtungsgrund' => 'Kundengespräch',
|
||||
'teilnehmerliste' => 'Max Mustermann, Erika Mustermann',
|
||||
]);
|
||||
|
||||
$b1a = \Steuerkram\Models\Booking::find($id1a);
|
||||
|
|
@ -95,20 +94,20 @@ class BewirtungssplitTest extends TestCase
|
|||
'Gesamt-Vorsteuer korrekt (100% des Nettobetrags)'
|
||||
);
|
||||
|
||||
// Bewirtungsfelder gespeichert
|
||||
$this->assertEquals('Kundengespräch', $b1a['bewirtungsgrund'], 'Bewirtungsgrund gespeichert');
|
||||
$this->assertEquals('Max Mustermann, Erika Mustermann', $b1a['teilnehmerliste'], 'Teilnehmerliste gespeichert');
|
||||
// Bewirtungsfelder auf dem Beleg gespeichert (seit Migration 024 in belege, nicht bookings)
|
||||
$belegDaten = \Steuerkram\Models\Beleg::find($beleg1);
|
||||
$this->assertEquals('Kundengespräch', $belegDaten['bewirtungsgrund'], 'Bewirtungsgrund gespeichert');
|
||||
$this->assertEquals('Max Mustermann, Erika Mustermann', $belegDaten['teilnehmerliste'], 'Teilnehmerliste gespeichert');
|
||||
|
||||
// ── Test 2: Split bei Konto 4651 ─────────────────────────────
|
||||
$beleg2 = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-BEW-4651-' . uniqid(),
|
||||
'filename' => 'test2.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'bew4651' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
'beleg_nr' => 'TEST-BEW-4651-' . uniqid(),
|
||||
'filename' => 'test2.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'bew4651' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
|
||||
$id2a = \Steuerkram\Models\Booking::create([
|
||||
|
|
@ -149,14 +148,13 @@ class BewirtungssplitTest extends TestCase
|
|||
$bankCheck = $this->findAccountId('4600');
|
||||
if ($bankCheck) {
|
||||
$beleg3 = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-BEW-NORMAL-' . uniqid(),
|
||||
'filename' => 'test3.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'normal' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
'beleg_nr' => 'TEST-BEW-NORMAL-' . uniqid(),
|
||||
'filename' => 'test3.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'normal' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
|
||||
$idNormal = \Steuerkram\Models\Booking::create([
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class AutomatikkontenUstTest extends TestCase
|
|||
$mapping = ['VSt19' => 19, 'USt19' => 19, 'VSt7' => 7, 'USt7' => 7];
|
||||
|
||||
$kontenMitSteuercode = \Steuerkram\Database::fetchAll(
|
||||
"SELECT kontonummer, steuercode FROM accounts WHERE steuercode IS NOT NULL LIMIT 20"
|
||||
"SELECT kontonummer, steuercode FROM accounts WHERE steuercode IS NOT NULL AND steuercode != '' LIMIT 20"
|
||||
);
|
||||
$this->assertNotEmpty($kontenMitSteuercode, 'Konten mit Steuercode vorhanden');
|
||||
|
||||
|
|
@ -60,14 +60,13 @@ class AutomatikkontenUstTest extends TestCase
|
|||
}
|
||||
|
||||
$belegId = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-AUTOUST-' . uniqid(),
|
||||
'filename' => 'test.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'autoust' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
'beleg_nr' => 'TEST-AUTOUST-' . uniqid(),
|
||||
'filename' => 'test.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'autoust' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
|
||||
$bookingId = \Steuerkram\Models\Booking::create([
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue