# -*- coding: utf-8 -*- """Pruefstand: finden sich die beiden Programme von SELBST? Sein Einwand vom 07.09.2026, wortwoertlich: "wie soll das rechnungstool und steuertool wissen wo es ist, das muss im ... ravokk liegen und dann zusammen, sonst kommt das eine nicht an das andere ran - die sind doch nur ueber die gemeinsame sqlite verbunden und mit api, die sagt hallo da ist was neues" Er hat recht: die beiden haengen an genau zwei Faeden - dieser SQLite-Datei und der kleinen API. Vorher fragte jedes Programm beim ersten Start nach einem Ordner, und der Nutzer musste in BEIDEN denselben eintragen. Ein Buchstabe daneben, und jedes Programm fuehrt sein eigenes Buch weiter - auffallen wuerde das erst, wenn eine Rechnungsnummer zum zweiten Mal vergeben ist (ยง 14 Abs. 4 Nr. 4 UStG). GEPRUEFT WIRD 1. Beide Programme nennen denselben Standardordner. Das ist die Grundlage; weichen sie hier ab, hilft alles Weitere nichts. 2. Der Ordner laesst sich anlegen, und darin entsteht EIN Nummernbuch. 3. Was das eine eintraegt, findet das andere - ohne dass jemand einen Pfad eingegeben hat. 4. Die Dateien, die von sich sagen, sie laegen in beiden Programmen gleich, sind auch wirklich gleich. Diese Datei liegt in BEIDEN Programmen gleich. Wer sie aendert, kopiert sie hinueber - und sie prueft sich unter Punkt 4 selbst mit, denn sie traegt denselben Satz wie die anderen. Angefasst wird dabei nichts Echtes: der Standardordner wird ueber die Umgebungsvariable LOCALAPPDATA auf einen Temp-Ordner umgelenkt. """ import os import shutil import sys import tempfile RECHNUNG = r"C:\claude\rechnungstool" STEUER = r"C:\claude\beherbergungssteuer" # ---- 1. Beide Programme meinen denselben Ort ---------------------------- # Geladen wird jede Fassung EINZELN, damit wirklich die Datei des jeweiligen # Programms befragt wird und nicht die zufaellig zuerst importierte. import importlib.util # noqa: E402 from pruefhelfer import fehler, pruefe def modul_aus(ordner, name): pfad = os.path.join(ordner, name + ".py") kennung = f"{name}_{os.path.basename(ordner)}" spec = importlib.util.spec_from_file_location(kennung, pfad) m = importlib.util.module_from_spec(spec) spec.loader.exec_module(m) return m tmp = tempfile.mkdtemp(prefix="gemeinsam_auto_") os.environ["LOCALAPPDATA"] = tmp g_rechnung = modul_aus(RECHNUNG, "gemeinsam") g_steuer = modul_aus(STEUER, "gemeinsam") a, b = g_rechnung.standard_ordner(), g_steuer.standard_ordner() pruefe(a == b, f"beide Programme nennen denselben Ordner ({a})") pruefe(a.startswith(tmp), "und er haengt an LOCALAPPDATA, nicht an einem festen Pfad im Quelltext") pruefe(os.path.basename(a) == "ravokk", f"er heisst 'ravokk', wie er es wollte ({os.path.basename(a)})") # ---- 2. Er wird angelegt, und darin liegt EIN Buch ---------------------- angelegt = g_rechnung.standard_anlegen() pruefe(bool(angelegt) and os.path.isdir(angelegt), f"der Ordner wird angelegt ({angelegt})") pruefe(g_rechnung.DATEINAME == g_steuer.DATEINAME, f"beide erwarten dieselbe Datei ({g_rechnung.DATEINAME})") pruefe(g_rechnung.pfad_zur_datei(angelegt) == g_steuer.pfad_zur_datei(angelegt), "und damit denselben vollen Pfad") # ---- 3. Was das eine eintraegt, findet das andere ----------------------- buch_r = g_rechnung.Nummernbuch(angelegt) buch_s = g_steuer.Nummernbuch(angelegt) buch_r.eintragen("2026-777", jahr=2026, nachname="Probe", quelle="rechnungstool") gefunden = [n for n in buch_s.nummern(2026) if n == "2026-777"] pruefe(bool(gefunden), "was das Rechnungstool eintraegt, sieht das Steuerjournal sofort") buch_s.eintragen("2026-778", jahr=2026, nachname="Gegenprobe", quelle="journal") zurueck = [n for n in buch_r.nummern(2026) if n == "2026-778"] pruefe(bool(zurueck), "und umgekehrt genauso") # GENAU eins - nicht "mindestens eins". Vorher stand hier `>= 1` mit einem # any(); im Text darueber stand "genau ein Buch". Eine Pruefung, die nicht rot # werden kann, prueft nichts: laege dort ein zweites Buch, weil eine der # Fassungen einen anderen Dateinamen bildet, waere sie gruen geblieben - und # das ist genau der Fall, den dieser Pruefstand abfangen soll. # # Die Begleitdateien von SQLite (-wal, -shm) zaehlen nicht mit; sie gehoeren # zum selben Buch. buecher = [n for n in os.listdir(angelegt) if n.endswith(".sqlite3")] pruefe(len(buecher) == 1, f"es liegt genau EIN Buch dort ({os.listdir(angelegt)})") pruefe(buecher == [g_rechnung.DATEINAME], f"und es traegt den Namen, den beide erwarten ({buecher})") # ---- 4. Was "in beiden gleich" heisst, ist auch gleich ------------------ # Neun Dateien tragen im Kopf den Satz, sie laegen in beiden Programmen # gleich. Das ist eine Zusage an den Naechsten, der eine davon anfasst - und # geprueft hat sie bis zum 07.09.2026 niemand. Bei hinweis.py stimmte sie da # schon nicht mehr: gleicher Inhalt, andere Zeilenenden. # # Die Liste steht bewusst NICHT hier, sondern wird aus dem Satz selbst # gelesen. Eine Liste, die jemand von Hand nachfuehren muss, veraltet still # (und still veraltete Pruefstaende fuehren in die Irre). MARKE = "Diese Datei liegt in BEIDEN Programmen gleich" gemeinsame = sorted(n for n in os.listdir(RECHNUNG) if n.endswith(".py") and MARKE in open(os.path.join(RECHNUNG, n), encoding="utf-8").read()) pruefe(len(gemeinsame) >= 5, f"{len(gemeinsame)} Dateien sagen von sich, sie seien in beiden gleich") for name in gemeinsame: hier = os.path.join(RECHNUNG, name) dort = os.path.join(STEUER, name) if not os.path.isfile(dort): pruefe(False, f"{name} fehlt im Steuerrechnungstool") continue roh_h, roh_d = open(hier, "rb").read(), open(dort, "rb").read() if roh_h == roh_d: pruefe(True, f"{name} ist byteweise gleich") continue # Nicht gleich - dann wenigstens sagen, WORAN es liegt. Das ist der # Unterschied zwischen einer Meldung und einer Suche. if roh_h.replace(b"\r\n", b"\n") == roh_d.replace(b"\r\n", b"\n"): grund = "nur die Zeilenenden weichen ab" else: grund = "der Inhalt weicht ab" pruefe(False, f"{name}: {grund}") shutil.rmtree(tmp, ignore_errors=True) if fehler: print(f"ROT | {len(fehler)} Punkt(e) nicht erfuellt") sys.exit(1) print("GRUEN | Beide Programme finden dasselbe Nummernbuch ohne Nachfrage")