Files
kaffeekasse-saas/docs/billing.md
T
clemensandClaude Sonnet 5 ade1fd0ed9 Billing Phase 1: Tarifstatus-Datenmodell und Tariflogik je Mandant
Vorbereitung fuer Stripe Billing (Zahlungseinzug) + bestehendes Dolibarr
des Kunden (Rechnungsstellung/Buchhaltung) statt eines eigenen Rechnungs-
systems oder eines zusaetzlichen ERP nur fuer Kaffeeliste - Begruendung
in docs/billing.md.

- Neue Tabelle tenant_billing (plan_code, subscription_status, sowie
  bereits vorbereitete, noch ungenutzte Felder fuer Stripe/Dolibarr-IDs).
- app/billing.php: billing_plans() als einzige Quelle der Tarifstufen
  (synchron mit preise.php), billing_required_plan_code() anhand aktiver
  Teilnehmerzahl, billing_check_tenant() vergleicht gebuchten mit
  benoetigtem Tarif - rein informativ, kein Enforcement, solange Stripe
  nicht angebunden ist.
- Neue Mandanten starten automatisch auf plan_code='free' bei der
  Registrierung.
- mandant-einstellungen.php zeigt Owner/Admin ihren aktuellen Tarif und
  Teilnehmerstand, mit Hinweis bei Bedarf einer hoeheren Stufe.
- Back-Office zeigt zusaetzlich zur Mandantenliste den gebuchten und
  (falls abweichend) den tatsaechlich benoetigten Tarif.

Live getestet: Tarifgrenzen (10/25/50/150) mit einem Mandanten unter und
einem ueber dem Freikontingent geprueft, UI in Mandant-Einstellungen und
Back-Office verifiziert. Alle M8-Isolations-/Rollenmatrix-Tests weiterhin
gruen.

Phase 2 (Stripe) und Phase 3 (Dolibarr-Sync) folgen, sobald Test-Keys
beziehungsweise Sandbox-Zugang vorliegen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 23:38:28 +02:00

97 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Preis- und Abrechnungslogik
Stand: 2026-07-16
Geplante Architektur (mit dem Kunden abgestimmt): **Stripe Billing für den
Zahlungseinzug, bestehendes Dolibarr für Rechnungsstellung/Buchhaltung.**
Kein eigenes Rechnungssystem, kein zusätzliches ERP nur für Kaffeeliste
siehe Begründung unten.
## Warum diese Aufteilung
Drei getrennte Probleme:
1. **Rechnung erzeugen** löst Dolibarr (bereits im Einsatz für ein
anderes Business des Kunden), fortlaufend nummeriert, GoBD-konform.
2. **Geld tatsächlich einziehen** der eigentlich schwierige Teil
(wiederkehrende Belastung, Fehlschlag-Wiederholung, Zahlungsmittel-
Verwaltung). Weder ein selbstgebautes System noch Dolibarr allein lösen
das; ein Zahlungsanbieter mit Abo-Logik schon.
3. **Tarif-/Nutzungsstand verwalten** das übernimmt Kaffeeliste selbst,
da die Teilnehmerzahl je Mandant ohnehin schon vorhanden ist.
Empfehlung: **Stripe Billing** statt Mollie, weil eine echte
Abo-Logik mit automatischem Stufenwechsel gebraucht wird (Stripes
Billing-Produkt ist dafür ausgereifter als Mollies Subscriptions-API);
Mollie ist bei SEPA-Lastschrift günstiger, aber weniger auf SaaS-Abos
zugeschnitten.
## Phase 1: Datenmodell und Tariflogik (umgesetzt, keine externen Zugänge nötig)
Umgesetzte Dateien:
```text
database/migrations/0014_saas_tenant_billing.sql
app/billing.php
app/saas-auth.php (Init bei Registrierung)
mandant-einstellungen.php (Anzeige "Abo & Tarif")
app/platform-admin.php, backoffice.php (Tarif-Spalte im Back-Office)
```
- Neue Tabelle `tenant_billing`: `plan_code`, `subscription_status`,
`stripe_customer_id`, `stripe_subscription_id`, `current_period_end`,
`dolibarr_thirdparty_id` (letztere beide vorbereitet für Phase 2/3,
noch ungenutzt).
- `billing_plans()` ist die einzige Quelle für die Tarifstufen
(`free`/`basic`/`plus`/`pro`/`enterprise`), synchron mit den Preisen auf
`preise.php`.
- `billing_required_plan_code()` errechnet anhand der aktiven
Teilnehmerzahl die günstigste ausreichende Stufe.
- `billing_check_tenant()` vergleicht gebuchten mit benötigtem Tarif;
rein informativ **kein Enforcement**, kein Sperren bei Überschreitung.
Solange Stripe nicht angebunden ist, wird bei Bedarf manuell
umgestellt (Hinweistext verweist auf Kontakt per E-Mail).
- Neue Mandanten starten automatisch mit `plan_code = 'free'`.
- Owner/Admin sehen ihren aktuellen Tarif und die aktive Teilnehmerzahl
unter „Abo & Tarif" auf `mandant-einstellungen.php`; bei Bedarf einer
höheren Stufe erscheint ein Hinweis.
- Das Back-Office (`backoffice.php`) zeigt zusätzlich zur Mandantenliste
den gebuchten Tarif und, falls abweichend, den tatsächlich benötigten
Tarif der Betreiber sieht auf einen Blick, wer manuell hochgestuft
werden müsste.
Live getestet: Tarifgrenzen-Berechnung (10/25/50/150) mit einem Mandanten
knapp unter und einem mit 12 Teilnehmern (über dem Freikontingent, korrekt
als „basic" erkannt) geprüft; UI-Anzeige in Mandant-Einstellungen und
Back-Office live verifiziert. Alle bestehenden M8-Isolationstests und der
Rollen-Matrix-Test bleiben unverändert grün.
## Phase 2: Stripe-Anbindung (noch offen)
Wartet auf Stripe-Test-API-Keys vom Kunden. Geplanter Umfang:
- Stripe Checkout zum Abschließen/Wechseln eines bezahlten Tarifs.
- Webhook-Endpunkt für `checkout.session.completed`,
`customer.subscription.updated`/`.deleted`, `invoice.paid`/`.payment_failed`,
der `tenant_billing` aktuell hält.
- Stripe Customer Portal für Zahlungsmittel-Verwaltung/Kündigung durch
den Kunden selbst.
- Automatischer Stufenwechsel: Sobald `billing_check_tenant()` einen
höheren Bedarf erkennt, Wechsel der Stripe-Subscription auslösen
(mit Proration) statt nur anzuzeigen.
## Phase 3: Dolibarr-Anbindung (noch offen)
Wartet auf Zugang zu einer Dolibarr-Sandbox/Testinstanz (bewusst nicht
direkt gegen die produktive Instanz des Kunden, um deren bestehende
Buchhaltungsdaten nicht zu gefährden). Geplanter Umfang:
- Bei jedem erfolgreichen Stripe-Zahlungsereignis (`invoice.paid`) über
die Dolibarr-REST-API eine Rechnung im bestehenden Dolibarr des Kunden
anlegen (`dolibarr_thirdparty_id` verknüpft den Mandanten mit dem
Dolibarr-Kunden).
- Stripe bleibt alleiniger Zahlungsweg; Dolibarr wird nur als Buchhaltungs-
Spiegel befüllt, nicht selbst zum Auslösen von Zahlungen verwendet.
- Erst nach erfolgreichem Test gegen die Sandbox gegen die produktive
Dolibarr-Instanz freigeben.