Zum Hauptinhalt springen

Transaktions-Zuordnungen (TransactionAllocation)

Zweck

TransactionAllocation modelliert die buchhalterische Zuordnung einer Bank- oder Pleo-Transaktion zu einem Beleg (Sales- oder Purchase-Document), einem Auftrag oder einer Auslage — und legt fest, auf welches SKR03-Konto plus Steuersatz gebucht wird.

Die Zuordnung läuft entweder

Sobald eine Allocation gebucht wird, erzeugt der Booking-Service symmetrische Konten-Buchungen — typischerweise Bank ↔ Debitor/Kreditor + GL-Buchung auf das SKR-Konto inklusive Vorsteuer-Split.

Status — wo lebt der Workflow?

Wichtig: TransactionAllocation selbst hat kein Status-Feld. Der Workflow-Status lebt auf der Transaktion (Transaction.matchingStatus) und wird durch die Kombination aus „Allocation existiert" + „AccountEntries existieren" gespiegelt.

matchingStatus (auf Transaction)BedeutungAllocation existiert?Gebucht?
unmatchedkeine Zuordnung, kein Vorschlagneinnein
proposal_createdAllocation als Vorschlag angelegt, User soll bestätigenjanein
auto_matchedKI hat autonom zugeordnet UND gebucht (Score ≥ 95)jaja
manually_matchedUser hat im Cockpit/Tab „Bestätigen & Buchen" geklicktjaja
skippedUser hat bewusst übersprungenoptionalnein

Voraussetzungen

- Berechtigung `view:FE_TransactionAllocation`, `view:TransactionAllocation`. - Für Anlage/Update/Löschung: `create`/`update`/`delete:TransactionAllocation`. - Eine [Transaktion](/transactions) mit Status `booked` und einem [Buchhaltungskonto](/transaction-accounts) `transactionAccountFromId`. - Mindestens ein [SKR-Konto](/accounts) und ggf. ein [Steuersatz](/tax-rates) — die KI-Engine kann beides vorschlagen, beim manuellen Anlegen ist das Konto Pflicht (außer bei Workorder-Zuordnungen).

Berechtigungen (CASL)

ActionSubjectWirkung
viewFE_TransactionAllocationAllocation-Listen und -Detail aufrufbar
viewTransactionAllocationDatensätze lesen
createTransactionAllocationManuelle Zuordnung anlegen, „Bestätigen & Buchen"
updateTransactionAllocationKonto/Tax/Document nachträglich ändern
deleteTransactionAllocationZuordnung löschen (cascade: AccountEntries werden mit weggeräumt; matchingStatus fällt zurück auf unmatched)
updateTransactionSkip / matchingStatus-Flip im Cockpit
doAiSuggestionPOST /transactions/:id/ai-classify für KI-Neu-Klassifizierung

Datenmodell

FeldTypBedeutung
idUUIDPrimary Key
transactionIdUUIDFK → Transaction
documentTypeENUM nullableSalesDocument | PurchaseDocument | Workorder — Zielobjekt der Zuordnung
documentIdUUID nullableFK auf das gewählte Dokument
accountIdUUID nullableFK → Account — SKR-Konto (Pflicht außer bei Workorder-Only)
taxRateIdUUID nullableFK → TaxRate — Vorsteuer-Split
allocatedAmountDecimalBetrag (Teil-Allocation möglich, in Summe gleich Transaction.amount)
currencyStringEUR / CHF / … (i. d. R. identisch mit der Transaction)
noteTEXT nullablefreie Notiz (z. B. „Anteilig Auftrag #00045")
isSkontoBooleanWenn true: Booking auf Skonto-Konto 8736 + USt-Korrektur
createdAt, updatedAt, deletedAtDateTimeStandard + Soft-Delete

Die KI-Begründung lebt nicht auf der Allocation, sondern auf TransactionAiAssessment (classificationReasoning, classificationConfidence) und wird über den Proposal-Endpoint mitgeliefert.

Allocation-Proposal — Score-Engine

Pro Transaktion liefert GET /api/transactions/:id/allocation-proposal einen Vorschlag, der aus drei Signalen kombiniert wird:

SignalPunkteBeschreibung
Expense-Match (deterministisch)0 / 60 / 95Hard (95): Name-Token-Overlap + Betrag ±2 %; Soft (60): nur Betrag (Pleo-Pfad). Zieht defaultAccountId und taxRateId aus dem Expense-Datensatz
AI-Confidence0 – 30classificationConfidence × 0,3 aus TransactionAiAssessment (Anthropic-Klassifizierung). Füllt Lücken bei suggestedAccountId, -TaxRateId, -WorkorderId
Account-Default0 / 10transactionAccountFrom.defaultOffsetAccountId als Fallback-Konto (z. B. „Pleo Geldtransit contra → 1361")

Gesamtscore = clamp(Summe, 0, 100).

Auto-Apply läuft nur bei Score ≥ 95 UND suggestedAccountId !== null — praktisch nur bei einem Expense-Hard-Match. Reine KI-Vorschläge bleiben bewusst im Modus „Vorschlag" und brauchen Bestätigung im Cockpit.

Details: KI-Allocation-Proposal-Engine.

Drei Apply-Pfade

PfadTriggerActionresultierender matchingStatus
Auto-ApplyScore ≥ 95 (Sync)Allocation anlegen + buchen + Tx-Status setzenauto_matched
Cockpit-BestätigungUser klickt „Bestätigen & Buchen"bestehende Proposal-Allocation übernehmen + buchenmanually_matched
Proposal-OnlyScore 1 – 94 (Sync)Allocation anlegen, nicht buchenproposal_created

Idempotent: Findet der Service eine bestehende Allocation zur Transaktion, wird sie wiederverwendet — keine Duplikate.

Schritt-für-Schritt-Anleitung

Im Cockpit bestätigen

  1. Transaktions-Cockpit öffnen, Transaktion mit Status „Vorschlag" auswählen.
  2. Im AiClassificationCard rechts den vorgeschlagenen SKR-Konto, Steuersatz, Auftrag/Beleg prüfen — inklusive Score-Balken, Signal-Breakdown und KI-Begründung.
  3. Bestätigen & Buchen klicken → POST /transactions/:id/allocation-proposal/apply mit forceBookAndMatch=true.
  4. Allocation wird gebucht, AccountEntries werden erzeugt, Tx-Status wechselt auf manually_matched.

Manuell zuordnen (Allocations-Tab)

  1. Transaktion-Detail-Seite öffnen → Tab Zuordnungen.
  2. + Zuordnung klicken — Modal ManualAllocationFormModal.
  3. Ziel wählen:
    • Workorder (nur bei ausgehenden Transaktionen / Aufwand) — SKR-Konto optional (Cost-Tracking ohne GL-Eintrag möglich).
    • PurchaseDocument (ausgehend) — SKR-Konto Pflicht.
    • SalesDocument (eingehend) — SKR-Konto Pflicht.
  4. SKR-Konto + Steuersatz wählen, Betrag bestätigen, Notiz optional.
  5. Speichern → POST /api/transaction-allocations. Die Allocation wird angelegt, aber nicht gebucht.
  6. Buchung anstoßen über Cockpit (Bestätigen & Buchen) oder über die Detail-Sicht.

Allocation stornieren (Reverse)

POST /api/transaction-allocations/:id/reverse erzeugt eine Spiegel-Allocation mit umgekehrtem Debit/Credit. Die ursprüngliche Allocation bleibt zur Nachvollziehbarkeit erhalten.

Die TransactionAllocationSummary-Komponente zeigt für jeden Vorschlag/jede Allocation klickbare Icons zu den verknüpften Modulen — Sprung in neuem Tab:

IconZiel
📒Konto — SKR-Detail
💶Steuersatz
🛠Auftrag
🧾Auslage

So lässt sich aus der Buchungs-Bestätigung schnell ins Quell-Modul springen, ohne den Cockpit-Workflow zu verlassen.

Booking-Verhalten

Beim Buchen erzeugt booking.service symmetrische AccountEntry-Paare:

FallDebetKredit
Eingang (Sales-Document)1200 Bank1400 Debitor
Ausgang (Purchase-Document)1600 Kreditor1200 Bank
GL-Eintrag (SKR-Konto)SKR-Konto (z. B. 4830 Werbung)Steuer-Splitting via taxRateId
Skonto (isSkonto = true)8736 Skonto-AufwandUSt-Korrektur

Die description der erzeugten Konten-Buchungen folgt seit Welle 129 dem Muster <fromAccount.displayName> — <tx.reference> (z. B. „Pleo – Andreas Hey — OBI SAGT DANKE"); freie note der Allocation überschreibt sie.

Workflows und Zustände

API/Schnittstellen

MethodeEndpointZweckCASL
GET/api/transaction-allocationsListe (filterbar nach transactionId, documentType, accountId)view TransactionAllocation
POST/api/transaction-allocationsManuelle Zuordnung anlegen (kein Auto-Book)create TransactionAllocation
GET/api/transaction-allocations/:idDetailview TransactionAllocation
PATCH/api/transaction-allocations/:idFelder ändernupdate TransactionAllocation
DELETE/api/transaction-allocations/:idLöschen (cascade auf AccountEntries)delete TransactionAllocation
POST/api/transaction-allocations/:id/reverseSpiegel-Buchung erzeugenupdate TransactionAllocation
GET/api/transactions/:id/allocation-proposalScore-Engine-Vorschlag (mit isPersisted, matchingStatus)view Transaction, view TransactionAiAssessment
POST/api/transactions/:id/allocation-proposal/applyÜbernehmen + buchen (forceBookAndMatch=true)create TransactionAllocation, update Transaction
POST/api/transactions/:id/ai-classifyKI-Klassifizierung neu anstoßendo AiSuggestion

Verknüpfungen zu anderen Modulen

Häufige Fehler und Lösungen

FehlerLösung
„Bestätigen & Buchen" nicht klickbarVariante ist compact (linke Spalte) — Button erscheint nur in der rechten Panel-Variante. Allocation ist bereits gebucht (isBooked = true).
Karten zeigen widersprüchliche StatusmatchingStatus und isPersisted aktualisieren über Query-Cache — Cockpit-Reload bringt Konsistenz.
KI gibt keinen VorschlagTransactionAiAssessment fehlt — POST /transactions/:id/ai-classify neu anstoßen.
Allocation löschen funktioniert nichtAccountEntries hängen dran. Erst reverse, dann delete — oder direkt delete (cascade).
Manuelle Allocation ohne Konto erlaubt?Nur bei documentType = Workorder — Cost-Tracking ohne GL-Buchung. Bei Sales/Purchase ist accountId Pflicht.
Skonto-Buchung fehltisSkonto = true setzen — Service bucht automatisch auf 8736 + USt-Korrektur.

Versionshinweise

  • 2026-05-16 (Welle 129): Initiale Veröffentlichung. Status-Modell auf Transaction.matchingStatus umgestellt, Score-Engine mit drei Signalen (Expense-Match / AI-Confidence / Account-Default), Auto-Apply nur bei Expense-Hard-Match, KI-Reasoning + Confidence durchgereicht, forceBookAndMatch-Pfad für Cockpit-Bestätigung, RefLink-Icons zu Konto/Tax/Workorder/Expense, „Bestätigen & Buchen"-Button nur in Panel-Variante. Quelle: BE-Commits bbd6e713, 1b962d16, c3c1aa0c, a0f4a675, 3c7e6d7b; FE-Commits c17ce160, 871c0107, 5e6efe9c, a54fb476, 38df9cea, 5922e752, c760900c, weitere.