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:
@@ -74,22 +74,17 @@
|
||||
<div class="card mb-3">
|
||||
<div class="card-header"><i class="ti ti-eye me-2"></i>Vorschau</div>
|
||||
<div class="card-body p-0">
|
||||
{% set stueckzahl = calc.stueckzahl %}
|
||||
{% set gesamt_netto = calc.gesamt_netto %}
|
||||
{% set gesamt_mwst = calc.gesamt_mwst %}
|
||||
{% set gesamt_brutto = calc.gesamt_endpreis %}
|
||||
<div class="p-3" style="font-family:'Courier New',Courier,monospace;font-size:13px;line-height:1.8;white-space:pre;overflow-x:auto;background:var(--tblr-bg-surface);">LEISTUNGSBESCHREIBUNG:
|
||||
{{ '\u2500' * 50 }}
|
||||
Position: 3D-Druck - {{ config.projektName }}
|
||||
Menge: {{ stueckzahl }}
|
||||
Einzelpreis: {{ "%.2f"|format(calc.verkaufspreis) }} EUR
|
||||
Gesamt: {{ "%.2f"|format(gesamt_netto) }} EUR
|
||||
|
||||
{{ '\u2500' * 50 }}
|
||||
Nettobetrag: {{ "%.2f"|format(gesamt_netto) }} EUR
|
||||
{% if calc.mwst_ausweisen %}MwSt. ({{ '%g'|format(calc.mwst_satz) }}%): {{ "%.2f"|format(gesamt_mwst) }} EUR
|
||||
{% endif %}{{ '\u2550' * 50 }}
|
||||
GESAMTBETRAG{% if calc.mwst_ausweisen %} (brutto){% endif %}: {{ "%.2f"|format(gesamt_brutto) }} EUR
|
||||
{{ '\u2500' * 58 }}
|
||||
{% for pos in calc.positionen -%}
|
||||
{{ loop.index }}. {{ pos.name if pos.name else (config.projektName if calc.anzahl_positionen == 1 else 'Position ' ~ loop.index) }}
|
||||
{{ pos.stueckzahl }} x {{ "%.2f"|format(pos.stueckpreis) }} EUR = {{ "%.2f"|format(pos.zeilensumme) }} EUR
|
||||
{% endfor %}
|
||||
{{ '\u2500' * 58 }}
|
||||
Nettobetrag: {{ "%.2f"|format(calc.gesamt_netto) }} EUR
|
||||
{% if calc.mwst_ausweisen %}MwSt. ({{ '%g'|format(calc.mwst_satz) }}%): {{ "%.2f"|format(calc.gesamt_mwst) }} EUR
|
||||
{% endif %}{{ '\u2550' * 58 }}
|
||||
GESAMTBETRAG{% if calc.mwst_ausweisen %} (brutto){% endif %}: {{ "%.2f"|format(calc.gesamt_endpreis) }} EUR
|
||||
{% if calc.kleinunternehmer %}
|
||||
{{ kleinunternehmer_hinweis }}
|
||||
{% elif calc.privat %}
|
||||
|
||||
Reference in New Issue
Block a user