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
105 lines
4.3 KiB
Python
105 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Zeigt, was die Stornos in einem Journal bewirken. NUR LESEN.
|
|
|
|
python zeig_stornos.py [Pfad zur journal.sqlite3]
|
|
|
|
Ohne Pfad nimmt es den Datenordner, den sich das Programm gemerkt hat.
|
|
|
|
Es wird ausschliesslich gelesen - keine Buchung angelegt, geaendert oder
|
|
geloescht, kein Scan des Rechnungsordners. Man kann es also bedenkenlos auf
|
|
das echte Journal loslassen.
|
|
|
|
Ausgegeben wird je Monat:
|
|
ALT = wie frueher gerechnet wurde (Rechnung + und Storno - stehen beide
|
|
in der Summe und heben sich gegenseitig auf)
|
|
JETZT = Storno und die von ihm aufgehobene Rechnung zaehlen gar nicht mit
|
|
(Berichtigung im Monat der Rechnung)
|
|
|
|
Der Unterschied wird nur dort sichtbar, wo Rechnung und Storno in
|
|
VERSCHIEDENEN Monaten liegen - genau der Fall, um den es geht.
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
HIER = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HIER)
|
|
|
|
from modell import MONATE, aufgehobene, eur, summiere # noqa: E402
|
|
|
|
|
|
def journal_pfad(argv):
|
|
if len(argv) > 1:
|
|
return argv[1]
|
|
merker = os.path.join(os.environ.get("LOCALAPPDATA", ""),
|
|
"Beherbergungssteuer", "datenordner.txt")
|
|
if os.path.exists(merker):
|
|
ordner = open(merker, encoding="utf-8").read().strip()
|
|
if ordner:
|
|
return os.path.join(ordner, "journal.sqlite3")
|
|
return os.path.join(HIER, "journal.sqlite3")
|
|
|
|
|
|
def main():
|
|
pfad = journal_pfad(sys.argv)
|
|
if not os.path.exists(pfad):
|
|
print(f"Kein Journal unter {pfad}")
|
|
print("Pfad angeben: python zeig_stornos.py <...\\journal.sqlite3>")
|
|
return 2
|
|
print(f"Journal: {pfad} (wird nur gelesen)\n")
|
|
|
|
from db import Journal
|
|
j = Journal(pfad)
|
|
try:
|
|
for jahr in sorted(j.jahre() or []):
|
|
alle = j.buchungen(jahr=jahr)
|
|
weg = aufgehobene(alle)
|
|
stornos = [b for b in alle if b.storno_zu]
|
|
print(f"=== {jahr} === {len(alle)} Buchungen, "
|
|
f"{len(stornos)} Storno-Beleg(e), "
|
|
f"{len(weg)} aufgehobene Rechnung(en)")
|
|
|
|
print(f"{'Monat':12s} {'ALT (verrechnet)':>18s} {'JETZT':>14s} "
|
|
f"{'Unterschied':>14s} Naechte alt/jetzt")
|
|
for m in range(1, 13):
|
|
des_monats = [b for b in alle if b.monat == m]
|
|
if not des_monats:
|
|
continue
|
|
alt_g = round(sum(float(b.gezahlt or 0) for b in des_monats), 2)
|
|
alt_n = sum(int(b.naechte or 0) for b in des_monats)
|
|
s = summiere(des_monats, weg)
|
|
marke = " <<<" if abs(alt_g - s.gezahlt) > 0.004 else ""
|
|
print(f"{MONATE[m-1]:12s} {eur(alt_g):>18s} {eur(s.gezahlt):>14s} "
|
|
f"{eur(s.gezahlt - alt_g):>14s} {alt_n}/{s.naechte}{marke}")
|
|
|
|
jahr_alt = round(sum(float(b.gezahlt or 0) for b in alle), 2)
|
|
jahr_neu = summiere(alle, weg)
|
|
print(f"{'JAHR':12s} {eur(jahr_alt):>18s} {eur(jahr_neu.gezahlt):>14s} "
|
|
f"{eur(jahr_neu.gezahlt - jahr_alt):>14s} "
|
|
f"{sum(int(b.naechte or 0) for b in alle)}/{jahr_neu.naechte}")
|
|
|
|
if not stornos:
|
|
print("\n(keine Stornos in diesem Jahr)\n")
|
|
continue
|
|
|
|
print("\nDie Storno-Paare im Einzelnen:")
|
|
for s_ in sorted(stornos, key=lambda b: (b.datum, b.rechnungsnummer)):
|
|
ziel = [b for b in alle if b.id in weg and b.voll_nummer == s_.storno_zu]
|
|
z = ziel[0] if ziel else None
|
|
print(f" Storno {s_.voll_nummer} vom {s_.datum:%d.%m.%Y} "
|
|
f"({MONATE[s_.monat-1]}) {eur(s_.gezahlt)}, {s_.naechte} Naechte")
|
|
if z:
|
|
gleich = "gleicher Monat" if z.monat == s_.monat else \
|
|
f"ANDERER Monat: Rechnung in {MONATE[z.monat-1]}"
|
|
print(f" hebt auf: {z.voll_nummer} vom {z.datum:%d.%m.%Y}, "
|
|
f"{z.nachname}, {eur(z.gezahlt)}, {z.naechte} Naechte [{gleich}]")
|
|
else:
|
|
print(f" ACHTUNG: zu {s_.storno_zu} liegt KEINE Rechnung im Journal - "
|
|
f"der Storno zieht also einfach ab, ohne dass etwas aufgehoben wird")
|
|
print()
|
|
finally:
|
|
j.schliessen()
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|