Vor- und Nachname getrennt + Kenndaten in die PDF-Metadaten
Bisher gab es nur ein Feld "Name / Firma". Stand in der Anrede etwas, war die Anrede die erste Zeile des Adressblocks - das Steuerjournal hat sie als Namen gelesen. - Kundenblock hat jetzt "Vorname (optional)" und "Nachname / Firma". Auf der Rechnung stehen beide wie gewohnt in einer Zeile. - Die Kenndaten der Rechnung (Nummer, Datum, Nachname, Naechte, Zwischensumme, Steuersatz und -betrag) stehen zusaetzlich als JSON in den PDF-Metadaten. Das Steuerjournal liest sie von dort und muss nichts mehr aus dem Fliesstext raten. Der Ausdruck aendert sich nicht. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dc170a9d9c
commit
0c83f9d821
2 changed files with 42 additions and 5 deletions
20
app.py
20
app.py
|
|
@ -265,13 +265,15 @@ class RechnungsApp(tk.Tk):
|
||||||
kunde = ttk.LabelFrame(top, text="Rechnung an (Kunde)", padding=8)
|
kunde = ttk.LabelFrame(top, text="Rechnung an (Kunde)", padding=8)
|
||||||
kunde.grid(row=0, column=0, sticky="nsew", padx=(0, 10))
|
kunde.grid(row=0, column=0, sticky="nsew", padx=(0, 10))
|
||||||
self.k_anrede = tk.StringVar()
|
self.k_anrede = tk.StringVar()
|
||||||
self.k_name = tk.StringVar()
|
self.k_vorname = tk.StringVar()
|
||||||
|
self.k_name = tk.StringVar() # Nachname oder Firma – die Zuordnung im Steuerjournal
|
||||||
self.k_zusatz = tk.StringVar()
|
self.k_zusatz = tk.StringVar()
|
||||||
self.k_strasse = tk.StringVar()
|
self.k_strasse = tk.StringVar()
|
||||||
self.k_plzort = tk.StringVar()
|
self.k_plzort = tk.StringVar()
|
||||||
felder = [
|
felder = [
|
||||||
("Anrede (optional)", self.k_anrede),
|
("Anrede (optional)", self.k_anrede),
|
||||||
("Name / Firma", self.k_name),
|
("Vorname (optional)", self.k_vorname),
|
||||||
|
("Nachname / Firma", self.k_name),
|
||||||
("Zusatz (optional)", self.k_zusatz),
|
("Zusatz (optional)", self.k_zusatz),
|
||||||
("Straße / Nr.", self.k_strasse),
|
("Straße / Nr.", self.k_strasse),
|
||||||
("PLZ / Ort", self.k_plzort),
|
("PLZ / Ort", self.k_plzort),
|
||||||
|
|
@ -503,7 +505,13 @@ class RechnungsApp(tk.Tk):
|
||||||
"Es ist kein Kundenname eingetragen. Trotzdem PDF erstellen?"):
|
"Es ist kein Kundenname eingetragen. Trotzdem PDF erstellen?"):
|
||||||
return
|
return
|
||||||
|
|
||||||
kunde_zeilen = [self.k_anrede.get(), self.k_name.get(), self.k_zusatz.get(),
|
# Auf der Rechnung stehen Vor- und Nachname wie gewohnt in einer Zeile;
|
||||||
|
# der Nachname geht zusätzlich getrennt mit, damit das Steuerjournal ihn
|
||||||
|
# nicht aus dem Adressblock raten muss.
|
||||||
|
nachname = self.k_name.get().strip()
|
||||||
|
vorname = self.k_vorname.get().strip()
|
||||||
|
namenszeile = " ".join(t for t in (vorname, nachname) if t)
|
||||||
|
kunde_zeilen = [self.k_anrede.get(), namenszeile, self.k_zusatz.get(),
|
||||||
self.k_strasse.get(), self.k_plzort.get()]
|
self.k_strasse.get(), self.k_plzort.get()]
|
||||||
kopf = {
|
kopf = {
|
||||||
"rechnungsnummer": nummer,
|
"rechnungsnummer": nummer,
|
||||||
|
|
@ -512,6 +520,8 @@ class RechnungsApp(tk.Tk):
|
||||||
"abreise": self.r_abreise.get().strip(),
|
"abreise": self.r_abreise.get().strip(),
|
||||||
"naechte": self.r_naechte.get() if self.r_naechte.get() != "–" else "",
|
"naechte": self.r_naechte.get() if self.r_naechte.get() != "–" else "",
|
||||||
"kunde_zeilen": kunde_zeilen,
|
"kunde_zeilen": kunde_zeilen,
|
||||||
|
"nachname": nachname,
|
||||||
|
"vorname": vorname,
|
||||||
}
|
}
|
||||||
out_dir = config.ensure_output_dir(self.cfg)
|
out_dir = config.ensure_output_dir(self.cfg)
|
||||||
fname = f"Rechnung_{safe_filename(nummer)}"
|
fname = f"Rechnung_{safe_filename(nummer)}"
|
||||||
|
|
@ -547,8 +557,8 @@ class RechnungsApp(tk.Tk):
|
||||||
self._neue_nummer_vorschlagen()
|
self._neue_nummer_vorschlagen()
|
||||||
|
|
||||||
def reset_formular(self):
|
def reset_formular(self):
|
||||||
for v in (self.k_anrede, self.k_name, self.k_zusatz, self.k_strasse, self.k_plzort,
|
for v in (self.k_anrede, self.k_vorname, self.k_name, self.k_zusatz,
|
||||||
self.r_anreise, self.r_abreise):
|
self.k_strasse, self.k_plzort, self.r_anreise, self.r_abreise):
|
||||||
v.set("")
|
v.set("")
|
||||||
self.r_datum.set(datetime.date.today().strftime("%d.%m.%Y"))
|
self.r_datum.set(datetime.date.today().strftime("%d.%m.%Y"))
|
||||||
for av in self.anzahl_vars.values():
|
for av in self.anzahl_vars.values():
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ im Layout der Excel-Vorlage:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
from reportlab.lib.pagesizes import A4
|
from reportlab.lib.pagesizes import A4
|
||||||
from reportlab.lib.units import mm
|
from reportlab.lib.units import mm
|
||||||
|
|
@ -324,6 +325,31 @@ def _seite_inhalt(story, st, cfg, rechnung, kopf, gesamtrechnung_betont):
|
||||||
story.append(KeepTogether(block))
|
story.append(KeepTogether(block))
|
||||||
|
|
||||||
|
|
||||||
|
def _kenndaten(rechnung, kopf):
|
||||||
|
"""
|
||||||
|
Kenndaten der Rechnung als JSON in die PDF-Metadaten (Feld "Subject").
|
||||||
|
|
||||||
|
Das Steuerjournal (Programm "Beherbergungssteuer") liest sie von dort aus,
|
||||||
|
statt Nachname und Betraege aus dem Fliesstext zu raten. Fuer den Ausdruck
|
||||||
|
aendert sich nichts - Metadaten stehen nicht auf dem Blatt.
|
||||||
|
"""
|
||||||
|
aufschlag = rechnung.aufschlaege[0] if rechnung.aufschlaege else None
|
||||||
|
daten = {
|
||||||
|
"quelle": "rechnungstool",
|
||||||
|
"version": 1,
|
||||||
|
"rechnungsnummer": kopf.get("rechnungsnummer", ""),
|
||||||
|
"datum": kopf.get("datum", ""),
|
||||||
|
"nachname": kopf.get("nachname", ""),
|
||||||
|
"vorname": kopf.get("vorname", ""),
|
||||||
|
"naechte": kopf.get("naechte", ""),
|
||||||
|
"zwischensumme": runde(rechnung.brutto),
|
||||||
|
"steuer_satz": float(aufschlag.satz) if aufschlag else 0.0,
|
||||||
|
"steuer_betrag": runde(aufschlag.betrag) if aufschlag else 0.0,
|
||||||
|
"gesamt": runde(rechnung.gesamt),
|
||||||
|
}
|
||||||
|
return json.dumps(daten, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
def render_rechnung(pfad, cfg, rechnung, kopf):
|
def render_rechnung(pfad, cfg, rechnung, kopf):
|
||||||
"""
|
"""
|
||||||
pfad : Zielpfad der PDF
|
pfad : Zielpfad der PDF
|
||||||
|
|
@ -342,6 +368,7 @@ def render_rechnung(pfad, cfg, rechnung, kopf):
|
||||||
topMargin=MARGIN_TOP, bottomMargin=MARGIN_BOT,
|
topMargin=MARGIN_TOP, bottomMargin=MARGIN_BOT,
|
||||||
title=f"Rechnung {kopf.get('rechnungsnummer','')}",
|
title=f"Rechnung {kopf.get('rechnungsnummer','')}",
|
||||||
author=cfg["firma"].get("name", ""),
|
author=cfg["firma"].get("name", ""),
|
||||||
|
subject=_kenndaten(rechnung, kopf), # maschinenlesbar fuers Steuerjournal
|
||||||
)
|
)
|
||||||
story = []
|
story = []
|
||||||
_seite_inhalt(story, st, cfg, rechnung, kopf, gesamtrechnung_betont=False) # Seite 1: Kunde
|
_seite_inhalt(story, st, cfg, rechnung, kopf, gesamtrechnung_betont=False) # Seite 1: Kunde
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue