Feature: Rechnungs-System (invoices) — Backend komplett

- DB-Migration: invoices + invoice_items Tabellen inkl. Indizes
- routes/invoices.py: vollständiger Admin-Router (prefix /api/admin/invoices)
  - CRUD: Liste, Detail, Erstellen, Senden, Bezahlen, Stornieren
  - PDF-Generierung via fpdf2 mit §14-UStG-Pflichtangaben (Kleinunternehmer-Hinweis)
  - Cashflow-Übersicht und Quartalsbericht
  - PDF-Download-Endpunkt
  - Speicherung in /scaninput + optionaler Paperless-Upload
- mailer.py: send_email() + Backends um optionale PDF-Anhänge erweitert
  (Brevo: base64, SMTP: MIMEApplication)
- main.py: invoices_router registriert
- docker-compose.yml: /volume1/scaninput:/scaninput Volume hinzugefügt
This commit is contained in:
rene 2026-05-15 10:04:23 +02:00
parent 9c359bb07e
commit b68a12587a
5 changed files with 570 additions and 10 deletions

View file

@ -2398,6 +2398,52 @@ def _migrate(conn_factory):
except Exception as e:
logger.warning(f"Migration route_dogs fehlgeschlagen: {e}")
# Rechnungs-System
try:
conn.execute("""
CREATE TABLE IF NOT EXISTS invoices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
invoice_number TEXT NOT NULL UNIQUE,
user_id INTEGER REFERENCES users(id),
recipient_name TEXT NOT NULL,
recipient_email TEXT NOT NULL,
recipient_address TEXT,
description TEXT NOT NULL,
service_period TEXT,
amount_net REAL NOT NULL,
discount_pct REAL DEFAULT 0,
discount_amount REAL DEFAULT 0,
amount_after_discount REAL NOT NULL,
tax_rate REAL DEFAULT 0,
tax_amount REAL DEFAULT 0,
amount_gross REAL NOT NULL,
status TEXT DEFAULT 'draft',
notes TEXT,
created_at TEXT DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
sent_at TEXT,
paid_at TEXT,
paid_amount REAL,
cancelled_at TEXT,
cancellation_reason TEXT,
cancellation_number TEXT
)
""")
conn.execute("CREATE INDEX IF NOT EXISTS idx_invoices_status ON invoices(status)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_invoices_user ON invoices(user_id)")
conn.execute("""
CREATE TABLE IF NOT EXISTS invoice_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
invoice_id INTEGER NOT NULL REFERENCES invoices(id) ON DELETE CASCADE,
description TEXT NOT NULL,
quantity REAL NOT NULL DEFAULT 1,
unit_price REAL NOT NULL,
total REAL NOT NULL
)
""")
logger.info("Migration: invoices + invoice_items bereit.")
except Exception as e:
logger.warning(f"Migration invoices: {e}")
def _seed_help_articles(conn):
"""Befüllt help_articles mit Starter-FAQs — nur wenn die Tabelle noch leer ist."""