Stand v0.24.0 (August 2026) · Pro-Addon buchhaltung · App apps/buchhaltung (Tabellen-Prefix bh_) · Konzept: docs/konzept-buchhaltung.md
Doppelte Vereinsbuchhaltung für Laien: KMU-Kontenrahmen, einfache Buchungsmasken, Bank-Abgleich (camt), Belege, Budget und die fertige Jahresrechnung für die GV. Das früher geplante Addon Nr. 22 «Zahlungs-Matching» ist hier als Matching-Center aufgegangen (aus dem Store entfernt).
| Prinzip |
Umsetzung |
| Revisionssicherheit |
Buchungen sind nach dem Buchen UNVERÄNDERLICH; Korrektur nur über Storno-Gegenbuchung (reverses-FK). Buchungsnummern {FY-Label}-{seq:05d} lückenlos pro Geschäftsjahr (select_for_update). |
| Perioden-Sperre |
Jede Buchung liegt in genau einem OFFENEN Geschäftsjahr. Abschluss sperrt und erzeugt automatisch den Vortrag ins Folgejahr; Wiedereröffnen storniert den Vortrag (kein Nummern-Loch), erneuter Abschluss erzeugt ihn frisch. |
| Kontenplan |
Schweizer KMU-Kontenrahmen 1:1 als Seed (kontenrahmen.py, ~68 Konten, Klassen 1–8) + gekennzeichnete Vereins-Unterkonten (3410 Mitgliederbeiträge, 3420 Spenden, 3430 Sponsoring, 3440/4410 Anlässe, 1091 PSP-Verrechnungskonto). Pro Verein kopiert, frei erweiterbar; Systemkonten (1000/1020/1100/2970/3805) geschützt; Konten mit Buchungen nur deaktivierbar. |
| Zwei Dimensionen |
Sachkonto = WAS, Kostenstelle = WOFÜR (optional, eigene Auswertung). |
| CHF-only |
Währungsfeld vorhanden, UI einspurig. |
FiscalYear (inkl. MwSt-Konfig pro Jahr) · LedgerAccount (mit financial_kind ''/bank/cash/psp + IBAN für camt-Zuordnung) · CostCenter · JournalEntry/JournalLine (Soll=Haben vom Service erzwungen) · BusinessEvent (generische Geschäftsvorgangs-Schnittstelle — Andock-Punkt für Ticketing/Shop/Spesen; Idempotenz via Unique source/event/ref) · BankTransaction/BankImportBatch (Dedupe über AcctSvcrRef bzw. Hash) · Budget/BudgetLine · BhSettings (Standardkonten + Spesen-Regeln) · ExpenseRequest/ExpenseItem/PayoutAccount (Spesen, v0.24.0). Belege: M2M bh_entry_document auf Datei-Browser-Assets + AssetUsage (usage_type buchung) → Lösch-Schutz.
- Bankzahlungen NUR über das Matching-Center: camt.053/054 hochladen (Parser namespace-tolerant, Sammelbuchungen pro TxDtls aufgelöst) → exakte QR-Referenz = sicherer Auto-Match mit Bulk-Bestätigung; eindeutiger Betrags-Treffer = Vorschlag; Rest manuell (Rechnung zuweisen oder Konto/Split kontieren). Eine Bestätigung erzeugt ATOMAR: Faktura-Payment (source camt) + Buchung «Bank an Forderungen» + Verknüpfung.
- Manuelle Faktura-Zahlung → Geschäftsvorgang: mit Finanzkonto (Auswahl im Zahlungs-Dialog) oder Profil-Bankkonto automatisch gebucht; Ausbuchungen auf 3805; sonst «Zu kontieren». Nie doppelt, nie verloren.
- Einzeln aktiv = No-Op: Ist die Buchhaltung inaktiv oder das Setup unfertig, tun alle Hooks nichts — Faktura läuft wie bisher.
Soll-Stellung (automatisch): Rechnungsversand bucht «Forderungen (1100) an Ertragskonto» (Auflösung Automation → Profil → Standard), Storno der Rechnung storniert die Buchung. Alle Hooks (apps/buchhaltung/integration.py) sind idempotent und defensiv — Fehler lassen den Vorgang mit Notiz in «Zu kontieren» liegen, brechen Faktura aber NIE ab.
¶ Fehler-Behandlung (v0.23.1/.2 — «Undo-Light»)
Kernidee: die jüngste Buchung eines offenen Jahres darf physisch gelöscht werden — ihre Nummer wird wieder frei, die Lückenlosigkeit bleibt. Kein freies Editieren/Löschen beliebiger Buchungen (bewusster Entscheid).
- ↶ Rückgängig (Journal, nur jüngste Buchung): löscht inkl. konsistenter Rücksetzung (Bank-Transaktion wieder offen, Matching-Zahlung entfernt, Geschäftsvorgang wieder «Zu kontieren», Beleg-Verwendung gelöst).
- Korrigieren: öffnet die vorbefüllte Maske im Korrektur-Modus (Präfix «Korrektur: …», Banner erklärt: es entstehen ZWEI Positionen). Abbrechen ist folgenlos — erst «Storno + Korrektur buchen» führt beides ATOMAR aus (
correct_entry).
- Import rückgängig: Batch samt Transaktionen weg, solange nichts verbucht ist (Dedupe-Schlüssel mit → Re-Import möglich).
- Matching rückgängig: Zahlung weg, Buchung gelöscht (wenn jüngste) sonst storniert, Transaktion wieder offen, Rechnungsstatus neu.
- Perioden-Reset («Zurücksetzen …», nur jüngstes offenes Jahr, Jahr-Label abtippen): alle Buchungen weg, Vorgänge/Bank zurückgesetzt, Matching-Zahlungen in Faktura entfernt. Einziges Jahr → Einrichtung startet neu, Kontenplan bleibt.
- Setup-Assistent: Geschäftsjahr (frei, auch 1.7.–30.6.) → KMU-Seed → Anfangsbestände (Differenz automatisch auf 2970; offene Faktura-Rechnungen als Forderungsbestand übernehmbar).
- Buchen: Laien-Maske «Geld erhalten / ausgegeben / Übertrag» + Expertenmodus (Splits). Beleg-Upload direkt in der Maske (Auto-Ordner «Buchhaltung Belege/») oder nachträglich über 📎 im Journal. Hinweis bei Bank-Konto: Bankzahlungen besser im Matching-Center kontieren (Doppelerfassung).
- Berichte: Bilanz (Vorjahr, Ausgeglichenheits-Check), ER (Vorjahr + Budget), Kontoblatt (Laufsaldo; Kassenbuch = Kontoblatt der Kasse), Kostenstellen, MwSt-Zusammenzug, GV-PDF (WeasyPrint, Unterschriftenblock, «provisorisch» bei offenem Jahr).
- MwSt: Saldosteuersatz-Methode, pro Verein schaltbar; Konfiguration am offenen Jahr, künftige Jahre übernehmen, abgeschlossene sind eingefroren. Steuerbar =
vat_relevant-Ertragskonten (Mitgliederbeiträge/Spenden default ausgenommen).
Was kann es: Mitglieder mit der Rollen-Freigabe portal.spesen reichen im Portal Auslagen ein — Titel, Datum, mehrere Positionen, optional Kilometergeld (km × Ansatz), Quittungsfoto und die IBAN für die Auszahlung (wird für den nächsten Antrag gespeichert). Danach läuft die Freigabe über zwei fest definierte Personen pro Stufe (pflegbar unter Berechtigungen › Freigaben › Spesen oder Buchhaltung › Einstellungen › Spesen — seit v0.26.0 dieselbe Komponente an beiden Orten): Die 1. Freigabe prüft jeden Antrag sachlich — eine der beiden Personen genügt, entschieden wird eingeloggt im Clu-Portal unter «Aufgaben». Optional gibt es eine 2. Freigabestufe ab einer Betragslimite (z.B. Präsidium ab CHF 200; Limite 0 = immer). Erst NACH der finalen Freigabe übernimmt der Kassier: Er kontiert und verbucht im Clu-Core (Tab «Spesen», je Position Aufwandkonto/Kostenstelle, mit Budget-Hinweis) und löst die Auszahlung aus — einzeln, als Sammel-Auszahlung pro Person oder direkt aus dem Matching-Center, wenn die Belastung im Kontoauszug auftaucht. Findet jemand einen Mangel (Beleg fehlt, Total falsch), geht der Antrag «zur Korrektur zurück» an die Person, die ihn im Portal anpasst und erneut einreicht — die Freigabe startet dann von vorn. Benachrichtigungen laufen über «🔔 Meldungen» und per E-Mail; der Antrag zeigt beiden Seiten jederzeit, auf welcher Stufe er liegt.
Die Mail-Kadenz ist bewusst gestuft: Die Aufgabe erscheint sofort bei beiden Personen der Stufe im Portal, die Mail geht aber nur an die primäre Person — die Stellvertretung wird erst nach X Tagen ohne Entscheid nachgemailt (Default 3, einstellbar), und nach der doppelten Frist erinnert das System einmalig beide und meldet den Admins «Antrag hängt» (täglicher Lauf 05:25). So versandet nichts, ohne dass jede Spese zwei Postfächer flutet.
Einrichtungs-Checkliste im Spesen-Tab (v0.25.1): Solange die Freigabe-Personen fehlen oder die Rolle «Spesen einreichen» keiner Rolle zugewiesen ist, zeigt der leere Tab nicht einfach «Keine Spesen», sondern die zwei offenen Schritte mit Direktsprung zu den Einstellungen bzw. zu den Berechtigungen — eine leere Liste wäre sonst nicht von «bereit, aber noch nichts eingereicht» unterscheidbar. Sind beide Punkte erledigt, steht dort «Bereit — Mitglieder mit der Rollen-Freigabe können im Portal einreichen».
Warum so gebaut — und warum nicht anders:
- Kein eigenes Addon (Katalog Nr. 15 entfernt): Spesen ohne Buchhaltung ist kein Produkt — die genehmigte Spese muss verbucht und ausbezahlt werden. Anders als bei Faktura gibt es keine eigenständige Zielgruppe, dafür einen Store-Eintrag und ein zweites Abo weniger. Damit Vereine mit externer Buchhaltung nicht ausgesperrt sind, läuft der Workflow auch ohne abgeschlossene Einrichtung (dann ohne Kontierung/Buchung).
- Feste Personen statt implizitem «wer Admin ist, entscheidet» (v0.25.0): Im ersten Wurf war der Erstgenehmiger jeder Owner/Admin, und der Zweitgenehmiger-Fallback konnte auf den Prüfer selbst zurückfallen — die Betragslimite stellte das Vier-Augen-Prinzip nicht sicher. Jetzt sind die Freigabe-Personen Namen, keine Rollen: Wer freigibt, steht in den Einstellungen, und der Kassier entscheidet gar nicht mehr — er verarbeitet Genehmigtes. Damit ist auch die alte Sonderregel «eigene Spesen des Kassiers eskalieren zwingend» überflüssig: JEDER Antrag wird von anderen geprüft; als Sicherheitsnetz wirft das System bei Selbstfreigabe weiterhin hart.
- Zwei Personen pro Stufe, EINE Unterschrift genügt: Die zweite Person ist Stellvertretung, kein Doppel-Visum — sie deckt Ferien UND den Fall, dass die erste selbst einreicht (dann entscheidet automatisch nur die andere). Ein echtes Doppel-Unterschriften-Modell wäre für Vereinsspesen Überregulierung und würde die 3-Tage-Kadenz sinnlos machen. Stufe 1 und Stufe 2 dürfen sich personell nie überschneiden (beim Speichern hart geprüft) — sonst könnte dieselbe Person beide Stufen desselben Antrags abnicken.
- Freigabe VOR der Kontierung: Die Freigabe-Personen beurteilen die Sache («war die Ausgabe ok, Beleg da?») — dafür braucht niemand Buchhaltungswissen, und das Portal muss keine Konten zeigen. Der Kassier fasst nur noch Genehmigtes an; bei einer Ablehnung wurde nichts umsonst kontiert. Deshalb entfiel auch die Ressort-Freigabe pro Kostenstelle aus v0.24.0: Zum Zeitpunkt der Genehmigung ist die Kostenstelle schlicht noch nicht gesetzt.
- Kein Admin-Fallback: Ohne vollständige Besetzung der 1. Stufe (und der 2., falls aktiviert) ist die Einreichung für ALLE ausgeblendet — Kachel weg, Dashboard-Hinweis «Spesen-Freigabe einrichten». Ein stiller Ersatz («dann entscheiden halt die Admins») wäre genau das Loch, das der Umbau schliesst. Konsequenz: Der Ein-Personen-Verein kann den Prozess nicht nutzen und bucht Auslagen manuell — ehrlich statt scheinsicher.
- Entscheid nur eingeloggt, kein Magic-Link: Bei Finanz-Freigaben wäre eine weitergeleitete Mail sonst eine Freigabe. Der Personen-Picker zeigt darum den Login-Status und verschickt auf Klick die Login-Einladung. (Die Magic-Link-Mechanik bleibt für die Self-Service-Genehmigungen bestehen — dort geht es um die eigenen Daten, nicht ums Vereinsgeld.)
- Änderungen an der Freigabe-Logik sind laut: Wer Personen oder Limite ändert, löst eine Diff-Meldung an alle Betroffenen aus (auch an entfernte) — stilles Auswechseln der Freigabe-Personen vor einer heiklen Freigabe fällt auf. Offene Aufgaben wandern automatisch zur neuen Besetzung; die Limite wirkt nie rückwirkend auf hängige Anträge.
- Zweistufige Buchung statt «erst bei der Auszahlung»: Verbuchen bucht Aufwand an Verbindlichkeiten (2010), die Auszahlung tilgt sie. So zeigt die Bilanz, was der Verein seinen Leuten schuldet — dasselbe Muster wie die Soll-Stellung bei Rechnungen.
- Auszahlung übers Matching-Center: Würde der Kassier überweisen und manuell buchen, käme dieselbe Belastung beim camt-Import ein zweites Mal — die Doppelerfassungs-Falle. Das Matching schlägt verbuchte Spesen bei Betrag und Empfängername vor (auch die Summe mehrerer Anträge) und bucht in einem Schritt.
- Bankkoordinaten in eigener Tabelle statt als Custom-Spalte: Eine IBAN hat in Personenlisten, Filtern und Exporten nichts zu suchen. Zweckgebunden, sichtbar nur im Spesen-Kontext und für die Person selbst; Prüfziffer-Validierung aus der Faktura.
- Belege ohne Ordner-Freigabe: Der Upload läuft über die Spesen-Schnittstelle in «Spesen/‹Geschäftsjahr›»; die Sichtbarkeit hängt am eigenen Antrag, nicht am Ordner — sonst sähe jeder Einreichende die Belege aller anderen. Lösch-Schutz wegen der 10-jährigen Aufbewahrungspflicht.
- «Meldungen» getrennt von «Aufgaben»: Eine Aufgabe verlangt eine Entscheidung, eine Meldung informiert nur. Beides in einen Topf zu werfen hätte die Inbox entwertet.
- Keine Workflow-Engine: Frei konfigurierbare Freigabeketten wären enormer Aufwand mit unverständlicher UI — Vereine brauchen genau zwei Fälle (eine Stufe, oder zwei ab Betrag X).
Bewusst nicht gebaut: Doppel-Unterschriften pro Stufe, ressort-/kostenstellenabhängige Freigabe-Personen, Magic-Link-Freigabe, Vorschüsse, Kreditkarten-Abrechnungen, Fremdwährungen, eigenes Spesen-Reporting (Kostenstellen-Auswertung deckt es ab), pain.001-Zahlungsdatei für den Massenversand ins E-Banking (späteres Paket).
Rollen-Freigabe portal.revision (🧾 im Rollen-Dialog): read-only Bilanz/ER/Journal/Beleg-Download unter /portal/revision/ — ohne CluCore-Zugriff (Revisor sieht keine Mitgliederdaten). Beleg-Auslieferung nur für Dateien, die an Buchungen des Vereins hängen.
Zugriff V1: Admin (Owner = Admin seit v0.26.0; wie Faktura); Kassier-Teilrechte später mit dem Rollen-Editor. Offen (Andock-Punkte vorbereitet): Stripe/TWINT-Abrechnungs-Importer, Spesen-Addon (Portal-Inbox), effektive MwSt-Methode, camt-Light für «nur Faktura».