Commit graph

42 commits

Author SHA1 Message Date
TheMockTv
f7c5a1618d Fassung 1.9.2
Aufraeumrunde nach der Pruefkette. Fuer den Nutzer sichtbar ist ein Punkt:
der Wechsel von einem Menuetitel zum anderen braucht nur noch EINEN Klick.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 18:41:34 +02:00
TheMockTv
96671027c8 Aufraeumen nach der Pruefkette: doppelter Code an eine Stelle
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_storno_verrechnet.py zaehlte in
  einer Zahl und konnte am Ende nicht sagen, WAS fehlschlug, pruef_bilder.py
  im Rechnungstool schrieb ein eigenes Format.

* 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.

* Die stummen "except OSError" in api.py, updater.py und einzelinstanz.py
  sagen jetzt, warum sie schweigen duerfen. Die 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
2026-09-07 18:39:03 +02:00
TheMockTv
039a23478f Zwei echte Fehler aus der Pruefkette behoben
## 1. Der Temp-Schutz war geschrieben, aber nicht angeschlossen

_ist_temp() stand seit heute Vormittag in ablage.py, ausfuehrlich begruendet
("Ein Merkzettel, der dorthin zeigt, wird deshalb verworfen") - und wurde von
NIEMANDEM gerufen. Der Schutz war ein Kommentar, keine Massnahme.

Zwei Pruefagenten haben das unabhaengig voneinander gefunden, einer mit
Messung: das Journal landete weiterhin im Temp-Ordner. Windows raeumt den von
selbst auf; es geht um aufbewahrungspflichtige Aufzeichnungen (§ 147 AO).

⚠️ Das ist die schlimmste Sorte Fehler - ein Kommentar, der eine
Schutzmassnahme zusichert, die es nicht gibt. Wer die Datei liest, haelt die
Falle fuer geschlossen. Und ich hatte sie dem Auftraggeber als behoben
gemeldet.

Behoben: _gemerkter_ordner() prueft jetzt wirklich.
pruef_temp_merkzettel.py sichert es ab - er prueft nicht, ob die FUNKTION
existiert, sondern ob sie WIRKT. Dazu die Gegenprobe, dass ein GUELTIGER
Merkzettel weiter befolgt wird: sonst haette der Schutz jemandem sein
Netzlaufwerk weggenommen.

⚠️ Im ersten Anlauf war dieser Pruefstand rot - weil ich seine Spielwiese mit
tempfile.mkdtemp() angelegt hatte und die selbst im Temp liegt. Wer das
Verhalten IM Temp-Ordner prueft, darf seine Spielwiese nicht dort aufbauen.

## 2. Der Darstellungsdialog zerstoerte sich beim ersten Klick selbst

Gleiche Ursache und gleiche Behebung wie im Rechnungstool: _oberflaeche_neu()
loeschte alle Kinder des Hauptfensters, und ein tk.Toplevel ist eines.
pruef_darstellung drueckt jetzt den Radioknopf statt cfg von Hand zu setzen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 18:10:41 +02:00
TheMockTv
dcc556217b pruef_installation hinterlaesst den Zustand, den er vorfindet
War das Programm vorher installiert, ist es danach wieder installiert. Beim
ersten Lauf war es das NICHT - danach stand ein deinstalliertes Programm da,
und der naechste Schritt (den Updater starten lassen) lief ins Leere.

Ein Pruefstand, der aufraeumt, muss auch sich selbst aufraeumen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 10:57:35 +02:00
TheMockTv
8cdd106a08 Windows-Symbol in den Programmfarben
Sein Befund: "hast du bei dem windows icon das gleich farbige wie im
programm, wo als wasserzeichen gilt, gemacht - weil das schaut blau aus".

Er hatte recht: auf der Kachel stand das ROHE Logo mit seinem Petrol
#004860, waehrend im Programm (Kopfzeile, Wasserzeichen) laengst die
umgefaerbte Fassung laeuft. Zwei Farben fuer dasselbe Zeichen.

Jetzt geht das Logo auch fuers Symbol durch _umfaerben() - dieselbe
Funktion, dieselben Farben: Tuerkis fuer die Wolke, Dunkelgrau fuer das
Zeichen daneben. Die Kachel ist weiss, also gilt die HELLE Fassung.

Fassung 1.9.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 10:52:02 +02:00
TheMockTv
1562388e78 Alles unter ravokk - und ein Deinstallieren laesst nichts liegen
Gleiche Umstellung wie im Rechnungstool, gleiche gemeinsame Dateien
(gemeinsam.py, ordnerwahl.py, wasserzeichen.py, bauen.py).

  %LOCALAPPDATA%/ravokk/
      journal.sqlite3, berichte/, Nummernbuch, config.json   <- Daten
      Rechnungstool/                                          <- Programm
      Steuerrechnungstool/                                    <- Programm

⚠ Hier gefunden und behoben: das Journal der INSTALLIERTEN Fassung lag im
  Temp-Ordner. Der Merkzettel (ablage.py) zeigte auf
  %TEMP%/abnahme_bst/Daten - haengengeblieben aus einem Abnahmelauf vom
  03.09.2026. Windows raeumt den Temp-Ordner von selbst auf; das Journal
  waere ohne Vorwarnung verschwunden. Ein Merkzettel, der dorthin zeigt,
  wird jetzt verworfen statt befolgt.

  Sein Echtbestand (238 Buchungen) lag davon unberuehrt in der Quelle und
  ist gesichert.

Kein Ordner-Dialog mehr beim ersten Start - der gemeinsame Ordner steht
fest. Der Knopf hiess dort "Install-Ordner auswaehlen...", was schon immer
falsch war: es geht um das gemeinsame Nummernbuch, nicht um den
Installationsort.

Uninstaller raeumt jetzt auch die vom Updater geladenen Fassungen weg.
pruef_installation.py prueft beides zusammen: Programmordner leer, Daten
unangetastet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 10:43:24 +02:00
TheMockTv
319c680a62 Logo in den Programmfarben, einen Tick groesser
Gleiche Umstellung wie im Rechnungstool (gemeinsame wasserzeichen.py): das
Blaugruen wird Tuerkis (#06C6A4), die zweite Haelfte weiss im Dunkeln und
dunkelgrau im Hellen, unterschieden nach Saettigung.

"beim steuertool koennte es ein tick groesser sein" - 28 -> 34 Pixel, wie im
Rechnungstool. Die Stelle bleibt rechts in der Kopfleiste: links stehen die
Bedienelemente (Jahr, Einlesen, Bericht), ein Logo davor wuerde sie alle nach
rechts schieben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 01:02:04 +02:00
TheMockTv
755c844ee4 Popups gehen mittig ueber dem Programmfenster auf
Gleiche Aenderung wie im Rechnungstool, gleiche theme.py: theme.mittig()
setzt jeden Dialog mittig ueber sein Elternfenster, theme.auf_bildschirm()
begrenzt auf den gesamten Desktop ueber alle Monitore statt auf den
Hauptmonitor.

Sein Befund: "da gehen noch die popups auf dem video monitor auf". Ursache
war ein `max(0, x)`, das jede negative Koordinate auf null klemmte - bei ihm
steht der zweite Monitor links (x = -1920).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 00:53:00 +02:00
TheMockTv
f57c7f52f4 Pruefstaende auf den zweiten Monitor, Desktop-Verknuepfung mit Symbol
Seine Ansage: "teste links auf dem 1080p monitor nicht mehr auf dem main ...
weil da schau ich nun video" - und danach "das nun der richtige das fuer
beide".

Dieses Programm hatte ueberhaupt keine Sonderposition fuer den Testlauf:
seine Pruefstandsfenster gingen mitten auf den Hauptbildschirm auf, waehrend
jemand daran arbeitete. Jetzt auf dem zweiten Monitor und ohne Eintrag in der
Taskleiste, wie im Rechnungstool.

Der Platz kommt aus theme.pruefplatz() - dieselbe Datei in beiden Programmen.

Dazu im Installer: der Haken "Verknuepfung auf dem Desktop" ist vorgesetzt
statt abgewaehlt, und jede Verknuepfung traegt IconFilename ausdruecklich.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 00:41:36 +02:00
TheMockTv
9d7aa1eec7 Darstellung: das Programm hatte ueberhaupt kein Theme
Sein Befund
  "und beim steuertool fehlt das theam in genze oder wird nicht durch die
   automatik gesetzt"
  "nur die einstellunden hilfe leiste die ist noch hell und der icon und
   titel leiste auch"

  Er hatte recht, und zwar wortwoertlich: dieses Programm lief im
  Tk-Standard, mit dreimal fest eingetragenem foreground="black". Es gab hier
  gar keine theme.py.

Gebaut
  theme.py aus dem Rechnungstool uebernommen und dabei von config.py geloest
  - eine Datei, die in BEIDEN Programmen liegt, darf nichts aus einem der
  beiden importieren. Beim ersten Uebernehmen flog sie genau daran beim
  Import auseinander.

  Die Einstellungen liegen hier in der Journal-Tabelle, nicht in einer
  config.json. _einstellungen() ist die Bruecke: etwas mit .get() und []=,
  wie hinweis.py und theme.py es erwarten.

  Menueleiste aus menueleiste.py statt tk.Menu - ein natives Menue laesst
  sich unter Windows nicht einfaerben, das war der letzte helle Rest.
  Treeview-Stil in theme.py ergaenzt (ttk zeichnet Listen nicht ueber den
  Grundstil), Reiter schmaler, damit alle zwoelf Monatsnamen lesbar bleiben.
  Die Summenleisten in gui_monat.py holen ihre Farben jetzt vom Fenster statt
  sie fest zu tragen - sie waren ein weisser Block unten im dunklen Bild.

  Logo und Fenstersymbol werden fuer die dunkle Darstellung aufgehellt.

⚠️ Altfehler behoben: die Meldung des Rechnungstools stand nie
  pruef_wache lief mal gruen und mal rot - je nachdem, wann er hinsah. Das
  war kein Wackler im Pruefstand, sondern sein Symptom: meldet das
  Rechnungstool eine neue Rechnung, laeuft sofort das Einlesen an, und dessen
  Ergebnis landete in derselben Zeile. Der Benutzer sah NIE, dass etwas
  hereingekommen war. melde() kennt jetzt einen Vorrang in Sekunden; die
  Meldung des Rechnungstools bekommt sechs. Dreimal hintereinander stabil
  gruen.

  Ein wackelnder Pruefstand ist keine Nebensache, die man wegdrueckt.

AUFGABE_STEUERSAETZE_DYNAMISCH.md
  Seine naechste Ansage notiert: die festen Saetze sollen raus, dynamisch per
  Tabelle wie im Rechnungstool. Mit dem, worauf dabei zu achten ist - ein
  Satz gilt ab einem DATUM, und die Saetze bereits erfasster Buchungen
  bleiben stehen (§ 147 AO).

Fassung 1.9.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-07 00:34:38 +02:00
TheMockTv
e4619259cb Release-Anhaenge: der Name entscheidet - und ein Pruefstand dafuer
Der Fehler
  Das Release war angelegt, die EXE hing dran - und der Updater haette
  trotzdem nie etwas gefunden. Der Anhang trug die Nummer im Namen, gesucht
  wird aber "Steuerrechnungstool.exe" (version.EXE_NAME). Die Nummer kommt
  erst beim Ablegen dazu.

  Das Tueckische: nichts schlaegt fehl. Der Updater meldet freundlich
  "Aktuell. Kein Update noetig." und startet die alte Fassung.

  Zweiter Fund: die Pruefsummen standen nur im Release-TEXT. Der Updater
  liest sie aus einer angehaengten Datei <exe>.sha256. Ohne die prueft er nur
  die Groesse - und eine verfaelschte Datei hat genau die richtige Groesse.

bauen.py legt jetzt release/ an, pruef_release.py prueft gegen das echte
Repository nach. Beide Dateien sind in beiden Programmen gleich.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 20:43:16 +02:00
TheMockTv
96aa51ac22 Kopflogo, Bau an einer Stelle, Startprobe fuer die EXE
Logo
  Das Programmlogo (Wolke mit Paragraphenzeichen) steht jetzt rechts in der
  Kopfleiste - damit sich die beiden Werkzeuge auf einen Blick unterscheiden.

bauen.py
  Der Weg von der Quelle zur Setup-Datei war eine Folge von Befehlen, die
  jemand von Hand eintippen musste. Wer einen Schritt vergisst, liefert eine
  Setup-Datei mit einer alten EXE aus - und sieht es ihr nicht an. Jetzt ist
  es ein Befehl, die Nummer kommt aus version.py, und am Ende stehen die
  SHA256-Summen fuer den Release-Text.

pruef_start_exe.py
  Prueft, was kein anderer Pruefstand prueft: ob die GEBAUTE EXE ein
  sichtbares Fenster zeigt. Alle uebrigen fahren das Programm aus der Quelle,
  dort trat der Fehler nie auf.

pruef_einzelinstanz.py wieder gruen
  Der Erprobungshinweis haette in jedem der drei Starts ein echtes Fenster
  geoeffnet - in einem eigenen Prozess laesst sich kein Dialog abfangen, es
  klickt niemand. Geprueft wird dort die SPERRE, nicht der Hinweis (der hat
  einen eigenen Pruefstand). Die Kenntnisnahme wird deshalb vorher
  eingetragen, und zwar mit genau dem Code, den auch der Klick auf "Ja"
  ausfuehrt. Das trifft nur die Kopie im Temp-Ordner: im echten Journal
  entsteht keine Zustimmung, die niemand gegeben hat.

Aufgeraeumt
  Beherbergungssteuer.exe und die gleichnamige .spec sind raus - das Programm
  heisst jetzt anders. Gebaute Dateien gehoeren ins Release, nicht ins Repo;
  die .spec-Dateien dagegen schon.

Fassung 1.8.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 20:35:23 +02:00
TheMockTv
b9094e7ebb updater.py und version.py nachgezogen (gleiche Dateien wie im Rechnungstool)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 16:42:35 +02:00
TheMockTv
40f53c85a0 Steuerrechnungstool: neuer Name und Erprobungshinweis wie im Rechnungstool
NAME
Das Programm heisst jetzt Steuerrechnungstool - wie sein Repository
(https://git.pcore.de/TheMockTv/Steuerrechnungstool). Umgestellt: Fenstertitel,
Kopfzeile, "laeuft bereits"-Meldung, Startdatei, Spec-Datei (EXE-Name), Logzeile.

NICHT umbenannt, mit Absicht:
  * "Beherbergungssteuer" als NAME DER STEUER - das ist ein Rechtsbegriff und
    steht weiter so in Berichten, Anmeldung und Oberflaeche.
  * LOCALAPPDATA\Beherbergungssteuer in ablage.py - dort liegt der Zeiger auf
    den Datenordner. Wer den umbenennt, kappt bestehenden Installationen den
    Weg zu ihren Daten.
  * Der lokale Ordner C:\claude\beherbergungssteuer - steht in Pruefstaenden
    und Spec-Dateien fest, eigener Schritt.

HINWEIS
hinweis.py aus dem Rechnungstool uebernommen (liegt in beiden Programmen
gleich). Der Hinweis kommt beim Start, Ablehnen beendet das Programm ohne
etwas zu vermerken, die Kenntnisnahme wird mit Benutzer, Zeit und Fassung in
der Einstellungstabelle des Journals gespeichert. Neu: Menue Hilfe -> Info mit
dem Text und der Signaturzeile.

PRUEFSTAENDE
Vier Prueflaeufe hatten gar keinen Dialogabfang - bisher fragte das Programm
beim Start nichts. Jetzt bleiben sie sonst vor einem echten Fenster stehen.
pruef_doppelte und pruef_storno_verrechnet haben einen bekommen, der bei
UNBEKANNTEN Fragen abbricht statt still "ja" zu sagen. pruef_storno_journal und
pruef_wache melden Hinweis und Freigabe ausdruecklich an. pruef_wache treibt
ausserdem die Ereignisschleife an (update), sonst kaeme after_idle nie dran.

pruef_wache: die Erwartung "im gemeinsamen Ordner liegt genau EINE Datei" ist
auf die richtige Menge gebracht - Nummernbuch UND Schluessel der Mini-API, der
seit dem 05.09.2026 dorthin gehoert. Alles darueber hinaus faellt weiter auf.

⚠️ pruef_wache bleibt ROT an einer Stelle, die NICHT von diesen Arbeiten kommt
(vor dem Umbau gemessen, war schon rot): die Statuszeile soll nach einem Push
"Rechnungstool meldet" zeigen, wird aber vom Ergebnis des Einlesens
ueberschrieben. Dokumentiert in AUFGABE_BEWEISKETTE_PRUEFBAR.md.

5 von 6 Pruefstaenden gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 16:24:43 +02:00
TheMockTv
f5f196151e README: Umbenennung nach Steuerrechnungstool vermerkt
Repository heisst jetzt https://git.pcore.de/TheMockTv/Steuerrechnungstool.
Der lokale Ordner bleibt vorerst beherbergungssteuer - der Pfad steht in
Pruefstaenden und Spec-Dateien fest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 15:55:57 +02:00
TheMockTv
ad5be5f1a5 gemeinsam.py nachgezogen: Spalte freigabe (gleiche Datei wie im Rechnungstool)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 15:42:55 +02:00
TheMockTv
876ee78311 pdf_parser: der Satz von der "Seite 2 fuers Amt" raus
Die Rechnung des Rechnungstools ist seit dem 05.09.2026 EIN Blatt. Der
Kopfkommentar behauptete weiter, Seite 2 sei die 1:1-Kopie fuers Amt.
Die Leselogik war davon nie betroffen - sie liest ohnehin nur Seite 1.

ABGRENZUNG, DAMIT DAS NICHT VERWECHSELT WIRD

Der "Bericht fuers Amt" (Monats-/Jahresbericht als PDF) BLEIBT. Das ist die
Steueranmeldung nach der kommunalen Satzung: eine Summenmeldung ohne
Gastnamen, kein zweiter Beleg zu einem Umsatz. Ohne sie kann der Betreiber
seine Beherbergungssteuer nicht anmelden.

Herausgenommen wurde nur das, was rechtswidrig war: das zweite Rechnungsblatt
mit derselben Rechnungsnummer und einem anderen Gesamtbetrag (§ 14 Abs. 4
UStG, § 14c UStG, § 146 AO, § 379 Abs. 1 Nr. 1 AO, § 370 AO) - und das lag im
Rechnungstool, nicht hier.

Ansage des Auftragnehmers: was nach dem Gesetz richtig ist, bleibt; im
Rechnungserstellungstool musste es raus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-06 15:33:36 +02:00
TheMockTv
7409fafb0b api.py nachgezogen: Schluessel und Bedienung (gleiche Datei wie im Rechnungstool)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
2026-09-05 18:24:59 +02:00
TheMockTv
379afbd9c1 Amtsbericht: Spalte "Art" mit R/S/B und Legende unter der Tabelle
Sein Einwand: "du musst die markieren als rechnung und storno oder
berichtigung, und das kannst einfach mit buchstaben machen: r fuer
rechnung, s fuer storno, b fuer berichtigung. am footer kannst eine
erklaerung fuer die buchstaben machen."

Er hat recht - ohne die Marke muss man aus der Begruendung raten, was fuer
ein Beleg die Zeile ueberhaupt ist. Mit dem Buchstaben liest sich die
Kette von selbst:

  2026-900  R  storniert mit 2026-901
  2026-901  S  neue Rechnung 2026-902
  2026-902  B  Neuausstellung
  2026-911  S  abgerechnet mit 2026-905     (Doppelungsfall)

Unter der Tabelle steht die Legende: "R = Rechnung, S = Stornorechnung,
B = berichtigte Rechnung (Neuausstellung nach einem Storno)". Bewusst
direkt unter die Tabelle und nicht in die Fusszeile - wer eine einzelne
Zeile prueft, hat sie dann vor Augen und muss nicht blaettern.

Dazu "neu abgerechnet mit" auf "abgerechnet mit" gekuerzt: mit dem S
davor ist das "neu" ueberfluessig, und die Zeile bricht nicht mehr um.
Spaltenbreiten neu verteilt (18/18/9/42/Rest/12/18/9/18 mm).

Erklaerungs-PDF um die Art-Spalte ergaenzt. Pruefkette gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 02:29:48 +02:00
TheMockTv
b2d933cb7c Amtsbericht: die Kette zeigt vorwaerts - Storno nennt die neue Rechnung
Sein Fund: "an der storno verweist du auf die alte rechnung, muss aber
lauten neu zu und neue rechnungs nummer. heisst kette ist so: rechnung
storniert weist auf die storno nummer, storno verweist auf neue rechnung.
wer soll denn sonst wissen wo er suchen muss."

Er hat recht: eine Zeile, die nur zurueckzeigt, laesst den Leser stehen.
Jetzt sagt jede Zeile, wo es WEITERGEHT:

  Rechnung   -> "storniert mit 2026-901"
  Storno     -> "neue Rechnung 2026-902"      (Fall A)
             -> "neu abgerechnet mit 2026-343" (Fall B, Doppelung)
             -> "Storno zu 2026-900"           (Fall C / alte Belege ohne Angabe)
  neue R.    -> "Neuausstellung"

Dafuer wandert die Folgenummer aus den PDF-Kenndaten bis ins Journal:
Buchung.folge_nummer + folge_art (neu | vorhanden | ""), gelesen aus
korrektur_nummer/ersatz_vorhanden/nur_storno, zwei neue DB-Spalten, alte
Journale bauen sich wie gehabt selbst um.

An seinen ECHTEN Belegen geprueft: Storno 2026-455 -> folge 2026-369
(vorhanden), 2026-456 -> 2026-343 (vorhanden). Die Angabe steht in den
Kenndaten schon drin, sie wurde bisher nur nicht gelesen.

Fenster und Blatt zeigen dieselben Worte. Erklaerungs-PDF um eine
Kettentabelle ergaenzt. Pruefkette gruen (storno_verrechnet inkl.
September-Blatt, doppelte_leistung, nur_storno).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 02:19:49 +02:00
TheMockTv
b4db3b3849 Erklaerung: eigener Abschnitt zur Rechnungsnummer
Auf seine Ansage: "erklaere dem auch das die rechnungs nummer nun fest
ist und nicht mehr aenderbar ist ausser mit dem storno butten".

Nachgesehen, was das Programm wirklich erzwingt, und genau das
aufgeschrieben - vier Sperren:

* eine vergebene Nummer wird nicht wiederverwendet (geprueft gegen die
  PDFs im Ordner UND das gemeinsame Nummernbuch); die vorhandene
  Rechnung wird nicht ueberschrieben, es wird die naechste freie
  angeboten
* der Zaehler kann nicht zurueck, auch nicht ueber die Einstellungen
* beim Storno ist das Nummernfeld gesperrt, dort vergibt nur das
  Programm
* keine Nummer auf Vorrat, wenn nichts folgt

Dazu der Hinweis, dass das Gesetz keine LUECKENLOSE Folge verlangt,
sondern eine EINMALIGE (§ 14 Abs. 4 Nr. 4 UStG) - vorwaerts darf es also
springen, zurueck nicht. Das ist genauer als "nicht mehr aenderbar" und
haelt einer Rueckfrage der Steuerberaterin stand.

Blatt hat jetzt vier Seiten; liegt auf dem Desktop und auf M:.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 02:09:59 +02:00
TheMockTv
965278020a Erklaerung fuers Amt / die Steuerberaterin als PDF
Auf seine Bitte: ein Blatt, das erklaert, WAS an Rechnungsschreibung und
Steuerbuch geaendert wurde, WARUM, und auf welche Paragraphen es sich
stuetzt. Drei Seiten, im Briefkopf des Betriebs.

Inhalt: Ausgangslage (dieselbe Leistung mehrfach im Ordner, unvollstaendige
Empfaengerangaben), die zwei festen Wege (Berichtigung / Storno), die drei
Storno-Faelle A/B/C, Pflichtfelder, Umgang mit doppelten Nummern, wie ein
Storno in die Steueranmeldung eingeht - dazu eine Tabelle mit elf
Fundstellen (UStG, UStDV, AO, SaechsKAG, Beherbergungssteuersatzung
Markkleeberg) und was im Programm daraus folgt.

Am Ende die zwei Punkte, die noch offen sind: steuerbefreite
Uebernachtungen (§ 4 Abs. 1 Nr. 1 der Satzung - Kinder bis 18, im Katalog
gibt es eine eigene Position dafuer) und die Abrundung je Uebernachtung
(§ 3 Abs. 3). Beide wirken zugunsten der Stadt, sind aber ungebaut - das
gehoert offen aufs Blatt und nicht verschwiegen.

Als Skript und nicht von Hand geschrieben, weil der Text Paragraphen
nennt: aendert sich das Programm, aendert man den Text hier und erzeugt
das Blatt neu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 01:57:20 +02:00
TheMockTv
ef3eef2852 Amtsbericht: Spalte heisst "Begruendung" und hat Platz
Sein Hinweis: "da ist noch so viel platz, die naechte und satz alleine
nehmen so viel raum ein auf dem blatt, da kannst locker zeile begruendung
oder so was setzen und da dann storno zu und die nummer vom storno".

Stimmt: die Zahlenspalten standen mit viel Luft nebeneinander, waehrend
die Begruendung klein gedruckt war. Neu verteilt (in mm):

  Datum 19 | Rechnung 19 | Begruendung 44 | Name Rest | Naechte 12 |
  Entgelt 19 | Satz 10 | Steuer 19

Damit passt "storniert mit 2026-901" in EINE Zeile, in normaler
Schriftgroesse statt 7,5 pt. Spaltenkopf heisst jetzt "Begruendung"
(sein Wort) und "Satz %" nur noch "Satz" - das Prozentzeichen steht
ohnehin nirgends im Wert.

Angesehen: Tabelle als Bild gerendert, alles einzeilig, auch mit langem
Namen. pruef_storno_verrechnet und pruef_berichtigung gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 01:40:03 +02:00
TheMockTv
87d92d15b6 Amtsbericht: eigene Spalte "Grund", und die stornierte Zeile nennt ihren Storno
Zwei Ansagen von ihm, beide am selben Blatt:

1. "weil die nummer hast nur auf der storno selber aber nicht am
   stornierten nummer um die es geht" - die aufgehobene Rechnung stand
   nur als "storniert" da. Jetzt steht dort "storniert mit 2026-901".
   Damit ist das Paar in BEIDE Richtungen lesbar, und das zaehlt vor
   allem dann, wenn der Storno in einem anderen Monat liegt und auf
   diesem Blatt gar nicht auftaucht.

2. "mach eine neue spalte mit grund oder so was" - der Vermerk stand als
   zweite Zeile unter der Rechnungsnummer. Jetzt ist es eine eigene
   Spalte "Grund" zwischen Rechnung und Name, eine Zeile je Buchung.
   Feste Breiten neu verteilt (20/20/34 mm + Rest fuer den Namen), damit
   nichts umbricht.

Dafuer neu: modell.aufhebungen() gibt {id der Rechnung: Storno-Buchung}
statt nur der ids - die Anzeige will auch sagen, WOMIT storniert wurde,
nicht nur DASS. aufgehobene() bleibt als duenne Huelle darueber, damit
zeig_stornos und doppelte_nummern unveraendert weiterlaufen.

Fenster und Blatt zeigen wieder dieselben Worte.

pruef_storno_verrechnet prueft beide Richtungen mit, auch ueber die
Monatsgrenze ("storniert mit 2026-911" im August, der Storno selbst steht
im September). Angesehen: Tabelle als Bild gerendert, alles einzeilig,
auch mit langem Namen. doppelte und berichtigung gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 01:38:36 +02:00
TheMockTv
3a9f1278c8 Amtsbericht beschriftet die Storno-Zeilen
Sein Wort: "musst dann rein schreiben storniert oder so was dran setzen".

Im Bericht fuers Amt stand bisher nur die Rechnungsnummer. Bei einem
Storno sieht das Amt damit eine Stornonummer neben einer voellig anderen
Rechnungsnummer und im Folgemonat eine Minuszeile - ohne einen Hinweis,
was wozu gehoert. Im Fenster gibt es dafuer die Spalte "Art", auf dem
Blatt fehlte sie.

Jetzt steht unter der Nummer in kleiner grauer Schrift dasselbe Wort wie
im Fenster: "storniert", "Storno zu 2026-900", "Neuausstellung". Die
Zuordnung wird ueber ALLE uebergebenen Buchungen bestimmt (das ganze
Jahr), weil der Storno in einem anderen Monat liegen kann als seine
Rechnung - genau der Fall, um den es geht.

An den Summen aendert sich nichts: verrechnet bleibt verrechnet.

pruef_storno_verrechnet prueft die drei Beschriftungen jetzt mit.
Angesehen wurde es auch: Monatsbericht August und September als Bild
gerendert, Zeilen und Summen stimmen (August 9 Naechte/117,00,
September -4/-52,00).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 01:20:02 +02:00
TheMockTv
13fe1d97f9 Storno wird wieder VERRECHNET statt weggelassen - seine Entscheidung
Heute Nacht war es andersherum gebaut (v1.6.3): Storno und aufgehobene
Rechnung zaehlten gar nicht mehr mit, die Berichtigung landete im Monat
der Rechnung. Sauber nach § 7 Abs. 5 der Satzung (angemeldet wird die im
Kalendermonat VEREINNAHMTE Steuer), aber nicht das, was er will.

Sein Wort:

    "ich wuerde das wie beim alten lassen, nicht das er der Stadt zu
     wenig gibt"
    "ob er im Sep dann weniger gemacht hat ist doch egal, weil im August
     hat er ja mehr - also gleicht es sich aus, es ist nur ein
     Time-Problem. Aber um was es mir geht: die Steuern sind sauber."

Und er hat recht: der Unterschied ist NUR der Monat, nie das Jahr, und
die Richtung stimmt - zu viel zuerst ist beim Amt nie ein Problem, zu
wenig schon.

Also zurueckgebaut:
- modell.zaehlbar() ist wieder raus, summiere() summiert alle Zeilen mit
  ihrem Vorzeichen. Die Begruendung samt Satzungs-Fundstelle steht im
  Docstring, damit es niemand "repariert" - in EINEM Monat sieht eine
  verrechnete Doppelung naemlich nach einem Fehler aus.
- Amtsbericht zeigt Rechnung und Storno wieder beide, jede in ihrem Monat
  und mit ihrem Vorzeichen. Damit erklaert sich die Meldung von selbst.
- aufgehobene() bleibt, wird aber nur noch fuer die Spalte "Art" und fuer
  die Dubletten-Meldung gebraucht, nicht mehr fuers Rechnen.

Nicht zurueckgebaut (das war eine eigene Ansage): Storno und aufgehobene
Rechnung werden NICHT mehr ausgegraut, sie stehen normal da und sind ueber
die Spalte "Art" gekennzeichnet.

pruef_storno_rechnet_nicht.py ist durch pruef_storno_verrechnet.py
ersetzt: derselbe Aufbau (Fake-Rechnungen in einer echten SQLite, auch
der Fall ueber die Monatsgrenze), aber es haelt jetzt das gewollte
Verhalten fest - August 9 Naechte/117,00, September -4/-52,00, Jahr
5/65,00. Restliche Kette (storno_journal, doppelte, berichtigung,
einzelinstanz, wache) gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 01:09:08 +02:00
TheMockTv
d9bff8f2ec Blick-Skript: was die Stornos in einem Journal bewirken
Reines Lesen - keine Buchung wird angelegt, geaendert oder geloescht und
der Rechnungsordner wird nicht gescannt. Damit kann man es ohne Sorge auf
das echte Journal loslassen.

Zeigt je Monat die alte Rechenweise (Rechnung + und Storno - heben sich
gegenseitig auf) gegen die jetzige (Storno und aufgehobene Rechnung
zaehlen gar nicht mit) und darunter jedes Storno-Paar einzeln, mit dem
Hinweis, wenn Rechnung und Storno in VERSCHIEDENEN Monaten liegen. Genau
dort unterscheiden sich die beiden Rechenweisen.

Anlass: die Frage "stimmen die 8.500 Euro jetzt" laesst sich nur an den
echten Daten beantworten, nicht durch Herleitung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 01:05:59 +02:00
TheMockTv
448afb3c62 Storno wird nicht mehr mitgerechnet, und nicht mehr ausgegraut
Seine Ansage: "wenn es als storno getagt ist darf der rechner das nicht
mehr rechnen weil es minus ist, die rechnung gibt es nicht mehr" - und
"ausgrauen wuerde ich es nicht, ich wuerde es nur als storno taggen".

Bisher standen Rechnung (+) und Storno (-) beide in der Summe und hoben
sich gegenseitig auf. Naechte, Entgelt und Steuer kamen dabei zwar
richtig heraus, aber:

* die Zahl "Rechnungen" war je Stornofall um ZWEI zu hoch - im Fenster
  wie im Amtsbericht, und
* lag der Storno in einem anderen MONAT als seine Rechnung, stand in
  jedem der beiden Monate die Haelfte der Verrechnung allein da: der
  August meldete eine Uebernachtung zu viel, der September eine zu wenig.
  Erst im Jahr hob sich das wieder auf.

Neu ist modell.zaehlbar(): Storno und die von ihm aufgehobene Rechnung
zaehlen gar nicht mehr mit. summiere() geht durch diesen Filter, das Set
der aufgehobenen Rechnungen wird ueber das ganze JAHR bestimmt und an
Monatsleiste, Jahresleiste und Amtsbericht durchgereicht.

Der Amtsbericht zeigt die beiden Zeilen auch nicht mehr an - die
Rechnung gibt es nicht mehr, und Minuswerte auf dem Blatt fuers Amt
waeren ohne die Gegenzeile nicht erklaerbar.

Im Fenster bleibt alles sichtbar, nur nicht mehr grau: der Hinweis
steht in der Spalte "Art" (Storno zu .../storniert/Neuausstellung).

Pruefstand pruef_storno_rechnet_nicht.py (neu, 22 Pruefungen) legt die
Faelle als Fake-Rechnungen in einer echten SQLite an - auch den Fall
ueber die Monatsgrenze, den echte Daten nicht hergeben - und prueft
Rechenkern, Amtsbericht-PDF und das echte Fenster. Die uebrige
Pruefkette (storno_journal, doppelte, berichtigung, einzelinstanz,
wache) laeuft unveraendert gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bEsoFUk16DfnNA7MjY36H
2026-09-04 00:10:19 +02:00
TheMockTv
0218abaebe Im Journal wird nichts mehr von Hand geloescht
Sein Einwand: 'wenn man in der beherbergungstool ein datensatz loescht, bleibt
die in der sqlite - oder du patchst es raus, dass man das garnicht mehr loeschen
kann'.

Beides stimmt. Im gemeinsamen Nummernbuch BLEIBT die Nummer stehen, und das ist
richtig: vergeben ist vergeben, die Rechnung liegt beim Gast. Das Loeschen im
Journal gehoert dagegen weg - eine Zeile aus einer PDF kaeme beim naechsten
Einlesen ohnehin zurueck, eine Zeile aus dem Excel-Altbestand (quelle='xlsx')
gibt es dagegen nirgends sonst; die waere fuer immer weg, samt Uebernachtung im
Amtsbericht. § 146 Abs. 4 AO verbietet Aenderungen, bei denen der urspruengliche
Inhalt nicht mehr feststellbar ist.

Raus sind: Papierkorb-Knopf, Entf-Taste, Menuepunkt und die Haken-Spalte, die
nur dafuer da war. Damit ist das Monatsblatt reine Anzeige.

Der Weg, der bleibt: die PDF aus dem Rechnungsordner nehmen - dann raeumt der
Scan die Zeile von selbst weg, und nur dann, wenn das Laufwerk erreichbar ist
(ein abgezogenes NAS darf die Buchhaltung nicht leeren).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 22:43:23 +02:00
TheMockTv
c230a27cff Angebote werden nicht gebucht - doppelt gesichert
Das Rechnungstool schreibt jetzt unverbindliche Angebote (frueher Proforma).
Uebersprungen werden sie zuerst ueber die Kenndaten (art=angebot, die
ueberleben auch ein Umbenennen) und, falls die einmal fehlen, ueber Dateiname
und Unterordner ('Angebot_...' bzw. 'Angebote/') - sein Vorschlag: 'kann er ja
am dateinamen festmachen, steht ja dann rechnung oder angebot'. Eine echte
Rechnung wird davon nicht erfasst, das prueft pruef_angebot.py mit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 21:41:14 +02:00
TheMockTv
dbe95e1ec6 Mini-API, Push vom Rechnungstool, Proforma wird nicht gebucht
Das Journal macht beim Start einen winzigen Server auf 127.0.0.1 auf und traegt
Port und PID in die gemeinsame SQLite ein (Tabelle "laeuft"). Das Rechnungstool
sieht daran, dass jemand zuhoert, und klopft nach jeder Rechnung an: "schau in
die sqlite". Dann wird sofort nachgelesen, statt bis zum naechsten Durchgang zu
warten. Faellt die API aus, findet die Wache die Meldung trotzdem - ein os.stat
auf die eine Datei, alle zwei Sekunden und sofort beim Zurueckklicken.

Die Proforma-Rechnung wird NICHT gebucht: keine_buchung() kennt jetzt
Berichtigung und Proforma. Der Scan fragt wieder keine_buchung() - seit dem
Berichtigungs-Umbau tat er das nicht mehr, und die Proforma waere als Buchung
im Journal gelandet (der Pruefstand hat es gefunden).

Pruefstand pruef_wache.py: 31 Pruefungen ueber BEIDE Programme - Anmeldung mit
PID, ping ("hallo, bin noch da"), genau eine Datei im gemeinsamen Ordner, Push
nach Rechnung und nach Storno, Einlesen samt Anzeige, Rueckfallebene ohne API,
tote PID wird weggeraeumt, kein Melden an ein geschlossenes Journal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 21:24:12 +02:00
TheMockTv
31bb0c600b Neue Rechnungen tauchen von selbst auf - das Journal hoert auf die gemeinsame SQLite
Stehen beide Programme offen und wird im Rechnungstool eine Rechnung
geschrieben, erscheint sie hier ohne Zutun. Das Journal traegt sich dafuer beim
Start mit seiner PID in der gemeinsamen SQLite ein (Tabelle "laeuft") und traegt
sich beim Schliessen wieder aus; das Rechnungstool sieht daran, dass jemand
zuhoert, und legt eine Zeile in die Tabelle "nachrichten".

Nachgesehen wird nur dort - erst ein os.stat auf die eine Datei, und nur wenn
sich etwas geruehrt hat, wird sie geoeffnet. Kein Absuchen des
Rechnungsordners, kein Server, kein Port. Beim Zurueckklicken ins Fenster wird
sofort nachgesehen statt zwei Sekunden zu warten.

Die Wache faengt jeden Fehler ab und stirbt nie - ein Netzlaufwerk, das kurz
weg ist, darf das Fenster nicht lahmlegen.

⚠ Ein Denkfehler daraus gleich behoben: der erste Blick nach dem Start merkt
sich den Stand AUCH dann, wenn es die Datei noch gar nicht gibt. Sonst galt die
erste Meldung danach als "schon gesehen" und wurde verschluckt.

Pruefstand pruef_wache.py (faehrt BEIDE Programme): 23 Pruefungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 21:02:24 +02:00
TheMockTv
59d2db75af Storno und Berichtigung kommen an, gemeinsames Nummernbuch, kein Bearbeiten mehr
Storno: das Journal zaehlte die Uebernachtungen der aufgehobenen Rechnung
weiter mit (4 - 0 + 3 = 7 statt 3 gemeldeter Naechte). Die Betraege kuerzten
sich, die Naechte nicht. Der Storno traegt jetzt die negative Zahl, und das
Journal kennt Art, Bezug und Datum des Belegs (vier neue Spalten, alte
Journale bauen sich beim Oeffnen um).

Berichtigung: das Blatt wurde nur uebersprungen. Der berichtigte NAME kommt
jetzt in der Buchung an - im Amtsbericht stand sonst weiter der falsche.
Angewandt wird erst am Ende des Scans, das Blatt kann vor seiner Rechnung im
Ordner liegen.

Doppelte Nummern: eine stornierte Rechnung ist keine offene mehr und faellt aus
der Meldung. Zugeordnet wird ueber Nummer + Datum + Empfaenger, nicht ueber die
Nummer allein - bei einer doppelt vergebenen Nummer waere die kein eindeutiger
Bezug, und genau den verlangt § 31 Abs. 5 UStDV. Die Texte nennen jetzt den
Weg: eine der beiden im Rechnungstool stornieren und mit freier Nummer neu
ausstellen (§ 14 Abs. 4 Nr. 4 UStG - jede Nummer nur einmal).

Neue Spalte "Art": Storno zu ..., storniert, Neuausstellung. Aufgehobene Zeilen
stehen grau - geloescht wird nichts.

Gemeinsames Nummernbuch (gemeinsam.py, ordnerwahl.py - in beiden Programmen
dieselbe Datei): eine SQLite in einem Ordner, den beide kennen. Das Journal
traegt seine Nummern ein, auch die aus der Excel-Mappe ohne PDF - genau die
kannte das Rechnungstool nicht und vergab sie ein zweites Mal. Beim ersten
Start wird nach dem Ordner gefragt (auswaehlen, OK, Sicherheitsfrage, bei Nein
zurueck ins Feld); wer ihn nicht hat, kommt mit "Spaeter einrichten" weiter.

Kein Doppelklick zum Bearbeiten mehr (gui_dialoge.py geloescht): wer hier Betrag
oder Nummer verstellt, meldet dem Amt etwas anderes, als auf dem Beleg steht.
Loeschen bleibt.

--test / CAMPINGHOF_TEST=1 unterdrueckt den Erststart-Dialog (Pruefstaende).

Pruefstaende: pruef_storno_journal.py (neu, ueber BEIDE Programme: Storno,
Berichtigung, doppelte Nummer aufloesen), pruef_doppelte, pruef_berichtigung,
pruef_einzelinstanz - alle gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 20:38:38 +02:00
TheMockTv
9e564466c7 Der Fund der Dubletten steht auch im Log
Der Amtsbericht wird aus diesen Zeilen gebaut - es muss spaeter nachvollziehbar
sein, wann eine doppelt vergebene Nummer zuerst dastand. Eine Zeile je
Auffrischung, mit Jahr, Anzahl und den Nummern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 19:51:14 +02:00
TheMockTv
894bc81c46 Doppelte Rechnungsnummern zeigen, nur ein Fenster, keine Handbuchungen
Doppelte Rechnungsnummern werden ANGEZEIGT statt still mitgeschleppt: rote
Zeile mit Warnzeichen, markierter Monatsreiter, rote Zeile unter der
Jahressumme und eine Liste aller Belege mit Dateinamen. Gerechnet wird ueber
das ganze Jahr - liegt die zweite Rechnung im naechsten Monat, sieht kein
Monat fuer sich eine Dublette, das Amt bekommt sie trotzdem doppelt. Die
Betraege bleiben in allen Summen und im Amtsbericht; gemeldet wird der Fund,
korrigiert wird nichts von allein.

Vorgeschichte: bis v1.2 war die Rechnungsnummer der Schluessel der Tabelle -
die zweite Rechnung ueberschrieb die erste still und fehlte im Amtsbericht.
v1.3 hat den Schluessel auf die PDF-Datei umgestellt, seitdem bleiben beide
Zeilen stehen. Erst jetzt sieht man den Fall auch.

Einzelinstanz aus dem Steuerrechner uebernommen (nur Mutex- und PID-Name
geaendert): zwei Fenster lesen denselben Rechnungsordner in dieselbe
journal.sqlite3 - was das eine loescht, steht im anderen noch da, und wer
dort "PDF fuers Amt" drueckt, meldet einen Stand, den es nicht mehr gibt.
Die Sperre greift vor ablage.daten_ordner() und nur beim echten Start.

"Neue Buchung" ist raus: jede Zeile gehoert zu einer Rechnung aus dem
Rechnungstool. Wer eine Buchung braucht, schreibt die Rechnung. Bestehende
Zeilen lassen sich weiter bearbeiten.

Pruefstaende: pruef_doppelte.py (27 Pruefungen am echten Fenster),
pruef_einzelinstanz.py (echte Prozesse). Beide gruen, dazu Abnahme mit den
Augen an Hauptfenster, Liste und Bearbeiten-Dialog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
2026-09-03 19:47:44 +02:00
TheMockTv
de71fce64f Eigener Datenordner (ablage.py)
Als EXE lagen Journal, Berichte und Log bisher direkt neben der EXE. Damit
laesst sich das Programm nicht in einen Ordner legen, in den Windows nicht
schreiben laesst - und beim Sichern uebersieht man leicht die Haelfte.

Jetzt: beim ersten Start ein Ordner "Daten" neben der EXE, alles darin. Geht
das nicht, weicht es nach LOCALAPPDATA aus. Was schon neben der EXE lag, zieht
mit um - sonst waere das Journal ploetzlich leer.

Ist der gemerkte Ordner nicht erreichbar (Stick ab, NAS aus), wird NICHTS
geaendert und der Merkzettel bleibt stehen: morgen steckt der Stick wieder
dran und alles ist da, wo es war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
2026-09-02 21:44:51 +02:00
TheMockTv
65eec9937a Storno und Berichtigung: das Journal darf die Buchung nicht verlieren
Das Rechnungstool schreibt seit heute auch Storno- und Berichtigungsblaetter in
denselben Ordner. Zwei Fehler, die daraus entstanden waeren - beide still:

1. Ein Berichtigungsblatt (§ 31 Abs. 5 UStDV) traegt die Nummer DER RECHNUNG,
   die es berichtigt, und lauter Nullen. Unter dem alten Schluessel
   (jahr, rechnungsnummer) hat es die echte Buchung ueberschrieben - im
   Amtsbericht fehlte die Uebernachtung dann. Wird jetzt uebersprungen
   (pdf_parser.keine_buchung), in beiden Scannern.
2. Der Schluessel ist jetzt die DATEI. Zwei Rechnungen mit derselben Nummer -
   der Altbestand, bevor das Rechnungstool eine Sperre bekam - ueberschrieben
   sich sonst gegenseitig. Bestehende Journale werden beim Oeffnen einmalig
   umgebaut, in einer Transaktion, mit Rueckfall auf den alten Stand.
   Buchungen von Hand (kein PDF-Pfad) bleiben davon unberuehrt.

Stornos zaehlen weiter mit - sie sind negativ und heben die Uebernachtung im
Bericht genau so auf, wie es sein soll.

pruef_berichtigung.py (neu): schreibt mit dem echten Renderer des
Rechnungstools eine Rechnung, ein Berichtigungsblatt dazu und zwei Rechnungen
mit derselben Nummer, liest sie ein und prueft das Ergebnis in der Tabelle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
2026-09-02 21:39:41 +02:00
TheMockTv
700ddc3bd1 Fusszeile raus - sie ragte in die Tabelle
Der Briefkopf-Fuss (Bank, Steuernummer, Inhaber, Homepage, E-Mail, Telefon) wurde
oberhalb des unteren Seitenrands gezeichnet und lief damit in den Textbereich. Auf
vollen Seiten stand er quer ueber der letzten Tabellenzeile. Die Kontaktdaten waren
zudem Platzhalter (example.de).

Es bleibt die Seitenzahl, bewusst unterhalb von MARGIN_BOT.
2026-07-13 20:59:20 +02:00
TheMockTv
7c66a669b4 Amtsbericht ohne Bankverbindung und Steuernummer
Die Fusszeile druckte Bankname, IBAN, BIC und Steuernummer. In einer Meldung
ans Amt haben die nichts verloren - es zieht nichts ein und ueberweist nichts.
Es bleiben Inhaber (wer meldet) und die Kontaktdaten fuer Rueckfragen; leere
Felder werden uebersprungen. Auf der Rechnung bleibt alles unveraendert.
2026-07-13 20:47:04 +02:00
TheMockTv
6a8cb0849f Nachname aus den PDF-Metadaten, Anrede nicht mehr als Name lesen
Der Parser nahm die erste Zeile unter "Rechnung an:" als Namen. Steht im
Rechnungstool eine Anrede, war das "Herr" statt "Mustermann".

- Neue Rechnungen: Kenndaten kommen aus den PDF-Metadaten (JSON), inkl.
  getrenntem Nachnamen. Nichts wird mehr geraten.
- Alte Rechnungen ohne Metadaten: der Adressblock wird gesammelt, reine
  Anrede-Zeilen (Herr/Frau/Familie/Firma) werden uebersprungen, fuehrende
  Anreden abgeschnitten.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:45:55 +02:00
TheMockTv
2b7990b1b6 Firmendaten portabel suchen + Menuepunkt zum Auswaehlen
Die config.json des Rechnungstools wurde nur unter dem festen
Entwicklungspfad gesucht - als EXE auf einem anderen Rechner haette der
Bericht keinen Briefkopf bekommen. Jetzt: neben dem Programm, im
Nachbarordner, in Dokumente, und ueber "Daten -> Firmendaten waehlen".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:22:17 +02:00
TheMockTv
80967de26f Beherbergungssteuer: Steuerjournal aus den Rechnungs-PDFs
Ersetzt die Excel-Mappe des Campinghofs. Die Rechnungs-PDFs des
Rechnungstools sind die Quelle; SQLite ist nur Cache, Excel nur noch
Import des Altbestands. Bericht fuers Amt als PDF im Briefkopf der
Rechnungen (Firmendaten aus der config.json des Rechnungstools).

- pdf_parser: liest Datum, Nummer, Name, Naechte, Zwischensumme, Satz
- db: Journal + Scan mit Cache (Pfad/mtime/Groesse)
- xlsx_io: Import der alten Tabelle, vereinheitlicht Rechnungsnummern
- bericht_pdf: Monats- und Jahresbericht (reportlab)
- GUI: Monatsreiter, Suche, Anhaken + Papierkorb, Kennzahlen-Leiste

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:15:44 +02:00