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
This commit is contained in:
TheMockTv 2026-09-03 21:24:12 +02:00
parent 31bb0c600b
commit dbe95e1ec6
6 changed files with 319 additions and 31 deletions

50
app.py
View file

@ -10,6 +10,7 @@ Start: Doppelklick auf "Beherbergungssteuer starten.bat" oder `python app.py`
"""
import os
import queue
import sys
import logging
from datetime import date
@ -42,6 +43,7 @@ if __name__ == "__main__":
_wurzel.destroy()
sys.exit(0)
import api
import db
import gemeinsam
import ordnerwahl
@ -82,6 +84,9 @@ class App(tk.Tk):
self.journal = db.Journal(JOURNAL)
self.buch = None # gemeinsames Nummernbuch, siehe gemeinsam.py
# Der eigene kleine Server. Klopft das Rechnungstool an, wird sofort
# nachgesehen - ohne auf den naechsten Durchgang der Wache zu warten.
self.api = api.MiniApi("journal", self._push_empfangen)
self.satz = float(self.journal.hole("satz", str(STANDARD_SATZ)))
self.pdf_ordner = self.journal.hole("pdf_ordner", "")
self.jahr = tk.IntVar(value=int(self.journal.hole("jahr", str(date.today().year))))
@ -107,6 +112,8 @@ class App(tk.Tk):
# Beide Programme laufen nebeneinander: schreibt das Rechnungstool eine
# Rechnung, meldet es das hier herein - siehe _wache_jetzt().
self._briefkasten_stand = "?" # "?" = noch nicht nachgesehen
self._push_kasten = queue.Queue() # Zettel aus dem API-Faden
self.after(250, self._push_abholen)
self._nachricht_stand = 0 # bis hierher sind Meldungen gelesen
self.after(600, self._wache)
# Beim Zurueckklicken sofort nachsehen statt zwei Sekunden zu warten.
@ -338,18 +345,43 @@ class App(tk.Tk):
self._buch_oeffnen()
if self.buch is None:
return
try:
self.buch.anmelden("journal", os.getpid(), os.path.basename(sys.executable))
except Exception as e: # noqa: BLE001
log.warning("Anmeldung fehlgeschlagen: %s", e)
# Die Mini-API aufmachen und mit Port und PID ins Telefonbuch: daran
# sieht das Rechnungstool, dass jemand zuhoert, und kann anklopfen.
self.api.starten(self.buch)
if not self.api.port:
try:
self.buch.anmelden("journal", os.getpid(),
os.path.basename(sys.executable))
except Exception as e: # noqa: BLE001
log.warning("Anmeldung fehlgeschlagen: %s", e)
def _abmelden(self):
if self.buch is None:
return
self.api.stoppen(self.buch)
def _push_empfangen(self):
"""Ruft die API aus IHREM Faden - Tkinter darf man von dort nicht anfassen.
Also nur einen Zettel in die Warteschlange legen; das Fenster holt ihn
gleich ab (_push_abholen).
"""
self._push_kasten.put(1)
def _push_abholen(self):
"""Im Fenster-Faden: liegt ein Zettel da, sofort in der SQLite nachsehen."""
try:
self.buch.abmelden("journal")
except Exception as e: # noqa: BLE001 - beim Schliessen nichts erzwingen
log.debug("Abmelden fehlgeschlagen: %s", e)
geklopft = False
while True:
try:
self._push_kasten.get_nowait()
geklopft = True
except queue.Empty:
break
if geklopft:
self._wache_jetzt()
except Exception as e: # noqa: BLE001 - darf das Fenster nie umwerfen
log.warning("Push: %s", e)
finally:
self.after(250, self._push_abholen)
def _buch_oeffnen(self):
ordner = self.journal.hole("gemeinsam_ordner", "")