Commit Graph

52 Commits

Author SHA1 Message Date
Erik Thiele
1ddab85e90 Plakette als Favicon
Sie bringt ihre eigene dunkle Platte mit und steht damit in hellen wie
dunklen Browserreitern, anders als die freistehende Wortmarke.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 14:28:52 +02:00
Erik Thiele
b0e6b1b9f2 JET-Design-Wortmarke im Kopf und auf der Rechnung
Die Logos stammen aus der Shop-Webseite (assets/img/logo). Im Seitenkopf
stehen beide SVG-Varianten im Markup, CSS blendet die zum Theme passende
ein -- der Dark-Mode-Schalter laedt die Seite nicht neu.

Fuer den Rechnungsdruck liegt die Wortmarke zusaetzlich als JPEG bei,
weil fpdf2 kein SVG setzen kann. logo_datei() waehlt aus: hochgeladenes
Logo vor mitgelieferter Marke, Textkopf nur noch als Notnagel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 14:25:52 +02:00
Erik Thiele
e1142ac904 Datumsausgabe im Format TT.MM.JJJJ
Auf der Rechnung standen die Daten bisher in ISO-Form (2026-08-22).

- Neuer Helfer datum_de() formatiert nach TT.MM.JJJJ. Er versteht ISO
  und bereits deutsche Eingaben und laesst alles Unbekannte unveraendert
  statt es zu verstuemmeln.
- Angewendet auf Rechnungs- und Leistungsdatum im PDF sowie auf die
  Datumszeile im TXT-Export. Auch als Jinja-Filter registriert.
- Gespeichert wird weiterhin ISO: sortierbar und eindeutig. Nur die
  Ausgabe ist deutsch.
- Die beiden Datumsfelder auf der Rechnungsseite sind jetzt
  type="date". Der Browser zeigt sie im deutschen Format mit
  Kalenderauswahl und liefert intern sauberes ISO zurueck, womit
  mehrdeutige Freitexteingaben entfallen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 12:35:48 +02:00
Erik Thiele
ab6d02eccb Fix: Ausstehender Autosave ueberschrieb das geladene Projekt
Beim Laden eines Projekts blieb der alte Projektname stehen, wenn kurz
zuvor getippt wurde.

Ursache: projektLaden() brach den laufenden Autosave-Timer nicht ab.
Der feuerte 500 ms nach dem letzten Tastendruck, las die noch alten
Formularfelder aus und schrieb sie ueber den gerade geladenen Stand.
Anschliessend folgte ein location.reload(), der den ueberschriebenen
Stand anzeigte. Auf localhost war das Zeitfenster meist zu klein, ueber
LAN gegen den Container dagegen zuverlaessig zu treffen.

- projektLaden() und projektNeu() brechen saveTimeout und calcTimeout ab.
- /projekte/laden und /projekte/neu liefern den neuen Stand zurueck,
  das Frontend setzt die Felder direkt (neue Funktion standUebernehmen).
- Kein location.reload() mehr. Das beseitigt zusaetzlich die
  Formular-Wiederherstellung, mit der Firefox und Safari von Hand
  geaenderte Felder nach einem Reload zurueckholen -- betroffen waere
  genau das Projektnamen-Feld gewesen.

Reproduziert und gegengeprueft: mit der alten Reihenfolge schreibt der
Autosave "Projekt B" ueber das geladene "Projekt A"; mit dem Fix bleiben
Feld und Serverstand ueber mehrere Wechsel hinweg stabil.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 12:10:50 +02:00
Erik Thiele
1b3ef82db4 Knopf "Neues Projekt" zum Leeren des Arbeitsstands
Bisher liess sich ein neuer Auftrag nur von Hand beginnen: Namen
ueberschreiben, jede Position neu ausfuellen und auf der Rechnungsseite
Kundendaten und Rechnungsnummer leeren. Wurde der letzte Schritt
vergessen, stand der alte Kunde auf der neuen Rechnung.

- POST /projekte/neu setzt nur PROJEKT_FELDER zurueck (Name, Positionen,
  Kundendaten, Rechnungsnummer, Datum auf heute). Betriebswerte wie
  Marge, Stundenlohn, Drucker, Steuer und Firmendaten bleiben.
- GET /projekte liefert zusaetzlich 'ungespeichert'. Der Knopf fragt nur
  nach, wenn der offene Stand wirklich nicht als Projekt gesichert ist.
- Der Vergleich ignoriert 'datum' und 'geaendert', sonst waere ein
  gespeichertes Projekt am naechsten Tag faelschlich "ungespeichert".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 11:59:20 +02:00
Erik Thiele
ce3ba9df7e Zahlungsziel bei Privatverkauf weglassen
Ein Zahlungsziel ist eine Geschaeftsbedingung. Auf einem Privatbeleg hat
es nichts zu suchen -- dort wird der Betrag ueblicherweise direkt
beglichen.

ZAHLUNGSZIEL und DANK sind jetzt getrennte Konstanten. Das Zahlungsziel
erscheint nur bei 'kleinunternehmer' und 'regel', der Dank in allen drei
Regimen. Gilt fuer PDF und Rechnungsvorschau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 11:50:08 +02:00
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
c5b52f4c1c README und AGENTS.md aktualisiert 2026-07-02 17:12:10 +02:00
Erik Thiele
542ad959bd .gitignore repariert: config und logo wieder ausgeschlossen 2026-07-02 17:08:38 +02:00
Erik Thiele
c2bd9aae89 PDF-Output: str/bytes handling fix 2026-07-02 17:05:36 +02:00
Erik Thiele
ebc4ca0000 .gitignore angepasst 2026-07-02 17:00:28 +02:00
Erik Thiele
980549faa3 README aktualisiert (Port 5001, Settings, Logo, proxmox-update) 2026-07-02 16:48:04 +02:00
Erik Thiele
0522a4c457 proxmox-update.sh: Update-Script fur LXC-Container (git pull + restart) 2026-07-02 16:39:11 +02:00
Erik Thiele
478dbbb31c PayPal, IBAN, Bank unter dem Logo im Firmendaten-Block 2026-07-02 16:27:46 +02:00
Erik Thiele
42a23ea4b6 Fusszeile aus PDF entfernt 2026-07-02 16:25:02 +02:00
Erik Thiele
5eee2f9c3f Inhalt noch weiter nach unten (content_y=80) 2026-07-02 16:04:11 +02:00
Erik Thiele
6c4f3e3c1b Datum und Inhalt weiter nach unten verschoben 2026-07-02 16:03:09 +02:00
Erik Thiele
1374e47e07 Logo noch kleiner (w=20) 2026-07-02 16:02:46 +02:00
Erik Thiele
6d6aab18ea Mehr Platz oben: Logo bei y=12 statt 5 2026-07-02 15:45:50 +02:00
Erik Thiele
85d382834b Logo rechtsbundig (x=171, rechte Kante am Rand) wie Text darunter 2026-07-02 15:41:43 +02:00
Erik Thiele
0ef4ab6c5a Logo 40% kleiner (w=24, x=165) 2026-07-02 15:40:33 +02:00
Erik Thiele
27e291b566 Telefon/Mail unter Logo jeweils eigene Zeile 2026-07-02 15:35:05 +02:00
Erik Thiele
cae45174ea Logo nach y=5 verschoben, Hoehe via image_dimensions() berechnet, Text darunter 2026-07-02 15:33:40 +02:00
Erik Thiele
46b5db964f PDF: Font vor Firmendaten setzen, feste Position unter Logo (logo_bottom=50) 2026-07-02 15:30:34 +02:00
Erik Thiele
42962d34cb Logo-Hoehe via image_dimensions() berechnen, Firmendaten korrekt darunter 2026-07-02 15:27:52 +02:00
Erik Thiele
3b6d2a96ba Firmendaten unter das Logo (rechtsbundig), Rechnungsdaten/Empfaenger darunter links 2026-07-02 15:26:27 +02:00
Erik Thiele
0241816252 Logo weiter nach oben rechts verschoben (x=155, y=8) 2026-07-02 15:24:23 +02:00
Erik Thiele
93885cd791 .gitignore: statische Logo-Dateien ignorieren 2026-07-02 15:23:02 +02:00
Erik Thiele
78d44ee982 Logo kleiner (w=40) und weiter oben rechts positioniert 2026-07-02 15:22:52 +02:00
Erik Thiele
93bf843903 Logo-Upload: Magic-Bytes-Pruefung (PNG/JPEG/WebP), dynamischer Dateiname 2026-07-02 15:16:29 +02:00
Erik Thiele
69a108e5b3 Logo-Upload: Bild hochladen/loeschen via Settings, Einbindung in PDF mit Fallback auf Text 2026-07-02 15:13:41 +02:00
Erik Thiele
2bd4d19034 PDF: Margins gesetzt (15mm links), Nettobetrag/Summen/Zahlbar starten auf gleicher Hohe wie Tabelle 2026-07-02 15:11:15 +02:00
Erik Thiele
7cc601acf3 PDF: Tabelle mit Spalten (Menge, EP, Gesamt rechts), Summen und Zahlbar links 2026-07-02 15:08:26 +02:00
Erik Thiele
961a3ae1c7 PDF: alle Zeilen linksbundig (Label: Wert untereinander) 2026-07-02 15:06:47 +02:00
Erik Thiele
5a8713ed2d PDF-Rechnung neues Layout: Logo rechts, Empfänger links, Firmendaten aus Einstellungen, Footer mit Kontakt/Paypal/IBAN 2026-07-02 15:01:50 +02:00
Erik Thiele
e97cad924d PDF: Rechnungs-Uberschrift linksbundig 2026-07-02 14:55:42 +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
fad9aefee3 Rechnungsnummer nur im PDF anzeigen wenn ausgefuellt 2026-07-02 14:46:43 +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
4f3c6763ca Arbeitszeit in die Kalkulationsseite verschoben 2026-07-02 14:35:37 +02:00
Erik Thiele
33e80ca7bb Settings-Seite: Darkmode-Button, kein Selbstlink 2026-07-02 14:33:58 +02:00
Erik Thiele
23d4c180a6 Stromverbrauch/Strompreis in Einstellungen verschoben 2026-07-02 14:31:35 +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
44e63c8cd6 Stückzahl in Projektinformationen verschoben 2026-07-02 13:13:43 +02:00
Erik Thiele
0c62e8aa78 Stückzahl-Feld: Formular, Rechnungsvorschau, PDF 2026-07-02 13:10:29 +02:00
Erik Thiele
f4e806079b Fix: use filesystem path instead of volume path for pct create 2026-07-01 20:00:26 +02:00
Erik Thiele
25ef5c329f Fix: vztplm -> vztemplate im pct create 2026-07-01 19:59:02 +02:00
Erik Thiele
ce6d60f0a2 README: Proxmox-Installationsanleitung 2026-07-01 19:46:30 +02:00
Erik Thiele
6b3b373a24 Proxmox-Setup-Script + Flask auf 0.0.0.0 fuer Container 2026-07-01 19:29:44 +02:00