Storno: das Journal zaehlte die Uebernachtungen der aufgehobenen Rechnung weiter mit (4 - 0 + 3 = 7 statt 3 gemeldeter Naechte). Die Betraege kuerzten sich, die Naechte nicht. Der Storno traegt jetzt die negative Zahl, und das Journal kennt Art, Bezug und Datum des Belegs (vier neue Spalten, alte Journale bauen sich beim Oeffnen um). Berichtigung: das Blatt wurde nur uebersprungen. Der berichtigte NAME kommt jetzt in der Buchung an - im Amtsbericht stand sonst weiter der falsche. Angewandt wird erst am Ende des Scans, das Blatt kann vor seiner Rechnung im Ordner liegen. Doppelte Nummern: eine stornierte Rechnung ist keine offene mehr und faellt aus der Meldung. Zugeordnet wird ueber Nummer + Datum + Empfaenger, nicht ueber die Nummer allein - bei einer doppelt vergebenen Nummer waere die kein eindeutiger Bezug, und genau den verlangt § 31 Abs. 5 UStDV. Die Texte nennen jetzt den Weg: eine der beiden im Rechnungstool stornieren und mit freier Nummer neu ausstellen (§ 14 Abs. 4 Nr. 4 UStG - jede Nummer nur einmal). Neue Spalte "Art": Storno zu ..., storniert, Neuausstellung. Aufgehobene Zeilen stehen grau - geloescht wird nichts. Gemeinsames Nummernbuch (gemeinsam.py, ordnerwahl.py - in beiden Programmen dieselbe Datei): eine SQLite in einem Ordner, den beide kennen. Das Journal traegt seine Nummern ein, auch die aus der Excel-Mappe ohne PDF - genau die kannte das Rechnungstool nicht und vergab sie ein zweites Mal. Beim ersten Start wird nach dem Ordner gefragt (auswaehlen, OK, Sicherheitsfrage, bei Nein zurueck ins Feld); wer ihn nicht hat, kommt mit "Spaeter einrichten" weiter. Kein Doppelklick zum Bearbeiten mehr (gui_dialoge.py geloescht): wer hier Betrag oder Nummer verstellt, meldet dem Amt etwas anderes, als auf dem Beleg steht. Loeschen bleibt. --test / CAMPINGHOF_TEST=1 unterdrueckt den Erststart-Dialog (Pruefstaende). Pruefstaende: pruef_storno_journal.py (neu, ueber BEIDE Programme: Storno, Berichtigung, doppelte Nummer aufloesen), pruef_doppelte, pruef_berichtigung, pruef_einzelinstanz - alle gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GYeAfLtccFrbU3MTj1MMTx
116 lines
5.7 KiB
Markdown
116 lines
5.7 KiB
Markdown
# Beherbergungssteuer – Campinghof Bartl
|
||
|
||
Ersetzt die Excel-Mappe `Beherbergungsteuer.xlsx`.
|
||
|
||
**Quelle der Wahrheit sind die Rechnungs-PDFs** aus dem Rechnungstool. Das Programm
|
||
liest den Rechnungs-Ordner ein, führt daraus das Steuerjournal und schreibt auf
|
||
Knopfdruck die Excel-Mappe fürs Amt.
|
||
|
||
## Starten
|
||
|
||
- **Doppelklick** auf `Beherbergungssteuer starten.bat`
|
||
- oder im Terminal: `python app.py`
|
||
|
||
## Bedienung
|
||
|
||
1. **Rechnungs-Ordner…** → den Ordner wählen, in dem das Rechnungstool die PDFs ablegt
|
||
(Standard: `Dokumente\Campinghof Rechnungen`). Danach wird sofort eingelesen; bei
|
||
jedem Start passiert das automatisch.
|
||
2. **Rechnungen einlesen** (oder F5) holt neue Rechnungen nach. Bereits gelesene PDFs
|
||
werden übersprungen (Vergleich über Pfad, Änderungszeit und Größe) – das geht auch
|
||
bei tausend Rechnungen schnell.
|
||
3. **Monats-Reiter** zeigen die Buchungen mit Summenzeile, unten rechts steht die
|
||
Jahressumme.
|
||
4. **PDF fürs Amt** schreibt den Monatsbericht des offenen Reiters als PDF im
|
||
Campinghof-Layout (gleicher Briefkopf wie die Rechnungen) nach `berichte/`:
|
||
Tabelle aller Rechnungen, Summenblock mit der Steuer, Unterschriftszeile.
|
||
Über das Menü gibt es zusätzlich den **Jahresbericht**. Gedruckt wird aus dem
|
||
PDF-Programm heraus.
|
||
|
||
**Im Journal wird nichts von Hand geändert** (seit v1.4): weder anlegen noch
|
||
bearbeiten. Jede Zeile gehört zu einer Rechnung aus dem Rechnungstool – auch die
|
||
Barzahlung. Wer hier Betrag oder Nummer verstellte, meldete dem Amt etwas anderes,
|
||
als auf dem Beleg steht; beim nächsten Einlesen käme die Änderung ohnehin zurück.
|
||
Stimmt eine Rechnung nicht, wird sie **im Rechnungstool** storniert oder berichtigt.
|
||
|
||
Löschen bleibt: **Entf** oder die Haken-Spalte mit dem Papierkorb. Das entfernt nur
|
||
die Zeile aus dem Zwischenspeicher – die PDF bleibt liegen und wird beim nächsten
|
||
Einlesen wieder gefunden.
|
||
|
||
Der Briefkopf des Berichts (Firma, Logo, Bankzeile) wird aus der `config.json` des
|
||
Rechnungstools gelesen – also nur an einer Stelle gepflegt.
|
||
|
||
## Was aus der PDF gelesen wird
|
||
|
||
| Spalte | Herkunft in der Rechnung |
|
||
|--------|--------------------------|
|
||
| Datum | `Rechnungsdatum:` |
|
||
| Rechnung | `Rechnungsnummer:` (z.B. 2026-238) |
|
||
| Nachname | erste Zeile unter `Rechnung an:` |
|
||
| Übernachtungen | `Zeitraum: 3 Nächte` (ersatzweise An-/Abreise) |
|
||
| Gezahlt | `Zwischensumme:` – das ist die Basis der Steuer |
|
||
| Steuer | `zzgl. Beherbergungssteuer (5 %):` |
|
||
|
||
Weicht der in der PDF ausgewiesene Steuerbetrag von der eigenen Rechnung ab,
|
||
steht das als Warnung in `beherbergungssteuer.log`.
|
||
|
||
## Doppelt vergebene Rechnungsnummern
|
||
|
||
Jede Rechnungsnummer darf es nur einmal geben (§ 14 Abs. 4 Nr. 4 UStG). Kommt eine
|
||
Nummer trotzdem zweimal vor, **zeigt das Journal sie an, statt eine der beiden
|
||
verschwinden zu lassen**:
|
||
|
||
- die betroffenen Zeilen stehen **rot** und tragen ein ⚠ vor der Nummer,
|
||
- der **Monatsreiter** bekommt ebenfalls ein ⚠ – auch dann, wenn die zweite Rechnung
|
||
in einem anderen Monat liegt (gerechnet wird über das ganze Jahr),
|
||
- unter der Jahressumme steht eine rote Zeile mit dem Knopf **„Doppelte Rechnungen
|
||
anzeigen…"**: dort stehen alle Belege mit Datum, Gast, Betrag und **Dateiname**.
|
||
|
||
Die Beträge bleiben in allen Summen und im Bericht fürs Amt – es wird nichts
|
||
stillschweigend weggerechnet. Zwei Zeilen zur *selben* Rechnung (z. B. einmal aus dem
|
||
Excel-Altbestand und einmal aus der PDF) melden die Übernachtung doppelt ans Amt; zwei
|
||
verschiedene Gäste unter einer Nummer sind ein Fehler im Rechnungstool. Was zu tun ist,
|
||
entscheidet der Wirt – das Programm ändert von allein nichts.
|
||
|
||
> Bis Version 1.2 war die Rechnungsnummer der Schlüssel der Datenbank: die zweite
|
||
> Rechnung hat die erste **still überschrieben** und fehlte danach in der Meldung ans
|
||
> Amt. Seit v1.3 ist der Schlüssel die PDF-Datei, seit v1.4 sieht man den Fall auch.
|
||
|
||
## Nur ein Fenster
|
||
|
||
Das Programm lässt sich **nicht zweimal öffnen**. Ein zweiter Doppelklick holt das
|
||
offene Fenster nach vorn. Grund: beide Fenster würden denselben Rechnungsordner in
|
||
dieselbe `journal.sqlite3` einlesen und danach verschiedene Stände zeigen – wer im
|
||
älteren Fenster auf „PDF fürs Amt" drückt, meldet einen Stand, den es nicht mehr gibt.
|
||
|
||
## Excel einlesen
|
||
|
||
`Datei → Excel-Tabelle einlesen…` zieht die bisherige `Beherbergungsteuer.xlsx` ins
|
||
Journal – sowohl den Altbestand aus der Zeit vor dem Rechnungstool als auch jede
|
||
spätere Fassung, die noch in Excel gepflegt wurde. Zeilen ohne PDF sind in der
|
||
Tabelle grau dargestellt. Rechnungsnummern werden dabei vereinheitlicht
|
||
(`001`, `13`, `2026-17` → `2026-013`), sonst entstünden doppelte Buchungen.
|
||
|
||
## Dateien
|
||
|
||
| Datei | Zweck |
|
||
|-------|-------|
|
||
| `app.py` | Fenster, Menü, Aktionen |
|
||
| `gui_monat.py` | ein Monatsblatt (Tabelle + Summenzeile) |
|
||
| `pdf_parser.py` | Rechnungs-PDF → Buchung |
|
||
| `bericht_pdf.py` | Monats-/Jahresbericht fürs Amt (reportlab) |
|
||
| `firma.py` | Briefkopf aus der `config.json` des Rechnungstools |
|
||
| `db.py` | Journal (SQLite) + PDF-Scan mit Cache |
|
||
| `xlsx_io.py` | Excel-Import |
|
||
| `modell.py` | Datenmodell + Steuerrechnung + doppelte Nummern (die einzige Rechenstelle) |
|
||
| `ablage.py` | wo der Datenordner liegt (neben der EXE oder in LOCALAPPDATA) |
|
||
| `einzelinstanz.py` | Sperre gegen ein zweites Fenster |
|
||
| `pruef_doppelte.py` | Prüfstand: werden doppelte Nummern angezeigt? |
|
||
| `pruef_einzelinstanz.py` | Prüfstand: geht das Programm wirklich nur einmal auf? |
|
||
| `pruef_berichtigung.py` | Prüfstand: Storno/Berichtigung überschreiben nichts |
|
||
| `journal.sqlite3` | die Daten (wird beim 1. Start angelegt) |
|
||
| `berichte/` | die erzeugten Amts-PDFs |
|
||
|
||
## Voraussetzungen
|
||
|
||
Python 3.10+, `pypdf`, `openpyxl` und `reportlab` (`pip install pypdf openpyxl reportlab`).
|