Die Runde vom 07.09.2026 hat neben den zwei echten Fehlern eine Reihe
Wiederholungen und stumme Stellen gemeldet. Abgearbeitet in Etappen, jede fuer
sich pruefbar - nach jeder liefen beide Pruefketten gruen.
* Menueleiste: der Wechsel von einem Titel zum anderen brauchte ZWEI Klicks.
Der grab_set der offenen Liste schluckt den ersten, die <Button-1>-Bindung
des Titels feuert gar nicht. Das native tk.Menu, das diese Leiste ersetzt
hat, wechselte schon beim blossen Ueberfahren - zwei Klicks waren also eine
Verschlechterung gegenueber dem, was vorher da war. Die Klappliste wird
ausserdem jetzt wie jede andere Position ueber theme.auf_bildschirm()
begrenzt; am unteren Fensterrand lief sie vorher hinaus.
Neu: pruef_menueleiste.py misst beides ueber echte Klickereignisse.
* %LOCALAPPDATA%/ravokk wurde an drei Stellen einzeln ausgerechnet. Jetzt
fragen alle gemeinsam.standard_ordner(). Laufen die je auseinander, fuehren
die beiden Programme zwei Nummernbuecher - und das faellt erst auf, wenn
eine Rechnungsnummer zum zweiten Mal vergeben ist (§ 14 Abs. 4 Nr. 4 UStG).
* pruefe() stand 35-mal im Quelltext, in sechs Fassungen -> pruefhelfer.py.
Die zwei Ausreisser sind mitgezogen: pruef_bilder.py schrieb ein eigenes
Format, pruef_storno_verrechnet.py zaehlte in einer Zahl und konnte am Ende
nicht sagen, WAS fehlschlug.
* dlg_darstellung() und die drei Handgriffe des Umschaltens standen in beiden
app.py fast wortgleich -> ThemeMixin in theme.py. Beide trugen inzwischen
denselben langen Kommentar zu demselben Fehler; das war der Beweis, dass es
eine Sache ist. Programmspezifisch bleiben der Hinweistext im Dialog (R31)
und die Frage, ob die Einstellungen ausdruecklich gespeichert werden muessen.
* pruef_gemeinsam_automatisch.py sagte im Text "genau ein Buch" und prueft
">= 1" mit einem any() - eine Pruefung, die nicht rot werden kann. Jetzt
== 1, und der Dateiname wird mitgeprueft.
Dazu neu: die neun Dateien, die im Kopf zusagen, sie laegen in beiden
Programmen gleich, werden byteweise verglichen. Bei hinweis.py stimmte die
Zusage seit dem 06.09. nicht mehr - gleicher Inhalt, CRLF gegen LF.
* .gitattributes, damit die Zeilenenden nicht von der Maschine abhaengen.
Ohne das meldet genau diese Pruefung nach einem frischen Checkout einen
Unterschied, den es im Repository gar nicht gibt.
* Sechs stumme "except OSError" sagen jetzt, warum sie schweigen duerfen, und
einer meldet statt zu schweigen: schlaegt die Uebernahme einer alten
config.json fehl, faengt das Programm ohne Firmendaten, Katalog und Zaehler
neu an - und der Erfolgsfall schrieb eine Zeile, der Fehlerfall nicht. Die
24 stummen tk.TclError bleiben: dort wird ein Widget angefasst, das gerade
zerstoert wurde, und eine Meldung waere Rauschen.
* Tote Parameter und Variablen aus dem Umbau des Vortags: symbol_setzen(dunkel=),
kachel(grund=, radius=), mit_trennlinie, sechs x/y-Berechnungen, die von
theme.mittig() sofort ueberschrieben wurden, vier lokale "import ctypes".
39 Pruefstaende, 0 rot.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
Sein Wortlaut (06.09.2026):
"bei jedem oeffnen, solange wir die testen, ein popup, dass dies eine
experimentelle software ist und ich keine haftung fuer irgendwelche falsch
ausgestellten uebernehme. der user muss selbst pruefen ueber den vorschau
button auf beiden tools, ob das alles seine richtigkeit hat. wenn nicht, auf
dem link eine issue erstellen. und das alles auch noch mal in die info mit
signatur: user hat dies gelesen und zur kenntnis genommen. wenn er nein
drueckt oder ablehnt, schliesst sich die software und geht beim naechsten
start wieder mit dem selben auf, bis er auf ja drueckt."
WIE ES GEBAUT IST
hinweis.py - neu, liegt spaeter in BEIDEN Programmen gleich (wie gemeinsam.py):
Text, Fehleradresse je Programm, Kenntnisnahme lesen/schreiben, Signaturzeile.
* Der Hinweis kommt als ERSTES beim Start. Erst nach der Bestaetigung faehrt
der uebrige Start an (_start_fortsetzen) - vorher wird nichts geoeffnet,
nichts gefragt, nichts geladen. Sonst stuenden beim Ablehnen noch Timer in
der Warteschlange, die auf ein Fenster zugreifen, das es nicht mehr gibt.
* "Nein" beendet das Programm. Es wird NICHTS vermerkt - ein Nein, das
trotzdem als Kenntnisnahme gespeichert wuerde, waere eine Luege.
* "Ja" wird mit Benutzername, Zeitpunkt und Fassung in der config vermerkt.
Das ist die Signatur.
* Aendert sich der TEXT (FASSUNG), wird erneut gefragt. Eine Zustimmung gilt
fuer das, was dagestanden hat, nicht fuer alles Kuenftige.
* Unter Hilfe -> Info steht derselbe Text dauerhaft, mit der Signaturzeile.
UMBENENNUNG
Das frueher "beherbergungssteuer" genannte Repository heisst jetzt
Steuerrechnungstool:
https://git.pcore.de/TheMockTv/Steuerrechnungstoolhttps://git.pcore.de/TheMockTv/rechnungstool
In beiden READMEs vermerkt, samt "git remote set-url". Der LOKALE Ordner heisst
weiter beherbergungssteuer - der Pfad steht in Pruefstaenden und Spec-Dateien
fest, das ist ein eigener Schritt.
PRUEFSTAND
pruef_hinweis.py prueft die ganze Strecke: Hinweis kommt und nennt Haftung,
Vorschau und Adresse; Nein schliesst das Fenster und vermerkt nichts; neuer
Start fragt wieder; Ja hinterlaesst Fassung, Zeit, Benutzer und eine lesbare
Signaturzeile; danach wird nicht mehr gefragt; bei geaenderter Fassung wieder.
Alle 17 Pruefstaende gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
Sein Grund, woertlich (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"
WAS PASSIERT
Vor dem Schreiben eines Belegs fragt das Programm einmal ausdruecklich nach.
Der Text nennt, was gleich entsteht und was daran bindend ist:
Rechnung: ausgestellt im Sinne des § 14 UStG; die Nummer ist danach vergeben
und darf kein zweites Mal verwendet werden (§ 14 Abs. 4 Nr. 4 UStG);
zehn Jahre aufzubewahren (§ 147 Abs. 3 AO); nachtraeglich nicht
aenderbar (§ 146 Abs. 4 AO) - eine falsche Rechnung wird nicht
ueberschrieben, sondern storniert.
Angebot: unverbindlich, KEINE Rechnung, weist keine Steuer aus, verbraucht
keine Rechnungsnummer, wird nirgends gebucht.
Storno/Korrektur und Berichtigung haben ihre eigene Rueckfrage - sie wird nicht
verdoppelt (ein Schritt pro Fenster).
DIE SPUR
Ein Popup allein waere fuer einen Pruefer wertlos, es hinterlaesst nichts.
Deshalb bekommt die Tabelle "nummern" im gemeinsamen Buch eine Spalte
"freigabe": der ISO-Zeitstempel der ausdruecklichen Freigabe, an der
Rechnungsnummer haengend. Bestehende Buecher werden per ALTER TABLE nachgezogen;
alte Zeilen bleiben LEER - dort wurde nie gefragt, und ein nachtraeglich
erfundener Zeitstempel waere schlimmer als keiner.
gemeinsam.py liegt in beiden Programmen gleich und wurde mit hinuebergezogen.
PRUEFSTAND
pruef_freigabe.py prueft beide Richtungen, weil jede einzeln wertlos waere:
NEIN -> kein PDF, Zaehler unveraendert, Nummer im Feld unveraendert,
Nummernbuch leer
JA -> genau ein PDF, eine Nummer im Buch, Freigabe gesetzt und ein ISO-Datum
Die sieben Pruefstaende, die Belege erzeugen, melden die Freigabe jetzt
ausdruecklich an (pruefsteuerung bricht bei unangemeldeten Dialogen absichtlich
ab - kein stilles "ja").
Alle 16 Pruefstaende gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
Seine Ansage: "schau dir unsern fivem server an und unsere webseiten, dann
weisst du wie mein design ist" - also die Palette aus _ui_www und der
Adminpage: Tuerkis #06C6A4 auf gestuften dunklen Flaechen (#0d0e10 Grund,
#15171b Kachel), Raender #25282e, Text #e8e8ea / #8a8e96, Rot #e85a5a.
Das PROGRAMM traegt diese Handschrift, die RECHNUNG die Farbe der jeweiligen
Firma - das Blatt gehoert dem Kunden, nicht uns.
- Roboto wird mitgeliefert und nur fuer den Prozess geladen
(AddFontResourceEx mit FR_PRIVATE): keine Installation, keine Adminrechte,
nach dem Schliessen ist der Rechner wie vorher. Fehlt sie, bleibt es bei
Segoe UI. Die Schriftdateien gehen mit in die exe (spec).
- Abschnitte sind Kacheln mit Ueberschrift statt grauer Rahmen.
- Knoepfe im Glas-Stil wie in seinen Oberflaechen: getoente Flaeche, Rand in
Akzent-Transparenz. Tk kann kein backdrop-filter - die Toenung wird
ausgerechnet (theme.mischen), das Ergebnis ist auf einfarbigem Grund
identisch. "PDF erstellen" fuehrt, "Storno" ist rot.
- Zebrastreifen in der Leistungsliste: bei 17 Zeilen verrutscht man sonst.
- Kein expand am offenen Reiter mehr - dadurch sprang beim Umschalten die
ganze Leiste ("das taben macht den aktiven kleiner").
- Das Fenster fuer den gemeinsamen Ordner stand als einziges noch in Weiss da:
es kam nie durch _style_dialog.
Dazu ein Fund, der nichts mit dem Design zu tun hat: die Pruefstaende erbten
"nummer_eingerichtet" aus der config DIESES Rechners. Sobald hier jemand die
Nummer einmal einrichtet, liefen sie in einen anderen Zweig und wurden rot -
ohne dass sich am Programm etwas geaendert haette. Sie legen den Zustand jetzt
selbst fest. Alle 14 gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
Das Rechnungstool kannte nur die Nummern seiner eigenen PDFs. Im Steuerjournal
stehen aber Buchungen ohne PDF - der Altbestand aus der Excel-Mappe - und deren
Nummern hat es ein zweites Mal vergeben. § 14 Abs. 4 Nr. 4 UStG laesst jede
Nummer nur einmal zu.
Deshalb fuehren beide Programme jetzt EIN gemeinsames Buch (gemeinsam.py): eine
SQLite in einem Ordner, den beide kennen. Es ist ein Register, keine zweite
Buchhaltung - die Wahrheit bleiben die PDFs. Was hineinkommt: jede geschriebene
Rechnung, jeder Storno (mit storno_zu), jede Neuausstellung. Die Nummernvergabe
und die Kollisionspruefung beim Erstellen fragen es mit ab; ein verworfener
Storno gibt seine Nummer wieder frei. Faellt der Ordner aus (Netzlaufwerk weg),
laeuft alles weiter - dann steht es in der Fussleiste.
ordnerwahl.py fragt den Ordner beim ersten Start ab: auswaehlen, OK,
Sicherheitsfrage, bei Nein zurueck ins Feld. Zwei Fehler daran gleich behoben,
bevor sie jemand treffen konnte: das Fenster war zu schmal (der Auswahl-Knopf
lag ausserhalb) und der Griff (grab_set) muss waehrend des Windows-Ordner-
dialogs los sein, sonst nimmt der keine Eingabe an.
Storno: er ist das Spiegelbild der Rechnung - auch bei den UEBERNACHTUNGEN.
Vorher stand dort nichts, und das Steuerjournal meldete dem Amt die Naechte der
aufgehobenen Rechnung weiter mit. Auf dem Blatt steht "4 Naechte (aufgehoben)",
in den Kenndaten -4.
"Neue Rechnung:" auf dem Storno-Blatt heisst jetzt "Berichtigte Rechnung:" -
die alte Beschriftung las sich wie die Nummer DIESES Blattes.
--test / CAMPINGHOF_TEST=1 unterdrueckt den Erststart-Dialog. In der EXE kommt
man ohnehin nicht daran, und die Pruefstaende bleiben sonst im Dialog stehen.
Pruefstand pruef_nummernbuch.py (neu): beide Programme auf einem Ordner - das
Journal traegt drei Altbestands-Nummern ein, das Rechnungstool schlaegt danach
2026-004 statt 2026-001 vor. Alle uebrigen Pruefstaende gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
- "Rechnung endgueltig erstellen?" nennt Nummer, Kunde und Betrag und weist
darauf hin, dass danach nur noch Storno oder Berichtigung bleibt
(§ 14 Abs. 4 Nr. 4 UStG, § 31 Abs. 5 UStDV). Geprueft ist auch, dass "Nein"
wirklich nichts schreibt - sonst waere die Frage eine Attrappe.
- Als EXE legt das Programm sich beim ersten Start einen Ordner "Daten" neben
die EXE (config.json). Ist dort nicht schreibbar (EXE unter "Programme"),
weicht es nach LOCALAPPDATA aus. Lag die config.json noch direkt neben der
EXE, zieht sie um - sonst faengt das Programm ohne Firmendaten neu an.
- Aufruf von _storno_fortsetzen entfernt: die Methode gibt es nicht mehr, seit
die Kette auf dem Storno-Blatt steht. War unerreichbar, waere aber beim
naechsten Anfassen ein AttributeError geworden.
- Pruefstaende raeumen ihren Wegwerf-Ordner weg und haben eine Reissleine
(Abbruch nach zwei Minuten), damit kein Dialog mehr ewig offen steht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
Statt einer Zustandsmaschine ("offener Storno" ueber den Neustart retten) traegt
das Storno jetzt einfach beide Nummern:
Storno zu Rechnung: 2026-002
Neue Rechnung: 2026-004
und im Text "2026-002 -> 2026-003 -> 2026-004". Damit ist die Kette aus dem
Beleg allein lesbar. Wird das Programm zwischendurch geschlossen, sagt der
Storno, unter welcher Nummer die berichtigte Rechnung gehoert; der Dialog
nennt sie ebenfalls, statt nur "bereits storniert" zu melden.
naechste_freie_nummer_nach() bestimmt die Folgenummer, damit sie nicht von der
Reihenfolge abhaengt, in der der Zaehler mitzieht.
Ausserdem: die Pruefstaende raeumen ihren Wegwerf-Ordner wieder weg, wenn sie
gruen sind. Ein Testlauf hatte 398 Ordner im Temp-Verzeichnis hinterlassen.
Bei Fehlern bleibt der Ordner stehen, damit man hineinsehen kann.
Weitere Funde des Code-Agenten behoben:
- "Kopie von Rechnung_...pdf" und klein geschriebene Dateinamen zaehlen jetzt
bei der Nummernvergabe mit (vorher galt die Nummer als frei).
- Strg+P feuerte auch aus einem offenen Dialog heraus (bind_all -> bind).
167 Pruefungen gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
Duplikatanzeige gehoert nicht hierher, sondern in den Steuerrechner - wieder
ausgebaut (duplikate.py, pruef_duplikate.py).
Zwei echte Loecher, die dabei auffielen:
1. vorhandene_rechnungen() uebersah Windows-Kopien. "Rechnung_2026-013 (1).pdf"
und "... - Kopie.pdf" galten nicht als vergeben, die Nummer wurde also ein
zweites Mal ausgegeben. Genau so ist der Altbestand entstanden. Jetzt zaehlt
alles mit, was nach der Nummer KEINE weitere Ziffer hat - "2026-0135" bleibt
getrennt.
2. Liegt eine Nummer mehrfach im Ordner, nahm der Storno-Dialog blind den ersten
Treffer. Jetzt erscheint eine Auswahlliste mit Datum, Name, Betrag und
Dateiname; ohne Auswahl passiert nichts, und die Meldung nennt die konkrete
Datei.
pruef_kernregeln.py: 37 Pruefungen (10 neue), pruef_nummern.py 10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
REGRESSION aus der Modulaufteilung (Code-Review-Agent):
- einstellungen.py fehlten "berechnung" und "datetime". Menue > Leistungskatalog
und > Rechnungsnummer stuerzten mit NameError ab und liessen ein leeres,
modales Fenster stehen. Preise und Nummernkreis waren nicht mehr einstellbar.
KEIN Pruefstand hat das gemerkt - keiner oeffnete je einen Dialog. Neu:
pruef_dialoge.py oeffnet ALLE Dialoge und schliesst sie wieder.
HAENGENDE ZWISCHENSPEICHER (derselbe Agent, gemessen):
- "Zuruecksetzen" liess storno_stand/berichtigung_stand stehen. Danach gehoerten
die Daten eines FREMDEN Gastes zum Storno der alten Rechnung, und die
Berichtigung schrieb ein Blatt mit Nummer A im Kenndatensatz und Nummer B auf
dem Blatt. reset_formular fragt jetzt nach und verwirft sauber.
- _neue_nummer_vorschlagen fasst die Nummer nicht mehr an, solange ein Vorgang
laeuft (traf auch dlg_nummer).
- Fenster schliessen mit offenem Storno fragt jetzt nach (WM_DELETE_WINDOW).
- _storno_verwerfen bricht ab, wenn das PDF nicht geloescht werden kann, statt
den Zaehler trotzdem zurueckzudrehen.
- Der Storno prueft die Kundenangaben und fragt, wenn die alte Rechnung sie
nicht hergibt.
- Zaehler nicht speicherbar -> sichtbare Meldung statt Traceback ins Nichts.
- storno.py: v1-Rueckfall nimmt den ersten Satz OHNE extra_blatt.
- EINE Quelle fuer die naechste Nummer: _neue_nummer_vorschlagen benutzt jetzt
naechste_freie_nummer, der Jahreswechsel steht nur noch dort. Vorher schlug
das Formular 2026-001 vor, waehrend der Storno-Weg 2025-088 nahm.
PRUEFSTAENDE (Audit-Agent: 16 von 27 eingebauten Fehlern blieben unbemerkt):
- Neu pruef_kernregeln.py (27 Pruefungen) fuer die zwei Regeln, um die es geht:
Nummer von HAND auf eine vergebene setzen, Zaehler hinter dem Ordner,
Jahreswechsel, Zaehler nur vorwaerts, Storno ueber den DIALOGKNOPF statt der
internen Methode, zweite Berichtigung am selben Tag. Der Bestand wird ueber
SHA256 verglichen - "Datei ist noch da" heisst nicht "unveraendert".
- Der Text des Storno-PDFs wird gelesen: Positionszeile negativ, nicht nur der
Summenblock.
- Tautologien raus: Selbstvergleich beim storno_datum, all() ueber eine leere
Liste, "nicht" in einem deutschen Text.
- Unangemeldeter Dialog laesst den Lauf scheitern, statt still "Nein" zu sagen.
- pruef_nummern.py: .PDF gross geschrieben, Rechnung_*.txt, echte Praefix-Falle.
- Gegenprobe: sechs Mutationen eingebaut, die vorher gruen blieben - alle sechs
werden jetzt rot.
RECHT (Gegenpruefungs-Agent): Zitate praezisiert. § 146 Abs. 4 AO verbietet nur
Aenderungen, bei denen der urspruengliche Inhalt nicht mehr feststellbar ist -
ein protokollierter Storno-Vermerk waere erlaubt, wir verzichten trotzdem
bewusst darauf. Der § 14c-Hinweis bleibt, gilt aber gegenueber Endverbrauchern
nicht (EuGH C-378/21, BMF v. 27.02.2024) - er zielt auf Firmengaeste.
142 Pruefungen gruen (100 + 27 + 8 + 7).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
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
Fuer Rechnungen, bei denen nur die Kundenangaben falsch sind - falsche
Betraege bleiben der Storno-Weg.
- Kein eigener Dialog: das Storno-Popup hat jetzt zwei Knoepfe. "Nur
berichtigen" laedt die Rechnung ins Formular, sperrt die Nummer und setzt
ein Flag; "PDF erstellen" schreibt daraus das berichtigte Blatt.
- Die Rechnung behaelt Nummer, Datum und Betraege; dazu kommt "Berichtigt am".
Der Zaehler bleibt stehen - das Blatt verbraucht keine Nummer.
- Ueberschrift "Berichtigte Rechnung", darunter die vollstaendige Rechnung,
darunter der Bezug nach § 31 Abs. 5 UStDV und der Satz, dass es KEINE
zusaetzliche Leistung und keine zweite Rechnung ist. Ohne den kann ein
zweites Blatt mit ausgewiesener USt die Steuer nach § 14c UStG ein zweites
Mal ausloesen.
- Kenndaten des Blattes tragen Nullen und "art": "berichtigung". Damit zaehlt
ein Programm, das die Art nicht kennt, 0,00 € statt den Umsatz doppelt; der
Steuerrechner ueberspringt es ganz (einnahmen.py).
- Dateiname "Berichtigte Rechnung_JJJJ-MM-TT_<Nummer>.pdf".
pruef_storno.py: 100 Pruefungen gruen, darunter der ganze Berichtigungsweg
inklusive Text auf dem Blatt und Gegenprobe mit dem Steuerrechner.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
Die bisherigen Rechnungen tragen den ganzen Namen in der Vornamen-Zeile und
oft gar keine Anschrift. Beim Stornieren stand dann nur "Andres Schaefer" da
und niemand wusste, wer der Gast ist.
- name_aufteilen(): am Leerzeichen trennen, das letzte Wort ist der Nachname.
- adresse_aus_pdf(): der Adressblock steht im Fliesstext zwischen
"Rechnung an:" und der Rechnungsnummer. Anrede wird an der Auswahlliste
erkannt, PLZ/Ort an der 4- bis 5-stelligen Zahl am Zeilenanfang, die Zeile
davor ist die Strasse - aber nur, wenn sie nicht die Namenszeile ist.
- kundendaten_ermitteln(): Kenndaten zuerst, Text als Rueckfall; benutzt vom
Storno (der geht an denselben Empfaenger) und vom Formular.
- Der Hinweis nach dem Storno sagt jetzt, was aus dem Text gelesen wurde und
was in der alten Rechnung schlicht nicht drinsteht.
Es wird nichts erfunden: fehlt die Anschrift in der alten PDF, bleiben die
Felder leer und die Pflichtpruefung greift.
pruef_storno.py: 80 Pruefungen gruen, darunter eine echte Altrechnung im
Muster "alles in der Vornamen-Zeile" - mit und ohne Anschrift.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
Leerzeichen allein waren schon vorher raus, aber "x" oder "123" als Nachname
und "12345" ohne Ort gingen durch.
- Felder werden vor der Pruefung gesaeubert (Rand- und Mehrfachleerzeichen),
damit geprueft wird, was nachher gedruckt wird.
- Vorname, Nachname/Firma, Strasse brauchen mindestens zwei Buchstaben.
- PLZ/Ort braucht mindestens vier Ziffern UND zwei Buchstaben - damit gehen
auch 4-stellige Postleitzahlen (AT, NL) durch, aber nicht PLZ ohne Ort.
- Fehlende Hausnummer wird nur nachgefragt, nicht gesperrt: Postfach- und
Feldweg-Anschriften gibt es wirklich, eine falsche Sperre waere schlimmer.
pruef_storno.py: 67 Pruefungen gruen, darunter Auslandsanschriften und kurze
Namen, die durchgehen MUESSEN.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
- Storno-Dialog: die alte Nummer wird eingetippt, das Programm sucht sie im
Ordner und zeigt sofort Datum, Name und den Betrag des Stornos. Kurze
Schreibweise (2026-3) findet 2026-003.
- Zwei Funde beim Pruefen: Storno-PDFs heissen "Storno_..." und fielen sowohl
aus der Ordnerliste als auch aus der Nummernpruefung heraus. Dadurch galt
eine schon stornierte Rechnung als stornierbar und eine vom Storno belegte
Nummer als frei - die haette ein zweites Mal vergeben werden koennen.
- Anrede ist eine Auswahlliste (tippbar fuer Sonderfaelle).
- Vorname, Nachname, Strasse und PLZ/Ort sind Pflicht; ohne sie wird keine
PDF geschrieben (§ 14 Abs. 4 Nr. 1 UStG). Die alte "trotzdem erstellen?"-
Frage ist raus.
Prueflauf: pruef_storno.py 46 Pruefungen gruen, pruef_nummern.py 7 gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
Eine ausgestellte Rechnung darf nicht geaendert und nicht geloescht werden
(§ 146 Abs. 4 AO), und jede Nummer gibt es nur einmal (§ 14 Abs. 4 Nr. 4
UStG). Korrigiert wird deshalb ueber ein eigenes Dokument mit neuer Nummer,
das sich auf die alte bezieht (§ 31 Abs. 5 UStDV).
- Knopf "Rechnung stornieren": alte Nummer waehlen, Programm liest deren PDF
und schreibt eine Stornorechnung mit eigener neuer Nummer, Betraege
negativ, mit Bezug auf Nummer und Datum der alten Rechnung.
- Danach steht das Formular auf der naechsten Nummer, gefuellt aus der alten
Rechnung; die Nummer ist gesperrt. "PDF erstellen" fragt noch einmal nach
und legt bei Nein das Storno-PDF wieder weg - dann bleibt allein das
Original stehen.
- Die alte Rechnung wird nie angefasst.
- Metadaten v3: art / storno_zu / ersetzt / storno_nummer, dazu Anschrift und
Positionen, damit eine Rechnung wieder ins Formular geladen werden kann.
Alle Felder aus v1/v2 bleiben unveraendert - daran haengt das Steuerjournal.
- Zaehler laeuft nur noch vorwaerts; eine vergebene Nummer wird nicht mehr
ueberschrieben, sondern die naechste freie angeboten.
- Combobox im Storno-Dialog blieb leer: die StringVar hing nur an einer
lokalen Variable und wurde weggeraeumt. Jetzt ohne textvariable.
Prueflauf (pruef_storno.py, 36 Pruefungen gruen): echte PDFs in einem
Wegwerf-Ordner, danach liest der Steuerrechner den Ordner - 001 + Storno +
Korrektur ergeben genau die berichtigte Rechnung, kein Beleg unsicher.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X