Zum Hauptinhalt springen

Snapshot-Pattern (Stamm vs Verwendung)

Zweck

Ein durchgaengiges Designprinzip in SpeamCore: Stamm-Datensaetze werden zum Zeitpunkt der Verwendung kopiert, nicht referenziert. So bleiben bestehende Belege, Aufträge und Verträge stabil, auch wenn Stamm-Daten später geändert werden.

Dieses Pattern ist kritisch für:

  • Buchhaltungs-/GoBD-Konformitaet (alte Belege bleiben unveraendert).
  • Vertragsstabilitaet (ein Mitarbeiter-Vertrag aus 2020 hat 2026 noch dieselben Konditionen, auch wenn der Tarif geändert wurde).
  • Inventur-Differenz-Rechnung (Bestand zum Inventur-Stichtag bleibt eingefroren).

Warum nicht einfach referenzieren?

Die Alternative waere productId als reiner Foreign-Key — dann wuerde der Beleg den aktuellen Produkt-Preis zeigen, auch wenn er vor zwei Jahren geschrieben wurde. Das waere:

  • Buchhalterisch falsch (Beleg-Summe ändert sich rueckwirkend).
  • Audit-untauglich (kein Beleg dafür was zur Belegerstellung galt).
  • Verwirrend für Anwender (alte Rechnung zeigt neue Preise).

Daher: bei der Verwendung wird Stamm-Daten kopiert (Snapshot), bei Anzeige wird die Kopie angezeigt — nicht der Stamm.

Wo das Pattern in SpeamCore angewendet wird

Verkaufsbeleg-Position (SalesDocumentItem)

Beim Hinzufuegen eines Produkts zur Beleg-Position werden aus dem Produkt-Stamm kopiert:

  • priceNet (Verkaufspreis)
  • taxRate (Steuersatz)
  • unitId (Einheit)
  • title und description (bei „Produkt"-Typ; bei „Produkt benutzerdefiniert" sind es ueberschreibbare Custom-Werte)

Änderungen am Produkt-Stamm wirken nicht rueckwirkend auf bestehende Belege. Manuelles Re-Sync über den Toolbar-Button „Produktdaten aktualisieren" (siehe Belegpositionen-Toolbar) aktualisiert die Snapshots gezielt — sinnvoll bei Beleg-Entwuerfen, NICHT bei gesperrten Belegen.

Auftrag-Material (WorkorderMaterial)

Beim Hinzufuegen eines Materials werden Verkaufspreis, Einheit und Stammdaten als Snapshot übernommen. Änderungen am Produkt-Stamm wirken nicht rueckwirkend — siehe workorders-materials.

Auftrag-Adressen (Workorder.locationParent* / customerParent*)

Beim Anlegen eines Auftrags werden Adressfelder vom Standort und Kunde als Snapshot kopiert (locationParentName, locationParentStreet, ..., customerParentName, ...). Änderungen am Standort/Kunde wirken nicht auf bestehende Aufträge. Siehe workorders.

Vertrags-bezogene Auftrags-Defaults

Beim Auftrags-Anlegen werden branchId und employeeOfficeId aus dem aktiven Vertrag des Mitarbeiters kopiert. Bei spaeterem Vertragswechsel bleibt der Auftrag stabil — der neue Vertrag wirkt nur auf neue Aufträge. Siehe employees-contracts.

Verkaufsbeleg-Textbausteine (TextBlockParent)

Beim Verknuepfen eines Textbausteins zum Beleg wird der Stamm-Text als Snapshot kopiert. Beleg-spezifische Override-Texte bleiben editierbar, ohne den Stamm zu touchieren. Siehe sales-documents-text-blocks.

Sub-Unternehmer-Stundensaetze (ContractorEmployeeCostRate)

Beim Erfassen einer Arbeitszeit für einen Subunternehmer wird der zur Erfassungs-Zeit gültige rate aus ContractorEmployeeCostRate als Snapshot übernommen — Stundensatz-Änderungen wirken nicht rueckwirkend. Siehe contractors.

Inventur-Position (InventoryWarehouseProduct)

Beim Anlegen einer Inventur werden alle aktuellen Bestaende des Lagers als Snapshot kopiert (currentAmount zum Inventur-Beginn). Spaetere normale Lager-Bewegungen ändern die Inventur nicht. Siehe inventories.

Steuersatz-Gültigkeiten (TaxRateValidity)

Eine Belegposition speichert den Steuersatz als Snapshot zur Belegzeit. Änderungen am Steuersatz (z. B. 19% → 16% in 2020) wirken nur auf neue Belege, alte bleiben mit dem damaligen Satz stabil.

Diagramm: Stamm vs Snapshot beim Verkaufsbeleg

Wann KEIN Snapshot — sondern Live-Referenz?

Manche Bezuege sind absichtlich Live, weil eine rueckwirkende Änderung gewünscht ist:

BezugLive oder Snapshot?Warum
Customer.idSalesDocument.parentIdLiveDie Kunden-Identitaet ist stabil — der Beleg bezieht sich immer auf denselben Kunden.
Customer.addressSalesDocument.customerParent*SnapshotAdressen ändern sich; auf alten Belegen muss die alte Adresse stehen bleiben.
Employee.idWorkorder.employeeIdLiveDer Mitarbeiter ist die Person — bleibt stabil.
Employee.activeContractWorkorder.branchIdSnapshotDer zur Auftragszeit gültige Vertrag liefert die Niederlassung; spaeterer Vertragswechsel ändert das nicht.
Product.idSalesDocumentItem.productIdLiveWenn das Produkt gelöscht wird, soll der Beleg-Verweis ins Leere zeigen.
Product.priceNetSalesDocumentItem.priceNetSnapshotPreis ändert sich; alter Beleg behaelt alten Preis.

Verknuepfungen

Versionshinweise

  • 2026-04-30: Initiale Veroeffentlichung — durchgaengiges Stamm-vs-Snapshot-Pattern dokumentiert mit allen Anwendungsfaellen.