rechnungstool/pruef_nummern.py
TheMockTv 3ea31b3421 Die Kette steht auf dem Storno-Blatt - kein gemerkter Zustand noetig
Statt einer Zustandsmaschine ("offener Storno" ueber den Neustart retten) traegt
das Storno jetzt einfach beide Nummern:

    Storno zu Rechnung:  2026-002
    Neue Rechnung:       2026-004

und im Text "2026-002 -> 2026-003 -> 2026-004". Damit ist die Kette aus dem
Beleg allein lesbar. Wird das Programm zwischendurch geschlossen, sagt der
Storno, unter welcher Nummer die berichtigte Rechnung gehoert; der Dialog
nennt sie ebenfalls, statt nur "bereits storniert" zu melden.

naechste_freie_nummer_nach() bestimmt die Folgenummer, damit sie nicht von der
Reihenfolge abhaengt, in der der Zaehler mitzieht.

Ausserdem: die Pruefstaende raeumen ihren Wegwerf-Ordner wieder weg, wenn sie
gruen sind. Ein Testlauf hatte 398 Ordner im Temp-Verzeichnis hinterlassen.
Bei Fehlern bleibt der Ordner stehen, damit man hineinsehen kann.

Weitere Funde des Code-Agenten behoben:
- "Kopie von Rechnung_...pdf" und klein geschriebene Dateinamen zaehlen jetzt
  bei der Nummernvergabe mit (vorher galt die Nummer als frei).
- Strg+P feuerte auch aus einem offenen Dialog heraus (bind_all -> bind).

167 Pruefungen gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvGkdNW1vKdnMPAM9Bp3X
2026-09-02 20:42:31 +02:00

72 lines
3.2 KiB
Python

# -*- coding: utf-8 -*-
"""Pruefstand: welche Nummern gelten als vergeben, welche als frei?
Kein Rateraum: legt echte Dateien in einem Wegwerf-Ordner an und fragt
bestand.py direkt. Geprueft wird beides - vorhandene_rechnungen() und
naechste_freie_nummer(), zusammen sind sie die Nummernvergabe.
"""
import os
import sys
import tempfile
sys.path.insert(0, r"C:\claude\rechnungstool")
from bestand import naechste_freie_nummer, vorhandene_rechnungen # noqa: E402
ordner = tempfile.mkdtemp(prefix="rechnungspruef_")
dateien = [
"Rechnung_2026-013_Meier.pdf", # dieselbe Nummer, Kunde Meier
"Rechnung_2026-0135_Schmidt.pdf", # laengere Nummer - darf NICHT treffen
"Rechnung_2026-777_Gross.PDF", # Endung GROSS geschrieben - zaehlt trotzdem
"Rechnung_2026-013_Meier.txt", # richtiger Name, aber kein PDF
"Rechnung_2026-050_Alt.pdf", # und drei Windows-Kopien davon:
"Rechnung_2026-050_Alt (1).pdf",
"Rechnung_2026-050_Alt - Kopie.pdf",
"Rechnung_2026-050 (2).pdf",
"Kopie von Rechnung_2026-050_Alt.pdf", # aeltere Windows-Fassung
"rechnung_2026-050_klein.pdf", # von Hand klein geschrieben
"Rechnung_2026-0501_Neu.pdf", # laengere Nummer - darf NICHT mitzaehlen
"Rechnung_2026-014_Meier.pdf", # andere Nummer
"Rechnung_2026-020.pdf", # ohne Kundenname
"Storno_2026-021_Meier.pdf", # Storno verbraucht die Nummer auch
"Notiz_2026-013.txt", # kein PDF
]
for d in dateien:
with open(os.path.join(ordner, d), "w") as f:
f.write("x")
faelle = [
("2026-013", ["Rechnung_2026-013_Meier.pdf"], "Nummer vergeben, anderer Kundenname"),
("2026-0135", ["Rechnung_2026-0135_Schmidt.pdf"], "laengere Nummer trifft nur sich selbst"),
("2026-777", ["Rechnung_2026-777_Gross.PDF"], "Endung GROSS geschrieben wird gefunden"),
("2026-020", ["Rechnung_2026-020.pdf"], "ohne Kundenname im Dateinamen"),
("2026-021", ["Storno_2026-021_Meier.pdf"], "Nummer ist von einem Storno belegt"),
("2026-050", ["Kopie von Rechnung_2026-050_Alt.pdf", "Rechnung_2026-050 (2).pdf",
"Rechnung_2026-050_Alt (1).pdf", "Rechnung_2026-050_Alt - Kopie.pdf",
"Rechnung_2026-050_Alt.pdf", "rechnung_2026-050_klein.pdf"],
"alle Windows-Kopien und Kleinschreibung zaehlen mit"),
("2026-0501", ["Rechnung_2026-0501_Neu.pdf"], "laengere Nummer bleibt getrennt"),
("2026-099", [], "freie Nummer"),
("2026-01", [], "Teilnummer darf nicht auf 2026-013 anspringen"),
]
fehler = 0
for nummer, erwartet, was in faelle:
ist = [os.path.basename(p) for p in vorhandene_rechnungen(ordner, nummer)]
ok = ist == erwartet
fehler += 0 if ok else 1
print((" OK " if ok else "FEHLER") + f" | {nummer} -> {ist} ({was})")
# leerer / nicht vorhandener Ordner darf nicht knallen
if vorhandene_rechnungen(os.path.join(ordner, "gibtsnicht"), "2026-013") != []:
print("FEHLER | fehlender Ordner")
fehler += 1
else:
print(" OK | fehlender Ordner gibt leere Liste")
# Wegwerf-Ordner nur bei Fehlern behalten
if not fehler:
import shutil as _sh
_sh.rmtree(ordner, ignore_errors=True)
print("---")
print("alles gruen" if fehler == 0 else f"{fehler} Fehler")
sys.exit(1 if fehler else 0)