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>
This commit is contained in:
commit
80967de26f
12 changed files with 1908 additions and 0 deletions
64
firma.py
Normal file
64
firma.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Firmendaten für den Briefkopf des Amts-Berichts.
|
||||
|
||||
Sie stehen bereits in der `config.json` des Rechnungstools – von dort werden sie
|
||||
gelesen, damit Rechnung und Steuerbericht garantiert denselben Kopf tragen und
|
||||
nichts doppelt gepflegt werden muss.
|
||||
|
||||
Wird das Rechnungstool nicht gefunden, greift ein neutraler Ersatz und der
|
||||
Bericht wird trotzdem gedruckt (nur ohne Logo/Bankzeile).
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
|
||||
log = logging.getLogger("bst.firma")
|
||||
|
||||
SUCHPFADE = [
|
||||
r"C:\claude\rechnungstool\config.json",
|
||||
os.path.join(os.path.expanduser("~"), "Documents", "rechnungstool", "config.json"),
|
||||
]
|
||||
|
||||
ERSATZ = {
|
||||
"name": "Campinghof Bartl",
|
||||
"untertitel": "Camping & Ferienwohnung am Markkleeberger See",
|
||||
"absender": "Campinghof Bartl - Bornaer Chaussee 36 - 04416 Markkleeberg OT Wachau",
|
||||
"inhaber": "", "bank": "", "iban": "", "bic": "",
|
||||
"homepage": "", "email": "", "telefon": "", "steuernummer": "", "logo": "",
|
||||
}
|
||||
|
||||
|
||||
def config_pfad(gespeichert: str = "") -> str:
|
||||
"""Erster gefundener Pfad zur config.json des Rechnungstools ('' = keiner)."""
|
||||
for p in ([gespeichert] if gespeichert else []) + SUCHPFADE:
|
||||
if p and os.path.isfile(p):
|
||||
return os.path.abspath(p)
|
||||
return ""
|
||||
|
||||
|
||||
def lade(gespeichert: str = "") -> dict:
|
||||
"""Firmendaten laden. Der Logo-Pfad wird absolut gemacht."""
|
||||
pfad = config_pfad(gespeichert)
|
||||
if not pfad:
|
||||
log.warning("config.json des Rechnungstools nicht gefunden – Ersatz-Briefkopf")
|
||||
return dict(ERSATZ)
|
||||
|
||||
try:
|
||||
with open(pfad, encoding="utf-8") as f:
|
||||
cfg = json.load(f)
|
||||
except Exception as e: # noqa: BLE001 - kaputte/fremde Datei
|
||||
log.warning("config.json nicht lesbar (%s): %s", pfad, e)
|
||||
return dict(ERSATZ)
|
||||
|
||||
daten = dict(ERSATZ)
|
||||
daten.update(cfg.get("firma", {}))
|
||||
|
||||
logo = str(daten.get("logo") or "").strip()
|
||||
if logo and not os.path.isabs(logo):
|
||||
kandidat = os.path.join(os.path.dirname(pfad), logo)
|
||||
daten["logo"] = kandidat if os.path.exists(kandidat) else ""
|
||||
|
||||
log.info("Firmendaten aus %s", pfad)
|
||||
return daten
|
||||
Loading…
Add table
Add a link
Reference in a new issue