konzept billing ext

This commit is contained in:
ValueOn AG 2026-03-21 01:34:59 +01:00
parent d5679f6e07
commit 4c7cc4069a

View file

@ -46,9 +46,10 @@ Mandant (Kostenstelle)
|--------|--------------|--------------|---------|
| `PREPAY_MANDATE` | Vorbezahltes Guthaben auf Mandantenebene | Mandant | Gemeinsames Budget für alle User |
| `PREPAY_USER` | Vorbezahltes Guthaben pro User | User (im Mandanten-Kontext) | Individuelles Budget |
| `CREDIT_POSTPAY` | Nutzung auf Kredit mit Nachzahlung | Mandant (Rechnungsadresse erforderlich) | Monatsrechnung |
| `UNLIMITED` | Keine Kostenlimitierung | - | Nur für interne Mandanten |
**Hinweis:** Das frühere Modell `CREDIT_POSTPAY` ist **nicht mehr** Teil des Produkts. Alte gespeicherte Werte werden beim Lesen auf `PREPAY_MANDATE` normalisiert (ohne DB-Migration).
### Modell: PREPAY_MANDATE
```
@ -74,7 +75,7 @@ Mandant "SOHA Treuhand AG"
```
Mandant "ROOT" (Bootstrap-Mandant)
├── Abrechnungsmodell: PREPAY_USER
├── Startguthaben für neue User: 10.00 CHF
├── Startguthaben bei neuem User nur hier (Root): z. B. 5.00 CHF (defaultUserCredit)
└── Nutzer:
├── User A: Guthaben 10.00 CHF → verbraucht 3.50 → Rest 6.50 CHF
└── User B: Guthaben 25.00 CHF → verbraucht 12.00 → Rest 13.00 CHF
@ -82,26 +83,13 @@ Mandant "ROOT" (Bootstrap-Mandant)
**Eigenschaften:**
- Jeder User hat eigenes Guthaben im Mandanten-Kontext
- Neuer User erhält Startguthaben (konfigurierbar)
- **Automatisches** Startguthaben nur, wenn ein User dem **Root-Mandanten** neu zugeordnet wird; bei allen anderen Mandanten wird das Nutzerkonto mit 0 CHF angelegt (Aufladung z. B. per Admin/Stripe)
- User kann Guthaben aufladen
- Bei Guthaben = 0 → AI-Features blockiert für diesen User
### Modell: CREDIT_POSTPAY
### Modell: CREDIT_POSTPAY (entfernt)
```
Mandant "Enterprise AG"
├── Abrechnungsmodell: CREDIT_POSTPAY
├── Rechnungsadresse: Enterprise AG, Musterstrasse 1, 8000 Zürich
├── Kreditlimit: 2000.00 CHF (optional)
├── Aktueller Saldo: -450.00 CHF (Schulden)
└── Monatsende: Rechnung über 450.00 CHF
```
**Eigenschaften:**
- Nutzung ohne Vorauszahlung
- Monatliche Abrechnung
- Optionales Kreditlimit
- Für verifizierte Geschäftskunden
Nicht mehr unterstützt. Siehe Hinweis in der Modell-Übersicht.
---
@ -110,18 +98,7 @@ Mandant "Enterprise AG"
### Neue Tabellen
```python
# modules/datamodels/datamodelBilling.py
class BillingAddress(BaseModel):
"""Rechnungsadresse für CREDIT_POSTPAY Mandanten"""
company: str # Firmenname
street: str # Strasse und Hausnummer
zip: str # PLZ
city: str # Ort
country: str # Land (Default: "CH")
vatNumber: Optional[str] # MwSt-Nummer (optional)
# modules/datamodels/datamodelBilling.py (vereinfacht, Stand Implementierung)
class BillingAccount(BaseModel):
"""Abrechnungskonto pro Mandant oder User-Mandant-Kombination"""
@ -130,8 +107,7 @@ class BillingAccount(BaseModel):
mandateId: str # FK → Mandate
userId: Optional[str] # FK → User (nur bei PREPAY_USER)
accountType: str # MANDATE | USER
balance: float # Aktuelles Guthaben/Saldo in CHF
creditLimit: Optional[float] # Kreditlimit in CHF (nur CREDIT_POSTPAY)
balance: float # Aktuelles Guthaben in CHF (Prepaid)
warningThreshold: float # Warnschwelle in CHF
lastWarningAt: Optional[datetime] # Letzte Warnung gesendet
enabled: bool # Account aktiv
@ -161,15 +137,11 @@ class BillingSettings(BaseModel):
id: str # UUID
mandateId: str # FK → Mandate (UNIQUE)
billingModel: str # PREPAY_MANDATE | PREPAY_USER | CREDIT_POSTPAY | UNLIMITED
billingModel: str # PREPAY_MANDATE | PREPAY_USER | UNLIMITED
# Konfiguration
defaultUserCredit: float # Startguthaben in CHF für neue User (bei PREPAY_USER)
defaultUserCredit: float # Startguthaben nur sinnvoll Root + PREPAY_USER (Bootstrap setzt z. B. 5 CHF); sonst typ. 0
warningThresholdPercent: float # Warnschwelle in % (z.B. 10)
blockOnZeroBalance: bool # AI blockieren bei Guthaben = 0
# Rechnungsadresse (erforderlich für CREDIT_POSTPAY)
billingAddress: Optional[BillingAddress]
# Benachrichtigungen
notifyEmails: List[str] # Email-Adressen für Monatsberichte
@ -322,13 +294,12 @@ class BillingService:
return BillingCheckResult(allowed=True)
if account.balance < estimatedCost:
if self.settings.blockOnZeroBalance:
return BillingCheckResult(
allowed=False,
reason='INSUFFICIENT_BALANCE',
currentBalance=account.balance,
requiredAmount=estimatedCost
)
return BillingCheckResult(
allowed=False,
reason='INSUFFICIENT_BALANCE',
currentBalance=account.balance,
requiredAmount=estimatedCost
)
return BillingCheckResult(allowed=True, currentBalance=account.balance)
@ -473,9 +444,8 @@ def _setupRootMandate():
id=generateUuid(),
mandateId=rootMandate.id,
billingModel='PREPAY_USER',
defaultUserCredit=10.0, # 10 CHF Startguthaben
defaultUserCredit=5.0, # 5 CHF Startguthaben (siehe DEFAULT_USER_CREDIT_CHF im Code)
warningThresholdPercent=20,
blockOnZeroBalance=True,
notifyOnWarning=True
)
@ -518,7 +488,7 @@ def _setupNewUserInRoot(user: User):
mandateId=rootMandate.id,
userId=user.id,
accountType='USER',
balance=settings.defaultUserCredit, # 10 CHF
balance=settings.defaultUserCredit, # z. B. 5 CHF Default
warningThreshold=settings.defaultUserCredit * 0.2, # 20%
enabled=True
)
@ -788,7 +758,6 @@ Das Automation-Editor Modal wird in drei Tabs aufgeteilt:
- Übersicht aller Mandanten mit Billing-Status
- Abrechnungsmodell ändern
- Guthaben manuell aufladen (Stripe-Vorbereitung für Zukunft)
- Rechnungsadresse verwalten (für CREDIT_POSTPAY)
- Email-Empfänger verwalten
```
@ -801,7 +770,7 @@ Das Automation-Editor Modal wird in drei Tabs aufgeteilt:
│ │ ──────────────────────────────────────────────── │ │
│ │ ROOT PREPAY_USER n/a ✓ │ │
│ │ SOHA Treuhand PREPAY_MANDATE CHF 299 ✓ │ │
│ │ Enterprise AG CREDIT_POSTPAY CHF -450 ✓ │ │
│ │ Enterprise AG PREPAY_MANDATE CHF 1200 ✓ │ │
│ │ Test GmbH PREPAY_MANDATE CHF 5 ⚠ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
@ -812,11 +781,6 @@ Das Automation-Editor Modal wird in drei Tabs aufgeteilt:
│ │ Abrechnungsmodell: [PREPAY_MANDATE ▼] │ │
│ │ │ │
│ │ Warnschwelle: [10] % │ │
│ │ Blockieren bei 0: [✓] │ │
│ │ │ │
│ │ Rechnungsadresse (für CREDIT_POSTPAY): │ │
│ │ [Firma: ________________] [Strasse: _________] │ │
│ │ [PLZ: ____] [Ort: _______] [MwSt-Nr: ________] │ │
│ │ │ │
│ │ Benachrichtigungs-Emails: │ │
│ │ [admin@soha.ch, billing@soha.ch ] │ │
@ -975,7 +939,7 @@ PowerOn Platform
1. **Root-Mandant Setup**
- `PREPAY_USER` Modell
- 10 CHF Startguthaben für neue User
- 5 CHF automatisches Startguthaben nur für neu im Root-Mandanten angelegte User (`DEFAULT_USER_CREDIT_CHF`)
- RBAC-Berechtigungen für alle LLM-Provider
2. **Bestehende User migrieren**
@ -1064,7 +1028,7 @@ Jedes AICore-Plugin definiert seine eigenen Preise via `calculatePriceCHF()`. Di
|---------|--------------|
| **AICore** | Plugin-System für LLM-Provider Integration |
| **Billing Account** | Konto für Guthaben/Saldo (pro Mandant oder User) |
| **Billing Address** | Rechnungsadresse, erforderlich für CREDIT_POSTPAY |
| **parseBillingModelFromStoredValue** | Mappt unbekannte/legacy `billingModel`-Strings auf `PREPAY_MANDATE` |
| **Connector** | AICore-Plugin für einen spezifischen Provider |
| **Kostenstelle** | Mandant, dem Kosten zugeordnet werden |
| **Mandate** | Mandant/Tenant in der Multi-Tenant-Architektur |
@ -1133,9 +1097,9 @@ frontend_nyla/src/
### Phase 1: Backend Grundstruktur
- [ ] `datamodelBilling.py` erstellen (BillingAccount, BillingTransaction, BillingSettings, UsageStatistics, BillingAddress)
- [ ] `interfaceDbBilling.py` erstellen (CRUD-Operationen)
- [ ] Datenbank-Migrations-Script erstellen
- [x] `datamodelBilling.py` (BillingAccount, BillingTransaction, BillingSettings, UsageStatistics)
- [x] `interfaceDbBilling.py` (CRUD-Operationen)
- [x] Kein separates Migrations-Script nötig (Legacy-Werte werden beim Lesen normalisiert)
- [ ] AICore-Plugins: Preise von USD auf CHF umstellen (`calculatepriceCHF` mit echten CHF-Werten)
### Phase 2: Service-Layer