wiki/b-reference/gateway/features/trustee.md
ValueOn AG 24190f532a fixes
2026-04-26 08:36:33 +02:00

163 lines
11 KiB
Markdown

<!-- status: canonical -->
<!-- lastReviewed: 2026-04-25 -->
<!-- verifiedAgainst: gateway/modules/workflows/methods/methodTrustee/ + gateway/modules/features/trustee/ + Typed Action Architecture Phasen 1-5 + Account-Balance-Import -->
# Feature: Trustee
## Ueberblick
Das **Trustee**-Feature digitalisiert Spesenbelege und synchronisiert sie in ein externes Buchhaltungssystem (ABACUS, Bexio, Banana, ...). Es kombiniert eine **Workflow-Method** (`trustee` mit fuenf typisierten Actions) mit einer **Feature-Domain** (`features/trustee/` -- Datenmodelle, Interface, Routes, AccountingBridge).
Datenfluss:
```
SharePoint / Upload
|
v
trustee.extractFromFiles (AI extrahiert Belegtyp + Felder -> ActionDocument-Liste)
|
v
trustee.processDocuments (legt TrusteeDocument + TrusteePosition an, verlinkt Bankkonten)
|
v
trustee.syncToAccounting (pusht Positions via AccountingBridge ins Zielsystem)
```
Alle drei Actions konsumieren `featureInstanceId` als typisierten **`FeatureInstanceRef`**-Envelope (Typed Action Architecture). Sub-Action `trustee.refreshAccountingData` und Read-only `trustee.queryData` erweitern den Funktionsumfang fuer Sync-Refresh und AI-Tool-Zugriffe.
---
## Module
| Modul | Pfad | Verantwortung |
|-------|------|---------------|
| Method (Workflow) | `gateway/modules/workflows/methods/methodTrustee/` | `MethodTrustee` registriert die fuenf Actions; jede Action liegt in `actions/<name>.py` mit eigener typisierter Eingabe + `ActionResult`-Output. |
| Feature-Domain | `gateway/modules/features/trustee/` | Datenmodell (`datamodelTrustee.py`), Interface (`interfaceTrustee.py`), Route-Module (`routeFeatureTrustee*.py`), `AccountingBridge` (`accountingBridge.py`). |
| Editor-Adapter | `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py` | Bindet die fuenf Actions als Editor-Nodes (`trustee.extractFromFiles`, ...) -- Ports + Pflicht-Felder werden via `registerNodeWithMethod` aus den Action-Signaturen abgeleitet. |
| Frontend | `frontend_nyla/src/components/Trustee/` + `TrusteeDataTablesView` | UI fuer Document/Position-Verwaltung, Daten-Tabellen, Connector-Konfiguration. |
---
## Actions (typisierte Inputs + Outputs)
| Action | Eingabe (Pflicht) | Output | Zweck |
|--------|-------------------|--------|-------|
| `trustee.extractFromFiles` | `featureInstanceId` (FeatureInstanceRef), entweder `fileIds: List[str]` oder `sourceFolder` | `DocumentList` (`documents: List[ActionDocument]`) | AI extrahiert Belegtyp + Strukturdaten aus PDFs / JPGs (SharePoint oder Upload). |
| `trustee.processDocuments` | `featureInstanceId`, `documentList: DocumentList` | `ActionResult` (mit `documents: List[ActionDocument]`) | Legt `TrusteeDocument`-Records + zugehoerige `TrusteePosition`-Eintraege an, auto-verlinkt Bankauszuege via `_linkBankPositions`. |
| `trustee.syncToAccounting` | `featureInstanceId`, `documentList: DocumentList` (typisch DataRef auf `processDocuments.documents`) | `ActionResult` (mit `documents`) | Pusht alle gebuchten Positions per `AccountingBridge.pushBatch` ins Zielsystem; markiert erfolgreiche Sync-Records. |
| `trustee.refreshAccountingData` | `featureInstanceId` | `ActionResult` (`success`, `error`) | Refresht Kontenplan + Saldo + Kontakte aus dem Buchhaltungssystem. |
| `trustee.queryData` | `featureInstanceId`, freie Filter-Argumente | `ActionResult` mit Query-Resultat | Read-only Zugriff fuer den AI-Agent (`dynamicMode=True`). |
> Schemas leben in `gateway/modules/datamodels/datamodelWorkflowActions.py` + `gateway/modules/features/trustee/datamodelTrustee.py`. **Single source of truth** fuer Editor + AI-Agent + Adapter ist die Action-Signatur (`/api/automation2/catalog`).
---
## Datenmodell
| Modell | Datei | Kommentar |
|--------|-------|-----------|
| `TrusteeOrganisation` | `datamodelTrustee.py` | Buchhaltungs-Mandant innerhalb der FeatureInstance. |
| `TrusteeRole`, `TrusteeAccess` | dito | Rollen + Zugriffsregeln je Organisation. |
| `TrusteeContract` | dito | Vertragsdatensatz je Mieter / Kontakt. |
| `TrusteeDocument` | dito | Originaldokument + AI-Klassifikation + Statusfelder; Quelle fuer Positionen. |
| `TrusteePosition` | dito | Buchungszeile (Debit/Kredit, Konto, Betrag, Datum, Sync-Status). |
| `TrusteeData*` (Account, JournalEntry, JournalLine, Contact, AccountBalance) | dito | Read-only Spiegel des Buchhaltungssystems (Kontenplan, Buchungen, Saldenliste). |
| `TrusteeAccountingConfig` | dito | Connector-Konfiguration (Bridge-Typ, Secrets via Encryption). |
| `TrusteeAccountingSync` | dito | Audit-Eintrag pro Sync-Lauf. |
---
## FeatureInstanceRef (Typed Action Architecture)
Seit Phase 5 ist `featureInstanceId` ueberall als **typisierter Envelope** persistiert:
```json
{ "$type": "FeatureInstanceRef",
"id": "11111111-1111-1111-1111-111111111111",
"featureCode": "trustee" }
```
- **Schreiben:** `materializeFeatureInstanceRefs` (`automation2/featureInstanceRefMigration.py`) wandelt rohe UUIDs **bei jedem Run** automatisch ins Envelope-Format. Optional persistiert `gateway/scripts/script_migrate_feature_instance_refs.py` die Aenderung in der DB (`--dry-run` Default).
- **Lesen:** `_unwrapTypedRef` (`graphUtils`) entpackt den Envelope vor dem Action-Call -- Trustee-Actions sehen weiterhin `featureInstanceId: "<uuid>"` und brauchen keinen Patch.
- **Discriminator:** `featureCode = "trustee"` macht die Trustee-Variante eindeutig (Editor zeigt `[trustee] <Label>` im Picker).
---
## Pick-not-Push fuer DocumentList
Die typische Spesenbelege-Kette ist:
```
trigger.manual -> trustee.extractFromFiles -> trustee.processDocuments -> trustee.syncToAccounting
```
`trustee.processDocuments` und `trustee.syncToAccounting` ziehen ihren `documentList`-Input ueber **`DataRef`**-Bindings aus dem Vorgaengerknoten:
```json
{ "type": "ref", "nodeId": "process", "path": ["documents"] }
```
`*`-Wildcard-Bindings (`["documents", "*", "name"]`) werden vom Resolver iteriert und liefern eine Liste -- noetig fuer Loop-Vorschlaege im DataPicker.
---
## AccountingBridge
`gateway/modules/features/trustee/accountingBridge.py` ist die einheitliche Abstraktion ueber alle Buchhaltungssysteme. `AccountingBridge.pushBatch(positions, config)` validiert + pusht; konkrete Adapter (`abacus.py`, `bexio.py`, `banana.py`, ...) implementieren das Protokoll. Sync-Ergebnisse landen als `TrusteeAccountingSync`-Audit-Eintraege.
`trustee.refreshAccountingData` ruft `AccountingBridge.fetchSnapshots` -- die Tabellen `TrusteeDataAccount`, `TrusteeDataJournal*`, `TrusteeDataContact`, `TrusteeDataAccountBalance` werden read-only befuellt.
### Saldenliste (`TrusteeDataAccountBalance`)
Die Tabelle `TrusteeDataAccountBalance` enthaelt pro Konto + Periode (13 Buckets: Annual `periodMonth=0` + 12 Monate) einen Datensatz mit `openingBalance`, `debitTotal`, `creditTotal`, `closingBalance`.
**Datenquelle (Prioritaet):**
1. **Connector** (`getAccountBalances`): Jeder Accounting-Connector kann ueber die optionale Methode `BaseAccountingConnector.getAccountBalances(config, years, accountNumbers)` echte Salden liefern. `AccountingPeriodBalance` (Pydantic) ist der einheitliche Rueckgabetyp.
- **RMA**: Dedizierter Endpunkt `GET /gl/saldo` -- liefert den echten, durch RMA berechneten Schlusssaldo inkl. Vorjahresvortrag und Jahresabschluss-Buchungen. Pro Konto + Stichtag ein API-Call. Wildcard-Pattern (`xxxx`, `xxxxx`) aus Kontenplan abgeleitet fuer Bulk-Abfrage.
- **Bexio**: Kein Saldo-Endpunkt verfuegbar; Aggregation aus `GET /3.0/accounting/journal` mit korrekter kumulativer Berechnung (Bilanzkonten 1xxx-2xxx carry-over, Erfolgskonten 3xxx-9xxx jaehrlicher Reset).
- **Abacus**: Aggregation aus `GET GeneralJournalEntries` (OData V4). Code-Hinweis fuer optionale `AccountBalances`-Entity (instanzabhaengig).
2. **Lokaler Fallback** (`_buildLocalBalanceFallback`): Wenn der Connector `[]` zurueckgibt (kein Endpunkt oder Fehler), aggregiert `accountingDataSync` die bereits importierten `TrusteeDataJournalLine`-Zeilen kumulativ. `openingBalance` der ersten Periode = `0` (kein Vortrag aus fehlenden Daten erfindbar).
Quelle wird im Log pro Sync dokumentiert: `source=connector` bzw. `source=local-fallback`.
---
## REST-Endpunkte (Auswahl)
Liste in `wiki/b-reference/gateway/architecture.md` (Abschnitt "Feature: Trustee -- Daten-Tabellen-Endpunkte"); zentral:
| Endpunkt | Modell | Zweck |
|----------|--------|-------|
| `GET /api/trustee/{instanceId}/documents` | `TrusteeDocument` | Paginierte Document-Liste (RBAC + Filter). |
| `GET /api/trustee/{instanceId}/positions` | `TrusteePosition` | Paginierte Position-Liste. |
| `GET /api/trustee/{instanceId}/data/...` | `TrusteeData*` | Read-only Spiegel (Konten, Journal, Saldo, Kontakte). |
| `GET /api/trustee/{instanceId}/accounting/configs` | `TrusteeAccountingConfig` | Connector-Konfiguration (Secrets maskiert). |
| `GET /api/trustee/{instanceId}/accounting/syncs` | `TrusteeAccountingSync` | Audit der Sync-Laeufe. |
UI-Sichtbarkeit der Daten-Tabellen-Seite haengt am Permission-Eintrag `ui.feature.trustee.data-tables` (Template-Rollen `trustee-viewer`, `trustee-user`, `trustee-accountant`).
---
## Tests
| Test | Datei | Was er beweist |
|------|-------|----------------|
| Unit | `gateway/tests/unit/methods/test_methodTrustee.py` (sofern vorhanden) | Action-Schemas + Pflicht-Felder. |
| Adapter-Drift | `gateway/tests/unit/graphicalEditor/test_adapter_validator.py` | Editor-Nodes synchron zu Method-Signaturen (`assert report.errors == []`). |
| FeatureInstanceRef | `gateway/tests/unit/workflows/test_featureInstanceRefMigration.py` | Materialisierung + Auto-Unwrap, Idempotenz. |
| Live-E2E | `gateway/tests/integration/trustee/test_spesenbelege_workflow_e2e.py` | `executeGraph` durch `processDocuments + syncToAccounting` mit In-Memory-Fakes. |
| DB-CLI | `gateway/tests/unit/scripts/test_migrate_feature_instance_refs.py` | Dry-run + Live-Migration des persistierten Graphs. |
| Balance RMA | `gateway/tests/unit/features/trustee/test_accountingConnectorRma_balances.py` | `getAccountBalances` via gemocktem `/gl/saldo` (BuHa-SoHa-Szenario + ER-Reset). |
| Balance Bexio | `gateway/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py` | Kumulative Aggregation aus Journal (BS carry-over + ER-Reset). |
| Balance Abacus | `gateway/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py` | OData-Aggregation (BS carry-over + ER-Reset). |
| Balance Sync | `gateway/tests/unit/features/trustee/test_accountingDataSync_balances.py` | Connector-Pfad (verbatim persist) + Local-Fallback (kumulative Berechnung). |
---
## Links
- Architektur-Plan: [`wiki/c-work/3-validate/2026-04-typed-action-architecture.md`](../../../c-work/3-validate/2026-04-typed-action-architecture.md)
- Folge-Plan: [`wiki/c-work/1-plan/2026-04-typed-action-followups.md`](../../../c-work/1-plan/2026-04-typed-action-followups.md)
- Adapter-Drift-Backlog (abgeschlossen): [`wiki/c-work/4-done/2026-04-adapter-drift-cleanup.md`](../../../c-work/4-done/2026-04-adapter-drift-cleanup.md)
- Account-Balance-Import (abgeschlossen): [`wiki/c-work/4-done/2026-04-trustee-account-balances-import.md`](../../../c-work/4-done/2026-04-trustee-account-balances-import.md)