# -*- coding: utf-8 -*- """Pruefstand: die Freigabe vor dem Beleg - und ihre Spur in der SQLite. Sein Satz vom 06.09.2026: "ich will fuer den pruefer sichtbar machen: ich wollte das so. die software dokumentiert das, und damit wird es nachvollziehbar, weil es einen checkmark nun gibt in der sqlite" - "das soll alles von anfang bis ende pruefbar sein" Geprueft wird beides, weil jedes einzeln wertlos waere: 1. NEIN -> es entsteht KEIN Beleg, die Nummer bleibt frei, im Buch steht nichts. Ein Popup, das man verneint und trotzdem eine Rechnung bekommt, waere schlimmer als gar keins. 2. JA -> der Beleg entsteht UND im Nummernbuch steht ein Zeitstempel der Freigabe. Ohne diesen Eintrag koennte spaeter niemand belegen, dass ausdruecklich freigegeben wurde. """ import json import os import re import shutil import sys import tempfile import threading QUELLE = r"C:\claude\rechnungstool" sys.path.insert(0, QUELLE) def _reissleine(): print("ABBRUCH | Pruefstand haengt (Zeitgrenze)") os._exit(2) _wecker = threading.Timer(120, _reissleine) _wecker.daemon = True _wecker.start() tmp = tempfile.mkdtemp(prefix="freigabe_pruef_") ordner = os.path.join(tmp, "rechnungen") install = os.path.join(tmp, "install") os.makedirs(ordner) os.makedirs(install) import config # noqa: E402 shutil.copy(os.path.join(QUELLE, "config.json"), os.path.join(tmp, "config.json")) config.CONFIG_PATH = os.path.join(tmp, "config.json") roh = json.load(open(config.CONFIG_PATH, encoding="utf-8")) roh["rechnung_jahr"], roh["rechnung_zaehler"] = 2026, 0 roh["nummer_eingerichtet"] = False roh["output_dir"] = ordner roh["gemeinsam_ordner"] = install json.dump(roh, open(config.CONFIG_PATH, "w", encoding="utf-8"), ensure_ascii=False, indent=2) os.environ["CAMPINGHOF_TEST"] = "1" import app as A # noqa: E402 import gemeinsam # noqa: E402 from tkinter import messagebox # noqa: E402 from pruefhelfer import fehler, pruefe antworten = {"Fertig": False, "Hausnummer": True} gefragt = [] def askyesno(titel, text, **kw): gefragt.append(titel) for schlue, wert in antworten.items(): if schlue in titel: return wert raise AssertionError(f"unangemeldeter Dialog: {titel!r}") # Der Erprobungshinweis wird hier bejaht - geprueft wird er in pruef_hinweis.py. antworten["Erprobungsfassung"] = True messagebox.askyesno = askyesno messagebox.showinfo = lambda *a, **k: None warnungen = [] messagebox.showwarning = lambda *a, **k: warnungen.append(a[0] if a else "") messagebox.showerror = lambda *a, **k: print("[fehler]", a[0] if a else "") f = A.RechnungsApp() f.update() f.cfg["output_dir"] = ordner # Im laufenden Programm oeffnet ein 400-ms-Timer das gemeinsame Buch. Den # erreicht ein Pruefstand nie - also wird dieselbe Stelle direkt gerufen. # Abgekuerzt wird damit nur das Warten, nicht der Weg. f._frage_gemeinsam_falls_noetig() pruefe(f.buch is not None, "das gemeinsame Nummernbuch ist offen") def kunde_fuellen(): f.k_vorname.set("Anna") f.k_name.set("Beispiel") f.k_strasse.set("Musterweg 1") f.k_plzort.set("12345 Musterstadt") f.r_anreise.set("01.08.2026") f.r_abreise.set("05.08.2026") erste = sorted(f.anzahl_vars)[0] f.anzahl_vars[erste].set("4") f.update() # ---- 1. NEIN: es darf nichts entstehen ---------------------------------- antworten["jetzt erstellen?"] = False kunde_fuellen() zaehler_vorher = f.cfg.get("rechnung_zaehler") nummer_vorher = f.r_nummer.get() f.pdf_erstellen() pdfs = [x for x in os.listdir(ordner) if x.lower().endswith(".pdf")] pruefe(not pdfs, f"nach Nein: kein PDF im Ordner (gefunden: {pdfs})") pruefe(any("jetzt erstellen?" in t for t in gefragt), "die Freigabe wurde ueberhaupt gefragt") pruefe(f.cfg.get("rechnung_zaehler") == zaehler_vorher, "nach Nein: der Rechnungszaehler ist unveraendert") pruefe(f.r_nummer.get() == nummer_vorher, "nach Nein: die Nummer im Feld ist unveraendert") buch = gemeinsam.Nummernbuch(install) pruefe(not buch.nummern(), f"nach Nein: das Nummernbuch ist leer ({buch.nummern()})") # ---- 2. JA: Beleg entsteht und die Freigabe steht in der SQLite --------- antworten["jetzt erstellen?"] = True kunde_fuellen() f.pdf_erstellen() pdfs = [x for x in os.listdir(ordner) if x.lower().endswith(".pdf")] pruefe(len(pdfs) == 1, f"nach Ja: genau ein PDF ({pdfs})") nummern = sorted(buch.nummern()) pruefe(len(nummern) == 1, f"nach Ja: eine Nummer im Buch ({nummern})") freigabe = "" if nummern: with buch._verbindung() as con: zeile = con.execute("SELECT freigabe FROM nummern WHERE nummer=?", (nummern[0],)).fetchone() freigabe = (zeile["freigabe"] if zeile else "") or "" pruefe(bool(freigabe), "die Freigabe steht in der SQLite") pruefe(bool(re.fullmatch(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}", freigabe)), f"der Zeitstempel ist ein ISO-Datum ({freigabe!r})") _wecker.cancel() f.destroy() shutil.rmtree(tmp, ignore_errors=True) if fehler: print(f"ROT | {len(fehler)} Punkt(e) nicht erfuellt") sys.exit(1) print("GRUEN | Freigabe wirkt und wird dokumentiert")