diff --git a/Beherbergungssteuer.exe b/Beherbergungssteuer.exe
index 5ddd36a..3bc47cd 100644
Binary files a/Beherbergungssteuer.exe and b/Beherbergungssteuer.exe differ
diff --git a/bericht_pdf.py b/bericht_pdf.py
index 23fe6aa..0cca167 100644
--- a/bericht_pdf.py
+++ b/bericht_pdf.py
@@ -198,6 +198,23 @@ def _ort(firma):
# ------------------------------------------------------------- Monat --------
+def _art_kuerzel(b) -> str:
+ """Ein Buchstabe je Beleg - seine Ansage vom 04.09.2026: *"du musst die
+ markieren als rechnung und storno oder berichtigung, und das kannst einfach
+ mit buchstaben machen"*. Ohne die Marke muss man aus der Begruendung raten,
+ was fuer ein Beleg die Zeile ueberhaupt ist.
+
+ R = Rechnung
+ S = Stornorechnung
+ B = berichtigte Rechnung (die Neuausstellung nach einem Storno)
+ """
+ if b.storno_zu or b.art == "storno":
+ return "S"
+ if b.art == "korrektur":
+ return "B"
+ return "R"
+
+
def _art_text(b, weg) -> str:
"""Was in der Rechnungsspalte unter der Nummer steht.
@@ -211,7 +228,7 @@ def _art_text(b, weg) -> str:
# Ein Storno, der nur zurueckzeigt, laesst den Leser stehen ("wer soll
# denn sonst wissen, wo er suchen muss" - 04.09.2026).
if b.folge_nummer and b.folge_art == "vorhanden":
- return f"neu abgerechnet mit {b.folge_nummer}"
+ return f"abgerechnet mit {b.folge_nummer}"
if b.folge_nummer:
return f"neue Rechnung {b.folge_nummer}"
if b.folge_art == "" and b.art == "storno" and not b.folge_nummer:
@@ -250,13 +267,15 @@ def render_monat(pfad, firma, jahr: int, monat: int, buchungen):
# Eigene Spalte "Grund" statt einer zweiten Zeile unter der Nummer - seine
# Ansage vom 04.09.2026: "mach eine neue spalte mit grund oder so was".
- kopf = ["Datum", "Rechnung", "Begründung", "Name", "Nächte", "Entgelt", "Satz", "Steuer"]
- stile = ["th", "th", "th_l", "th_l", "th", "th", "th", "th"]
+ kopf = ["Datum", "Rechnung", "Art", "Begründung", "Name",
+ "Nächte", "Entgelt", "Satz", "Steuer"]
+ stile = ["th", "th", "th", "th_l", "th_l", "th", "th", "th", "th"]
daten = [[Paragraph(k, st[s_]) for k, s_ in zip(kopf, stile)]]
for b in liste:
daten.append([
Paragraph(b.datum.strftime("%d.%m.%Y"), st["zelle_c"]),
Paragraph(b.voll_nummer, st["zelle_c"]),
+ Paragraph(f'{_art_kuerzel(b)}', st["zelle_c"]),
Paragraph(_art_text(b, weg), st["zelle"]),
Paragraph(b.nachname, st["zelle"]),
Paragraph(str(b.naechte), st["zelle_c"]),
@@ -267,7 +286,7 @@ def render_monat(pfad, firma, jahr: int, monat: int, buchungen):
if len(daten) == 1:
daten.append([Paragraph("", st["zelle_c"]),
Paragraph("(keine Buchungen in diesem Monat)", st["zelle"]),
- "", "", "", "", "", ""])
+ "", "", "", "", "", "", ""])
# Namensspalte nur so breit wie der breiteste Name (Rest der Tabelle ist fest)
breiteste = max([stringWidth(b.nachname, "Helvetica", 8.5) for b in liste]
@@ -278,11 +297,11 @@ def render_monat(pfad, firma, jahr: int, monat: int, buchungen):
# raum ein, da kannst locker zeile begruendung setzen"*. Also enger gestellt
# und der Begruendung so viel gegeben, dass "storniert mit 2026-901" in EINE
# Zeile passt - in normaler Schriftgroesse, nicht kleingedruckt.
- name_w = min(max(breiteste + 6 * mm, 22 * mm), CONTENT_W - 142 * mm)
+ name_w = min(max(breiteste + 6 * mm, 22 * mm), CONTENT_W - 144 * mm)
tabelle = Table(daten, repeatRows=1, hAlign="LEFT",
- colWidths=[19 * mm, 19 * mm, 44 * mm, name_w,
- 12 * mm, 19 * mm, 10 * mm, 19 * mm])
+ colWidths=[18 * mm, 18 * mm, 9 * mm, 42 * mm, name_w,
+ 12 * mm, 18 * mm, 9 * mm, 18 * mm])
tabelle.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), GREY_BG),
("LINEBELOW", (0, 0), (-1, 0), 0.8, ACCENT),
@@ -294,6 +313,14 @@ def render_monat(pfad, firma, jahr: int, monat: int, buchungen):
("RIGHTPADDING", (0, 0), (-1, -1), 3),
]))
story.append(tabelle)
+ # Legende zu den Buchstaben - direkt unter der Tabelle, damit sie beim Lesen
+ # da ist und nicht auf der naechsten Seite. Wer nur eine Zeile prueft, muss
+ # nicht raten, was fuer ein Beleg sie ist.
+ story.append(Spacer(1, 1.5 * mm))
+ story.append(Paragraph(
+ "Art: R = Rechnung · S = Stornorechnung · B = berichtigte Rechnung "
+ "(Neuausstellung nach einem Storno). Die Spalte Begründung nennt den Beleg, "
+ "bei dem es weitergeht.", st["klein"]))
_summenblock(story, st, s, satz_text)
story.append(Spacer(1, 3 * mm))
diff --git a/doku_aenderungen_pdf.py b/doku_aenderungen_pdf.py
index 7bc9ffa..ae3a39a 100644
--- a/doku_aenderungen_pdf.py
+++ b/doku_aenderungen_pdf.py
@@ -207,16 +207,20 @@ def bauen(pfad, cfg):
"Begründung, und zwar als Kette, die vorwärts zeigt – jede Zeile sagt, wo es "
"weitergeht:")
s.append(tabelle([
- ["Zeile im Bericht", "Begründung", "Bedeutung"],
- ["die aufgehobene Rechnung", "storniert mit 2026-901",
+ ["Art", "Zeile im Bericht", "Begründung", "Bedeutung"],
+ ["R", "die aufgehobene Rechnung", "storniert mit 2026-901",
"hier steht, welcher Beleg sie aufhebt"],
- ["die Stornorechnung", "neue Rechnung 2026-902",
+ ["S", "die Stornorechnung", "neue Rechnung 2026-902",
"hier steht, unter welcher Nummer die Leistung jetzt abgerechnet ist"],
- ["die Stornorechnung im Doppelungsfall", "neu abgerechnet mit 2026-343",
+ ["S", "Stornorechnung im Doppelungsfall", "abgerechnet mit 2026-343",
"die Leistung war bereits abgerechnet – das ist die Rechnung, die bleibt"],
- ["die neue Rechnung", "Neuausstellung",
+ ["B", "die berichtigte Rechnung", "Neuausstellung",
"sie ersetzt die aufgehobene"],
- ], st, [45 * mm, 47 * mm, CONTENT_W - 92 * mm]))
+ ], st, [9 * mm, 40 * mm, 40 * mm, CONTENT_W - 89 * mm]))
+ s.append(Spacer(1, 1 * mm))
+ P("Die Spalte Art markiert jeden Beleg mit einem Buchstaben – R Rechnung, "
+ "S Stornorechnung, B berichtigte Rechnung. Die Erklärung dazu steht auf jedem "
+ "Blatt unter der Tabelle.", "klein")
s.append(Spacer(1, 2 * mm))
P("So findet man von jedem Beleg aus den nächsten, auch wenn Rechnung und Storno in "
"verschiedenen Monaten liegen und gar nicht auf demselben Blatt stehen.")
diff --git a/gui_monat.py b/gui_monat.py
index eaefa91..43ecd6d 100644
--- a/gui_monat.py
+++ b/gui_monat.py
@@ -155,7 +155,7 @@ class MonatsTab(ttk.Frame):
if b.storno_zu:
# Kette vorwaerts: Rechnung -> Storno -> die Rechnung, die gilt.
if b.folge_nummer and b.folge_art == "vorhanden":
- art_text = f"neu abgerechnet mit {b.folge_nummer}"
+ art_text = f"abgerechnet mit {b.folge_nummer}"
elif b.folge_nummer:
art_text = f"neue Rechnung {b.folge_nummer}"
else:
diff --git a/pruef_storno_verrechnet.py b/pruef_storno_verrechnet.py
index d131433..394cc40 100644
--- a/pruef_storno_verrechnet.py
+++ b/pruef_storno_verrechnet.py
@@ -157,9 +157,13 @@ pruefe("neue Rechnung 2026-902" in text,
pfad_sep = os.path.join(tmp, "September.pdf")
bericht_pdf.render_monat(pfad_sep, firma_lib.lade(), JAHR, 9, alle)
text_sep = " ".join((PdfReader(pfad_sep).pages[0].extract_text() or "").split())
-pruefe("neu abgerechnet mit 2026-905" in text_sep,
+pruefe("abgerechnet mit 2026-905" in text_sep,
"und beim Doppelungsfall zeigt er auf die Rechnung, die bleibt")
pruefe("-52,00" in text_sep, "der September traegt weiter seinen Minusbetrag")
+# Die Buchstaben-Marke: ohne sie muss man aus der Begruendung raten, was fuer ein
+# Beleg die Zeile ist ("du musst die markieren als rechnung und storno").
+pruefe("R = Rechnung" in text and "S = Stornorechnung" in text,
+ "unter der Tabelle steht die Erklaerung der Buchstaben")
pruefe("Neuausstellung" in text, "die neue Rechnung ist als Neuausstellung beschriftet")
# ---------------------------------------------------------------------------