Commit Graph

7 Commits

Author SHA1 Message Date
Erik Thiele
c42fecacb9 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>
2026-08-22 11:38:26 +02:00
Erik Thiele
b6e5a59daa Sicherheit, PDF-Robustheit, Stueckzahl und Besteuerung ueberarbeitet
Sicherheit:
- debug=True aus app.run() entfernt. Der Werkzeug-Debugger erlaubt
  Codeausfuehrung ueber das Netz und lief bisher im LXC-Container mit.
  Neu ueber FLASK_DEBUG/HOST/PORT steuerbar; mit FLASK_DEBUG=1 bindet
  die App automatisch nur an 127.0.0.1.
- Wirkungsloses --no-reload aus dem systemd-ExecStart entfernt
  (app.run() wertet sys.argv nicht aus).
- /save_config uebernimmt nur noch Keys aus DEFAULT_VALUES.

PDF:
- pdf_text() transliteriert Zeichen, die die latin-1-Kernfonts nicht
  koennen (Gedankenstrich, typografische Anfuehrungszeichen, Euro-Zeichen).
  Vorher warf jeder solche Kundenname einen UnicodeEncodeError -> HTTP 500.
- Legacy-fpdf2-API abgeloest: ln=True -> new_x/new_y, output(dest='S')
  -> output(), Font "Arial" -> "Helvetica". Alle drei waren als
  "will soon be removed" markiert.

Kalkulation:
- Stueckzahl wirkt jetzt in der Hauptansicht. Vorher zeigte "GESAMT"
  den Preis pro Stueck, obwohl die Stueckzahl direkt darueber eingegeben
  wurde. Anzeige jetzt getrennt nach PRO STUECK und AUFTRAG.
- Rundung auf Cent-Basis des Stueckpreises, damit die Rechnungszeile
  nachrechenbar bleibt (Einzelpreis x Menge == Zeilensumme).
- as_stueckzahl() faengt '', '1.5' und 0 ab (vorher ValueError -> 500).
- Gewinnmarge im Ergebnis kommt vom Server; das Label zeigte auf der
  Startseite immer 20 %, weil es ein nicht vorhandenes Feld auslas.

Besteuerung (drei Regime statt eines Bool-Schalters):
- 'privat'           - kein Unternehmer nach §2 UStG: weder MwSt. noch
                       Steuernummer noch §19-Hinweis auf dem Beleg
- 'kleinunternehmer' - §19 UStG mit Pflichthinweis
- 'regel'            - MwSt. mit konfigurierbarem Satz (19 % / 7 %)
Steuernummer, USt-IdNr. und Leistungsdatum (§14 UStG) ergaenzt; sie
erscheinen nur in den beiden Unternehmer-Modi, unabhaengig davon, ob
die Felder in der Config gefuellt sind.

Config-Handling:
- save_config() schreibt atomar (tmp + os.replace + fsync), ein Lock
  serialisiert die Read-modify-write-Zyklen.
- load_config() wirft ConfigError bei beschaedigter YAML, statt still
  auf Defaults zu fallen -- sonst haette der naechste Autosave die
  Datei endgueltig ueberschrieben.
- _migriere() leitet steuerregime aus dem alten mwst_ausweisen ab und
  laeuft vor dem Auffuellen mit Defaults sowie nach jedem Speichern.

Frontend:
- Dark-Mode-Toggle schrieb "Light"/"Dark" als Textknoten in den
  Icon-Button und liess das Icon in der falschen Richtung stehen.
- recalculate() steigt auf Seiten ohne Ergebnisblock aus; auf der
  Einstellungsseite warf bisher jeder Tastendruck eine TypeError.
- Live-Berechnung entprellt (150 ms) statt ein Request pro Tastendruck.

Sonstiges:
- requirements.txt mit gepinnten Versionen; beide Proxmox-Skripte
  nutzen sie statt loser Paketlisten und ohne blindes --upgrade.
- Falsche Port-Ausgabe in proxmox-setup.sh korrigiert (5000 -> 5001).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 10:51:45 +02:00
Erik Thiele
0f09977885 Kundenname/Kundenadresse via data-var speicherbar (Auto-Save auf Rechnungsseite) 2026-07-02 14:48:23 +02:00
Erik Thiele
f77be1c07a MWST optional: Schalter in Einstellungen (mwst_ausweisen), standardmassig Ausweis deaktiviert 2026-07-02 14:39:12 +02:00
Erik Thiele
4eb2c9e71d Einstellungen ausgelagert: eigene Seite für Druckerabschreibung, Arbeitskosten, Gewinnmarge
- Neue /settings-Route mit eigener Seite (Einstellungen für Drucker, Arbeit, Marge)
- Settings-Cards aus index.html entfernt
- /save_config merged mit bestehenden Werten (kein Überschreiben)
- Navigation im Header: Kalkulation ↔ Einstellungen (alle Seiten)
- Port auf 5001 geändert (macOS AirPlay blockiert 5000)
2026-07-02 14:29:03 +02:00
Erik Thiele
0c62e8aa78 Stückzahl-Feld: Formular, Rechnungsvorschau, PDF 2026-07-02 13:10:29 +02:00
Erik Thiele
73631b415d Flask-Web-App statt Tkinter: Live-Berechnung, PDF-Rechnung, Dark Mode, Tabler CSS 2026-06-30 20:46:52 +02:00