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>
This commit is contained in:
65
app.py
65
app.py
@@ -359,6 +359,50 @@ def projekt_aus_config(config):
|
||||
for feld in PROJEKT_FELDER}
|
||||
|
||||
|
||||
def leerer_projektstand():
|
||||
"""Projektfelder im Ausgangszustand. Datum auf heute."""
|
||||
stand = {feld: DEFAULT_VALUES.get(feld) for feld in PROJEKT_FELDER}
|
||||
stand['projektName'] = ''
|
||||
stand['kundenName'] = ''
|
||||
stand['kundenAdresse'] = ''
|
||||
stand['rechnungsnummer'] = ''
|
||||
stand['leistungsdatum'] = ''
|
||||
stand['datum'] = datetime.now().strftime('%Y-%m-%d')
|
||||
stand['positionen'] = [dict(DEFAULT_POSITION)]
|
||||
return stand
|
||||
|
||||
|
||||
def _vergleichbar(stand):
|
||||
"""Projektfelder in eine vergleichbare Form bringen.
|
||||
|
||||
'geaendert' und das Datum bleiben aussen vor -- ein neuer Tag macht
|
||||
aus einem gespeicherten Projekt keinen ungespeicherten Stand.
|
||||
"""
|
||||
return {
|
||||
'projektName': projekt_name(stand.get('projektName')),
|
||||
'kundenName': str(stand.get('kundenName') or ''),
|
||||
'kundenAdresse': str(stand.get('kundenAdresse') or ''),
|
||||
'rechnungsnummer': str(stand.get('rechnungsnummer') or ''),
|
||||
'leistungsdatum': str(stand.get('leistungsdatum') or ''),
|
||||
'positionen': saubere_positionen(stand.get('positionen')),
|
||||
}
|
||||
|
||||
|
||||
def ungespeicherte_aenderungen(config, projekte):
|
||||
"""True, wenn der Arbeitsstand nicht so in den Projekten liegt.
|
||||
|
||||
Ein voellig leerer Stand zaehlt nicht als ungespeichert -- da ist
|
||||
nichts zu verlieren.
|
||||
"""
|
||||
aktuell = _vergleichbar(config)
|
||||
if aktuell == _vergleichbar(leerer_projektstand()):
|
||||
return False
|
||||
gespeichert = projekte.get(aktuell['projektName'])
|
||||
if not isinstance(gespeichert, dict):
|
||||
return True
|
||||
return aktuell != _vergleichbar(gespeichert)
|
||||
|
||||
|
||||
def steuer_kontext(data):
|
||||
"""Liest Regime und MwSt.-Satz robust aus den Formularwerten."""
|
||||
regime = str(data.get('steuerregime', 'regel')).lower()
|
||||
@@ -582,7 +626,11 @@ def projekte_liste():
|
||||
'gesamt_endpreis': calc['gesamt_endpreis'],
|
||||
})
|
||||
eintraege.sort(key=lambda e: e['geaendert'], reverse=True)
|
||||
return jsonify({'projekte': eintraege, 'aktuell': config.get('projektName', '')})
|
||||
return jsonify({
|
||||
'projekte': eintraege,
|
||||
'aktuell': config.get('projektName', ''),
|
||||
'ungespeichert': ungespeicherte_aenderungen(config, projekte),
|
||||
})
|
||||
|
||||
|
||||
@app.route('/projekte/speichern', methods=['POST'])
|
||||
@@ -635,6 +683,21 @@ def projekt_laden():
|
||||
return jsonify({'status': 'ok', 'name': name})
|
||||
|
||||
|
||||
@app.route('/projekte/neu', methods=['POST'])
|
||||
def projekt_neu():
|
||||
"""Setzt den Arbeitsstand auf einen leeren Auftrag zurueck.
|
||||
|
||||
Betriebswerte (Drucker, Strom, Stundenlohn, Marge, Steuer,
|
||||
Firmendaten) bleiben unangetastet -- zurueckgesetzt wird nur, was
|
||||
zu einem einzelnen Auftrag gehoert.
|
||||
"""
|
||||
with _config_lock:
|
||||
config = load_config()
|
||||
config.update(leerer_projektstand())
|
||||
save_config(_migriere(config))
|
||||
return jsonify({'status': 'ok'})
|
||||
|
||||
|
||||
@app.route('/projekte/loeschen', methods=['POST'])
|
||||
def projekt_loeschen():
|
||||
"""Entfernt ein gespeichertes Projekt. Der Arbeitsstand bleibt."""
|
||||
|
||||
Reference in New Issue
Block a user