Angebotsnummer statt Rechnungsnummer, und Angebote in einen eigenen Unterordner
"und rechnungsnummer ist dann angebotsnummer - dann ist das auch weg": das Feld heisst jetzt Angebotsnummer, und der Hinweis "die Nummer oben ist keine Rechnungsnummer" konnte damit entfallen. Auf dem ganzen Blatt steht das Wort Rechnung nur noch im Pflichthinweis, der gerade sagt, dass es keine ist. Der Pruefstand prueft beides ausdruecklich. "oder in ein extra ordner gepackt werden": die Angebote landen in "Angebote" neben den Rechnungen. Der Rechnungsordner ist die Buchhaltung, dort haben sie nichts zu suchen. Weggeworfen werden duerfen sie trotzdem nicht - ein abgesandtes Angebot ist ein Handelsbrief (§ 257 HGB) - deshalb ein Unterordner und kein anderer Ort. Die Nummernsuche schaut jetzt dort nach, und das Steuerjournal ueberspringt sie ohnehin ueber art="angebot". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
This commit is contained in:
parent
82d84f7aea
commit
ad1ac9af6f
3 changed files with 35 additions and 13 deletions
22
app.py
22
app.py
|
|
@ -899,6 +899,22 @@ class RechnungsApp(ThemeMixin, KorrekturMixin, EinstellungenMixin, tk.Tk):
|
|||
self.wait_window(d)
|
||||
return wahl["art"]
|
||||
|
||||
def _angebot_ordner(self):
|
||||
"""Unterordner "Angebote" neben den Rechnungen.
|
||||
|
||||
Angebote sind keine Buchhaltung - im Rechnungsordner haetten sie nur
|
||||
zwischen den Belegen gelegen. Aufzubewahren sind sie trotzdem: ein
|
||||
abgesandtes Angebot ist ein Handelsbrief (§ 257 HGB). Das Steuerjournal
|
||||
liest den Ordner mit, ueberspringt sie aber (art="angebot").
|
||||
"""
|
||||
ordner = os.path.join(config.ensure_output_dir(self.cfg), "Angebote")
|
||||
try:
|
||||
os.makedirs(ordner, exist_ok=True)
|
||||
except OSError as e: # noqa: BLE001 - dann eben neben die Rechnungen
|
||||
print("[angebot] Unterordner nicht anlegbar:", e)
|
||||
return config.ensure_output_dir(self.cfg)
|
||||
return ordner
|
||||
|
||||
def _naechstes_angebot(self):
|
||||
"""JJJJ-Annn aus der EIGENEN Reihe. Der Jahreswechsel faengt bei A001 an.
|
||||
|
||||
|
|
@ -910,9 +926,9 @@ class RechnungsApp(ThemeMixin, KorrekturMixin, EinstellungenMixin, tk.Tk):
|
|||
zaehler = int(self.cfg.get("angebot_zaehler", 0) or 0)
|
||||
if int(self.cfg.get("angebot_jahr", 0) or 0) != jahr:
|
||||
zaehler = 0
|
||||
out_dir = config.ensure_output_dir(self.cfg)
|
||||
ordner = self._angebot_ordner()
|
||||
try:
|
||||
vorhanden = os.listdir(out_dir)
|
||||
vorhanden = os.listdir(ordner)
|
||||
except OSError:
|
||||
vorhanden = []
|
||||
for _ in range(1000):
|
||||
|
|
@ -1144,7 +1160,7 @@ class RechnungsApp(ThemeMixin, KorrekturMixin, EinstellungenMixin, tk.Tk):
|
|||
name = f"Angebot_{safe_filename(nummer)}"
|
||||
if self.k_name.get().strip():
|
||||
name += "_" + safe_filename(self.k_name.get().strip())
|
||||
pfad = os.path.join(out_dir, name + ".pdf")
|
||||
pfad = os.path.join(self._angebot_ordner(), name + ".pdf")
|
||||
try:
|
||||
pdf_renderer.render_rechnung(pfad, self.cfg, r, kopf)
|
||||
except Exception as e: # noqa: BLE001 - dem Nutzer den Fehler zeigen
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ def _seite_inhalt(story, st, cfg, rechnung, kopf, gesamtrechnung_betont):
|
|||
angebot = art == "angebot"
|
||||
info_rows = [
|
||||
("Stornonummer:" if art == "storno" else
|
||||
"Angebot-Nr.:" if angebot else "Rechnungsnummer:",
|
||||
"Angebotsnummer:" if angebot else "Rechnungsnummer:",
|
||||
kopf.get("rechnungsnummer", "")),
|
||||
# Auf dem Angebot faellt das Wort "Rechnung" ueberall weg: es soll gar
|
||||
# nicht erst der Eindruck entstehen, der Gast haette schon eine.
|
||||
|
|
@ -373,8 +373,8 @@ def _seite_inhalt(story, st, cfg, rechnung, kopf, gesamtrechnung_betont):
|
|||
story.append(Paragraph(
|
||||
"<b>Dies ist ein unverbindliches Angebot</b> und <b>keine Rechnung im "
|
||||
"Sinne des § 14 UStG</b>: es berechtigt nicht zum Vorsteuerabzug und ist "
|
||||
"nicht zu bezahlen. Die Nummer oben ist <b>keine Rechnungsnummer</b>. "
|
||||
"Alle Beträge in Euro inkl. gesetzlicher Umsatzsteuer; ausgewiesen wird "
|
||||
"nicht zu bezahlen. Alle Beträge in Euro inkl. gesetzlicher "
|
||||
"Umsatzsteuer; ausgewiesen wird "
|
||||
"sie erst in der Rechnung nach dem Aufenthalt.", st["dank"]))
|
||||
story.append(Spacer(1, 3 * mm))
|
||||
|
||||
|
|
|
|||
|
|
@ -150,8 +150,12 @@ pruefe(not os.listdir(ordner), f"Abbrechen schreibt nichts ({os.listdir(ordner)}
|
|||
# ---- 3. Angebot waehlen --------------------------------------------------
|
||||
klicke_im_popup("Angebot")
|
||||
f.pdf_erstellen()
|
||||
dateien = sorted(os.listdir(ordner))
|
||||
pruefe(dateien == ["Angebot_2026-A001_Vorab.pdf"], f"das Angebot liegt da ({dateien})")
|
||||
pruefe(sorted(os.listdir(ordner)) == ["Angebote"],
|
||||
f"im Rechnungsordner liegt nur der Unterordner ({sorted(os.listdir(ordner))})")
|
||||
angebote = os.path.join(ordner, "Angebote")
|
||||
dateien = sorted(os.listdir(angebote))
|
||||
pruefe(dateien == ["Angebot_2026-A001_Vorab.pdf"],
|
||||
f"das Angebot liegt im Unterordner Angebote ({dateien})")
|
||||
|
||||
# ---- 4. DIE Hauptsache: die Rechnungsnummer ist unberuehrt --------------
|
||||
pruefe(f.r_nummer.get() == nummer_vorher,
|
||||
|
|
@ -164,7 +168,7 @@ pruefe(f.cfg.get("angebot_zaehler") == 1,
|
|||
# ---- 5. Was auf dem Blatt steht -----------------------------------------
|
||||
from pypdf import PdfReader # noqa: E402
|
||||
|
||||
pfad = os.path.join(ordner, "Angebot_2026-A001_Vorab.pdf")
|
||||
pfad = os.path.join(angebote, "Angebot_2026-A001_Vorab.pdf")
|
||||
seiten = PdfReader(pfad).pages
|
||||
pruefe(len(seiten) == 1, f"eine Seite - kein Blatt fuers Amt ({len(seiten)})")
|
||||
text = (seiten[0].extract_text() or "").replace("\n", " ")
|
||||
|
|
@ -173,7 +177,9 @@ pruefe("Rechnung" not in text.split("Unverbindliches Angebot")[0],
|
|||
"und das Wort Rechnung steht nicht in der Ueberschrift")
|
||||
pruefe("keine Rechnung im Sinne des § 14 UStG" in text,
|
||||
"mit dem Satz, dass es keine Rechnung nach § 14 UStG ist")
|
||||
pruefe("keine Rechnungsnummer" in text, "und dass die Nummer keine Rechnungsnummer ist")
|
||||
pruefe("Angebotsnummer" in text, "die Nummer heisst Angebotsnummer")
|
||||
pruefe("Rechnungsnummer" not in text,
|
||||
"das Wort Rechnungsnummer kommt gar nicht mehr vor")
|
||||
pruefe("2026-A001" in text and "2026-001" not in text,
|
||||
"nur die Angebots-Nummer steht drauf, keine Rechnungsnummer")
|
||||
pruefe("Mehrwertsteuer" not in text and "Nettobetrag" not in text,
|
||||
|
|
@ -195,7 +201,7 @@ antworten["Storno"] = True
|
|||
klicke_im_popup("Rechnung 2026-001 erstellen")
|
||||
f.pdf_erstellen()
|
||||
pruefe(os.path.exists(os.path.join(ordner, "Rechnung_2026-001_Vorab.pdf")),
|
||||
f"die Rechnung 2026-001 ist geschrieben ({sorted(os.listdir(ordner))})")
|
||||
f"die Rechnung liegt bei den Rechnungen ({sorted(os.listdir(ordner))})")
|
||||
pruefe(f.cfg.get("rechnung_zaehler") == 1,
|
||||
f"jetzt erst laeuft der Rechnungszaehler weiter ({f.cfg.get('rechnung_zaehler')})")
|
||||
|
||||
|
|
@ -204,8 +210,8 @@ f.reset_formular()
|
|||
kunde("Bernd", "Zweitvorab")
|
||||
klicke_im_popup("Angebot")
|
||||
f.pdf_erstellen()
|
||||
pruefe(os.path.exists(os.path.join(ordner, "Angebot_2026-A002_Zweitvorab.pdf")),
|
||||
f"das zweite Angebot heisst A002 ({sorted(os.listdir(ordner))})")
|
||||
pruefe(os.path.exists(os.path.join(angebote, "Angebot_2026-A002_Zweitvorab.pdf")),
|
||||
f"das zweite Angebot heisst A002 ({sorted(os.listdir(angebote))})")
|
||||
f.destroy()
|
||||
|
||||
# ---- 8. Das Steuerjournal bucht das Angebot NICHT ---------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue