Knoepfe: "Storno" und "Berichtigen" setzen den Weg schon beim Oeffnen fest, das Popup fragt dann nur noch die Nummer. Vorher entschied ein zweiter Knopf im Popup - der ist raus. app.py war 1802 Zeilen, jetzt 672. Neu daneben: helfer.py Zahlen, Datum, Namen, Pruefungen (87) bestand.py was im Rechnungsordner liegt, nur lesen (171) storno.py den spiegelbildlichen Storno rechnen (57) einzelinstanz.py nur ein Fenster zulassen (90) theme.py Farben nach Windows hell/dunkel (120) korrektur.py Storno- und Berichtigungsweg (306) einstellungen.py die Dialoge aus dem Menue (358) Die Oberflaeche bleibt eine Klasse - die Teile sind Mixins, damit kein einziger self-Zugriff umgeschrieben werden musste. Kein Modul importiert app.py zurueck, keine ungenutzten Importe mehr. Die Pruefstaende holen die Funktionen jetzt aus dem Modul, dem sie gehoeren. pruef_storno.py 100 gruen, pruef_nummern.py 7 gruen, Fenster nach der Aufteilung gestartet und angesehen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
57 lines
2.8 KiB
Python
57 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Den spiegelbildlichen Storno zu einer Rechnung rechnen."""
|
|
|
|
import berechnung
|
|
|
|
|
|
def storno_rechnung_bauen(meta, cfg):
|
|
"""Baut aus den Kenndaten der alten Rechnung den spiegelbildlichen Storno.
|
|
|
|
Alle Betraege negativ. Je USt-Satz eine Zeile - die einzelnen Leistungen der
|
|
alten Rechnung werden NICHT wiederholt: aufgehoben wird der Beleg als Ganzes,
|
|
und die Positionen stehen in aelteren PDFs gar nicht in den Kenndaten.
|
|
"""
|
|
r = berechnung.Rechnung()
|
|
nummer = meta.get("rechnungsnummer", "")
|
|
bloecke = meta.get("ust_bloecke") or []
|
|
if not bloecke:
|
|
# v1-PDF ohne Aufteilung: alles auf den ermaessigten Satz, sonst faellt
|
|
# die USt unter den Tisch.
|
|
brutto = float(meta.get("zwischensumme") or 0)
|
|
satz = int((cfg.get("steuersaetze") or [{"satz": 7}])[0].get("satz", 7))
|
|
netto = berechnung.runde(brutto * 100 / (100 + satz)) if satz else brutto
|
|
bloecke = [{"satz": satz, "netto": netto, "ust": berechnung.runde(brutto - netto),
|
|
"brutto": brutto}]
|
|
|
|
saetze = {int(s.get("satz", -1)): s for s in cfg.get("steuersaetze", [])}
|
|
for i, b in enumerate(bloecke, start=1):
|
|
satz = int(float(b.get("satz", 0) or 0))
|
|
brutto = -abs(berechnung.runde(b.get("brutto") or 0))
|
|
netto = -abs(berechnung.runde(b.get("netto") or 0))
|
|
ust = -abs(berechnung.runde(b.get("ust") or 0))
|
|
r.zeilen.append(berechnung.PositionsZeile(
|
|
nr=i, leistung=f"Storno der Rechnung {nummer} ({satz} % USt)",
|
|
satz=satz, preis=brutto, anzahl=1, personen=0, pro_person=False,
|
|
brutto=brutto, netto=netto))
|
|
info = saetze.get(satz, {})
|
|
r.bloecke.append(berechnung.Steuerblock(
|
|
satz=satz, netto=netto, ust=ust,
|
|
bezeichnung=str(info.get("bezeichnung", "") or "Mehrwertsteuer"),
|
|
extra_blatt=bool(info.get("extra_blatt", False))))
|
|
|
|
r.netto_gesamt = berechnung.runde(sum(b.netto for b in r.bloecke))
|
|
r.ust_gesamt = berechnung.runde(sum(b.ust for b in r.bloecke))
|
|
r.brutto = berechnung.runde(r.netto_gesamt + r.ust_gesamt)
|
|
|
|
# Beherbergungssteuer wird mitstorniert, sonst stimmt die Meldung ans Amt nicht.
|
|
# Die Bezeichnung kommt aus dem Satz mit "extra_blatt" - genau dem, aus dem
|
|
# berechne() den Aufschlag baut.
|
|
steuer = berechnung.runde(meta.get("steuer_betrag") or 0)
|
|
if steuer:
|
|
extra = next((s for s in cfg.get("steuersaetze", []) if s.get("extra_blatt")), {})
|
|
r.aufschlaege.append(berechnung.Aufschlag(
|
|
satz=float(meta.get("steuer_satz") or extra.get("satz", 0) or 0),
|
|
bezeichnung=str(extra.get("bezeichnung", "") or "Beherbergungssteuer"),
|
|
basis=r.brutto, betrag=-abs(steuer), extra_blatt=True))
|
|
r.gesamt = berechnung.runde(r.brutto + sum(a.betrag for a in r.aufschlaege))
|
|
return r
|