Mehrere Positionen pro Auftrag und Projektverwaltung

Bisher liess sich pro Rechnung nur ein Teil kalkulieren. Ein Objekt aus
mehreren Teilen musste in getrennten Rechnungen abgebildet werden.

Positionen:
- Die Kalkulation arbeitet mit einer Positionsliste statt einem
  Einzelteil. Bezeichnung, Material, Preis/kg, Druckzeit, Arbeitszeit
  und Stueckzahl gelten je Position -- verschiedene Teile nutzen oft
  unterschiedliche Filamente und brauchen unterschiedlich viel Nacharbeit.
- Drucker, Strom, Stundenlohn, Marge und Steuer bleiben auftragsweit.
- Jede Position wird eine eigene Rechnungszeile mit Menge, Einzelpreis
  und Zeilensumme. Bei vielen Positionen bricht das PDF auf weitere
  Seiten um.
- Die Auftragssumme ist die Summe der bereits gerundeten Zeilen, damit
  die Rechnung zeilenweise nachrechenbar bleibt.
- saubere_positionen() normalisiert jede Liste aus Config oder Client
  (Typen, Wertebereiche, Obergrenze 50); es bleibt immer mindestens
  eine Position bestehen.
- Alte Configs mit den Flachfeldern werden in eine einzelne Position
  migriert, die Altfelder entfernt.
- sammlePositionen() liefert null auf Seiten ohne Positionsliste, damit
  ein Tastendruck auf der Einstellungs- oder Rechnungsseite die
  Positionen nicht loescht.

Projekte:
- Benannte Kalkulationen lassen sich speichern und wieder laden,
  Ablage in druckkalkulation_projekte.yaml (ein Mapping fuer alle
  Projekte, Schluessel ist der Projektname).
- Gesichert werden nur PROJEKT_FELDER: Name, Positionen, Kundendaten,
  Rechnungsnummer, Rechnungs- und Leistungsdatum. Betriebswerte gehoeren
  bewusst nicht dazu -- sonst wuerde das Laden eines alten Projekts den
  aktuellen Stundenlohn oder das Steuerregime ueberschreiben.
- Neue Routen: GET /projekte sowie POST /projekte/{speichern,laden,loeschen}.
- Eigenes Lock, gleiche atomare Schreibtechnik wie die Config.
- Ueberschreiben, Laden bei ungespeicherten Aenderungen und Loeschen
  fragen jeweils nach.
- Der offene Autosave-Debounce wird vor dem Speichern durchgedrueckt,
  damit wirklich der aktuelle Stand ins Projekt geht.

Die beiden Teile stehen in einem Commit, weil die Aenderungen in app.py,
script.js und index.html ineinandergreifen und ein aufgetrennter
Zwischenstand nicht als solcher getestet wurde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik Thiele
2026-08-22 11:38:26 +02:00
parent b6e5a59daa
commit c42fecacb9
7 changed files with 762 additions and 182 deletions

View File

@@ -29,6 +29,14 @@ sich ueber `HOST` und `PORT` ueberschreiben.
## Funktionen
- **Mehrere Positionen pro Auftrag** — ein Objekt aus mehreren Teilen wird als
Positionsliste kalkuliert und als eigene Rechnungszeilen ausgewiesen.
Material, Preis/kg, Druckzeit, Arbeitszeit und Stückzahl gelten je Position;
Drucker, Strom, Stundenlohn, Marge und Steuer gelten für den ganzen Auftrag.
- **Projekte speichern und laden** — benannte Kalkulationen bleiben erhalten
und lassen sich jederzeit wieder aufrufen (`druckkalkulation_projekte.yaml`).
Betriebswerte (Drucker, Strom, Stundenlohn, Marge, Steuer) gehören *nicht*
zum Projekt und bleiben beim Laden unangetastet.
- **Live-Berechnung** bei jeder Eingabe (Material, Strom, Abschreibung, Arbeit, Gewinn)
- **Dark Mode** (persistiert in YAML-Konfiguration)
- **PDF-Rechnung** mit Logo, Kundendaten und Positionstabelle (via fpdf2)
@@ -112,7 +120,8 @@ static/style.css # Minimales Custom-CSS
static/script.js # Live-Berechnung + Auto-Save
proxmox-setup.sh # Ersteinrichtung LXC-Container
proxmox-update.sh # Update LXC-Container
druckkalkulation_config.yaml # Automatisch erstellte Konfiguration (ignoriert)
druckkalkulation_config.yaml # Aktueller Arbeitsstand (ignoriert)
druckkalkulation_projekte.yaml # Gespeicherte Projekte (ignoriert)
```
## Routen
@@ -120,12 +129,16 @@ druckkalkulation_config.yaml # Automatisch erstellte Konfiguration (ignoriert)
| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/` | Hauptseite mit Formular |
| POST | `/calculate` | JSON-Berechnung (AJAX) |
| POST | `/calculate` | JSON-Berechnung aller Positionen (AJAX) |
| POST | `/save_config` | Speichert Werte in YAML |
| GET | `/invoice` | Rechnungsseite |
| POST | `/invoice/pdf` | PDF-Download |
| POST | `/export` | TXT-Download |
| GET | `/settings` | Einstellungsseite |
| GET | `/projekte` | Liste der gespeicherten Projekte (JSON) |
| POST | `/projekte/speichern` | Aktuellen Stand als Projekt sichern |
| POST | `/projekte/laden` | Projekt in den Arbeitsstand laden |
| POST | `/projekte/loeschen` | Projekt entfernen |
| POST | `/upload_logo` | Logo hochladen |
| POST | `/delete_logo` | Logo loschen |