Weiterführende Themen

Reservationen (Bestand und Ladeeinheit)

Einführung

Reservationen sichern geplante Lageroperationen ab, bevor sie ausgeführt werden. Es gibt Reservationen auf Bestandsebene (stock_reservation_*, Schlüssel stock_id) und auf Ladeeinheitsebene (unit_reservation_*, Schlüssel unit_id).

Mehrere Reservationen können über das Attribut composition (UUID) zu einer Gruppe zusammengefasst werden. Eine Gruppe erfüllt drei Zwecke:

  1. Governing Reservation — bestimmt die reservierte Menge für abbuchende Operationen (Split, Outbound).
  2. Ausführungsreihenfolge — innerhalb einer Composition gilt: Split → Umlagerung (xfer) → Outbound.
  3. Bestandsbezug nach Split — nach einem Split beziehen sich nachfolgende Reservationen der Composition auf den neuen Bestand.

Implementierung (Bestand): werner-backend.domain.stock-reservation.* inkl. constraints und availability. Ladeeinheiten: werner-backend.domain.unit-reservation.* inkl. constraints; hierarchische Vorbedingungen (Abschnitte 2.5–2.6) über werner-backend.domain.reservation.feasibility.

Gemeinsame Spalten auf abstract-Ebene (Auszug): state, sort, composition, ready_from (Zeitpunkt, ab dem eine Reservation ausführbar ist — siehe 3. Vorbedingungen für das Ausführen), unit_barcode / unit_id_persisted bzw. stock_barcode / stock_id_persisted zur persistenten Nachverfolgung.

1. Reservationsarten

1.1 Bestand (stock_reservation_*)

TypTabelleKurzbeschreibung
Umlagerung (xfer)stock_reservation_xferBestand an neuen Standort (Lager, Adresse, Fahrzeug, Unit, anderer Bestand mit Merge). Reserviert den gesamten Bestand.
Outboundstock_reservation_outboundAusgang — Bestand wird entnommen oder (Miete) umgebucht. Mengenbasiert.
Splitstock_reservation_splitTeilung in mehrere neue Bestände. Mengenbasiert (amount[]).
Inventurstock_reservation_inventoryAttribute oder Menge des Bestands ändern; Menge 0 = Löschen.
Sperre (lock)stock_reservation_lockSetzt stock.locking_reason_id.
Entsorgung (destroy)stock_reservation_destroyArchiviert den Bestand.

Composition-Typen (Kette): Split, xfer, Outbound. Isolierte Typen: Inventur, lock, destroy.

1.2 Ladeeinheit (unit_reservation_*)

TypTabelleKurzbeschreibung
Umlagerung (xfer)unit_reservation_xferLadeeinheit inkl. verschachtelter Inhalte an neuen Standort.
Outboundunit_reservation_outboundAuslagern der Unit inkl. enthaltener Units und Bestände (rekursiv).
Inventurunit_reservation_inventoryAttribute einer oder mehrerer Units ändern.
Sperre (lock)unit_reservation_lockVerhindert Änderungen an der Unit und enthaltenen Units/Beständen.
Entsorgung (destroy)unit_reservation_destroyEntsorgen der Unit inkl. enthaltener Units und Bestände (rekursiv).

Unit-xfer und Unit-outbound können wie bei Beständen in Compositions gruppiert werden; lock, inventory und destroy sind isoliert.

2. Vorbedingungen beim Anlegen einer Reservation

2.1 Legende der Zellwerte

WertBedeutung
OKReservation darf angelegt werden.
NOKReservation darf nicht angelegt werden.
N/ANicht anwendbar (falscher Bezugsebene-Typ).
CN1Nur wenn amount > 0 und amount ≤ available_amount (Bestand; siehe can-create-reservation?).
CN2Nur wenn kein stock.locking_reason_id gesetzt ist (Outbound-Ausführung; siehe check-stock-not-locked-for-outbound).

Abschnitte mit Hinweis (Zielbild) sind fachlich verbindlich definiert; die Backend-Prüfung für ready_from beim Ausführen folgt in Issue #358.

2.2 Matrix — bestehende Reservation auf demselben Bestand

Quelle für Bestand: werner-backend.domain.stock-reservation.constraints/can-create-reservation?.

Zeilen: anzulegende Reservation · Spalten: pending (state = init) bestehende Reservation auf demselben stock_id

Anlage ↓ / Bestehend →xferoutboundsplitinventorylockdestroy
stock_reservation_xferOKOKOKNOKNOKNOK
stock_reservation_outboundOKOKOK (CN1)NOKNOKNOK
stock_reservation_splitOKOKOK (CN1)NOKNOKNOK
stock_reservation_inventoryOKOKOKOKOKNOK
stock_reservation_lockNOKNOKNOKOKOKNOK
stock_reservation_destroyNOKNOKNOKNOKNOKNOK

Hinweise:

  • Mehrere lock- oder inventory-Reservationen auf demselben Bestand sind zulässig (sequenziell bzw. parallel bei lock+inventory).
  • Eine zweite destroy-Reservation auf demselben Bestand ist nicht zulässig (kein zusätzlicher Nutzen; Ausführung würde am bereits archivierten Bestand scheitern).
  • xfer prüft keine Menge, reserviert aber über availability den vollen Bestand — weitere abbuchende Reservationen können über CN1 scheitern.

2.3 Matrix — Unit-Reservationen vs. N/A auf Bestandsspalten

Unit-Reservationen können nicht auf Beständen angelegt werden; Spalten „Bestand (aktuell / untergeordnet)“ sind für Zeilen 8–12 N/A.

Anlage ↓ / Bestehend →xferoutboundsplitinventorylockdestroy
unit_reservation_xferN/AN/AN/AN/AN/AN/A
unit_reservation_outboundN/AN/AN/AN/AN/AN/A
unit_reservation_inventoryN/AN/AN/AN/AN/AN/A
unit_reservation_lockN/AN/AN/AN/AN/AN/A
unit_reservation_destroyN/AN/AN/AN/AN/AN/A

2.4 Matrix — bestehende Reservation auf derselben Ladeeinheit

Quelle: werner-backend.domain.unit-reservation.constraints/can-create-reservation?.

Anlage ↓ / Bestehend →xferoutboundinventorylockdestroy
unit_reservation_xferOKOKNOKNOKNOK
unit_reservation_outboundOKOKNOKNOKNOK
unit_reservation_inventoryOKOKOKOKNOK
unit_reservation_lockNOKNOKOKOKNOK
unit_reservation_destroyNOKNOKNOKNOKNOK

Eine zweite destroy-Reservation auf derselben Unit ist nicht zulässig (analog zu Bestand).

2.5 Matrix — Anlage von Reservationen auf einer Unit unter Beachtung von Reservationen auf enthaltenen Units/Beständen

Implementiert über werner-backend.domain.reservation.feasibility (Feature child/stock/*).

Zeilen: anzulegende Reservation auf der Parent-Unit · Spalten: pending Reservation auf enthaltenem Bestand (split/xfer/outbound/inventory/lock/destroy)

Anlage (Parent) ↓ / Bestehend auf Inhalt →stock xferstock outboundstock splitstock inventorystock lockstock destroy
unit_reservation_xferOKOKOKOKNOKNOK
unit_reservation_outboundNOKNOKNOKNOKNOKNOK
unit_reservation_inventoryOKOKOKOKOKOK
unit_reservation_lockNOKNOKNOKNOKOKNOK
unit_reservation_destroyNOKNOKNOKNOKNOKNOK

Begründung:

  • Routing-xfer auf Unit-Ebene bewegt Container und Inhalt zu einem Versandplatz; pending split/xfer/outbound auf enthaltenen Beständen bleiben gültig (Picking kann vor oder nach dem Routing angelegt werden). Nur lock und destroy auf Inhalten blockieren die Parent-Umlagerung.
  • unit_reservation_outbound setzt die rekursive Auslagerungsannahme voraus — jede pending Reservation auf Inhalten (inkl. Inventur, die Menge/Artikel ändern kann) macht die Parent-Outbound-Reservation ungültig.
  • unit_reservation_inventory auf der Parent-Unit betrifft nur Unit-Attribute; pending Reservationen auf enthaltenen Beständen stehen dem nicht entgegen.

2.5b Matrix — Anlage auf einer Unit unter Beachtung von Reservationen auf enthaltenen Units

Implementiert über werner-backend.domain.reservation.feasibility (Feature child/unit/*).

Zeilen: anzulegende Reservation auf der Parent-Unit · Spalten: pending Reservation auf enthaltener Unit (xfer / outbound / inventory / lock / destroy)

Anlage (Parent) ↓ / Bestehend auf enthaltener Unit →unit xferunit outboundunit inventoryunit lockunit destroy
unit_reservation_xferOKOKOKNOKNOK
unit_reservation_outboundNOKNOKNOKNOKNOK
unit_reservation_inventoryOKOKOKOKOK
unit_reservation_lockNOKNOKNOKOKNOK
unit_reservation_destroyNOKNOKNOKNOKNOK

Symmetrisch zu Abschnitt 2.5 (enthaltene Bestände): Routing-xfer auf Parent-Ebene toleriert pending Operationen auf enthaltenen Units, ausser lock/destroy; Parent-outbound und Parent-destroy blockieren bei jeder pending Child-Unit-Reservation.

2.6 Matrix — Anlage von Reservationen auf einer Unit/einem Bestand unter Beachtung von Reservationen auf übergeordneten Units

Implementiert über werner-backend.domain.reservation.feasibility (Feature parent/unit/*).

Zeilen: anzulegende Reservation auf untergeordnetem Bestand oder Unit · Spalten: pending Reservation auf der übergeordneten Unit (xfer / outbound / inventory / lock / destroy)

Anlage auf Inhalt ↓ / Bestehend auf Parent-Unit →unit xferunit outboundunit inventoryunit lockunit destroy
stock_reservation_xferOKNOKOKNOKNOK
stock_reservation_outboundOKNOKOKNOKNOK
stock_reservation_splitOKNOKOKNOKNOK
stock_reservation_inventoryOKNOKOKOKNOK
stock_reservation_lockNOKNOKNOKOKNOK
stock_reservation_destroyNOKNOKNOKNOKNOK
unit_reservation_xferOKNOKOKNOKNOK
unit_reservation_outboundOKNOKOKNOKNOK
unit_reservation_inventoryOKNOKOKOKNOK
unit_reservation_lockNOKNOKNOKOKNOK
unit_reservation_destroyNOKNOKNOKNOKNOK

Begründung:

  • Pending Parent-outbound blockiert jede weitere Outbound-Reservation auf Inhalten (der Parent-Outbound umfasst den gesamten Inhalt rekursiv).
  • Pending Parent-xfer blockiert kein Picking auf Inhalten (Routing zuerst, Split/Outbound danach — symmetrisch zu Abschnitt 2.5); ein Child-xfer ist ebenfalls zulässig, solange kein Parent-outbound pending ist.
  • Pending Parent-inventory erlaubt Child-inventory (sequenziell); Child-outbound unter Parent-inventory ist nicht zulässig (Inventur auf Parent kann die Outbound-Annahme invalidieren).

2.7 Feasibility-Schicht (Batch-Prüfung)

Namespace: werner-backend.domain.reservation.feasibility · Regeldaten: reservation.rules.

Für Kandidatenlisten (Picking, Wareneingang, UI-Vorschau) und als Gatekeeper beim Anlegen:

  1. Stufe A (boolean): emit-feature-matrix sammelt pending Reservationen auf dem Kandidaten selbst (self/*), enthaltenen Beständen (child/stock/*), enthaltenen Units (child/unit/*) und übergeordneten Units (parent/unit/*) in einem SQL-Snapshot. check-boolean-feasibility wendet die Regelmasken aus den Matrizen 2.2–2.6 an.
  2. Stufe B (quantitativ): Für Split/Outbound auf Bestand delegiert die Schicht an stock-reservation.availability (CN1) — keine doppelte Reserved-Amount-Logik.

Gatekeeper-Modus (Create-Pfade): Stufe A und ggf. B in derselben Transaktion; überlebende Kandidaten werden über stock/unit FOR UPDATE gesperrt. Außerhalb von Transaktionen (Strategie-Vorfilter, UI) ist das Ergebnis ein beratender Snapshot.

3. Vorbedingungen für das Ausführen

BedingungEbeneStatus
state = initalleimplementiert
ready_from IS NOT NULLalleZielbild — Spalte vorhanden; Prüflogik folgt
Composition-Reihenfolge: vorherige Schritte der Gruppe ausgeführtsplit/xfer/outboundimplementiert (execute-reservation-with-composition!)
Bestand nicht gesperrt (locking_reason_id)stock outboundimplementiert
Inventur bei pending split/outbound: nur Mengenänderung, neue Menge ≥ reservierte Mengestock inventoryimplementiert (can-finish-inventory?)

4. Nachbedingungen beim Ausführen

4.1 Bestand

TypNach Ausführung (state = done)
xferBestand am Zielstandort; ggf. Merge; Composition-Kette auf neuen Bestand umgehängt.
splitQuellbestand reduziert; neue Bestände angelegt; nachfolgende Composition-Schritte auf letzten Split-Bestand.
outboundBestand entnommen oder (Miete) umgebucht; stock_outbound_shipping_advice wird bei Unit-Outbound-Ausführung für enthaltene Bestände geschrieben.
inventoryBestandsattribute/Menge aktualisiert; bei Menge 0 Bestand gelöscht.
lockstock.locking_reason_id gesetzt.
destroyBestand archiviert (archived gesetzt).

4.2 Ladeeinheit

TypNach Ausführung
xferUnit am Zielstandort; verschachtelte Inhalte bewegen mit.
outboundUnit und Inhalt ausgelagert; unit_outbound_shipping_advice rekursiv für enthaltene Units; pro enthaltenem Bestand stock_outbound_shipping_advice.
inventoryUnit-Attribute aktualisiert.
lockunit.locking_reason_id gesetzt; Inhalt rekursiv gesperrt (unit und stock.locking_reason_id).
destroyUnit und Inhalt rekursiv archiviert/entsorgt.

5. Nachbedingungen beim Stornieren

Stornieren setzt state = cancelled (nur aus init).

TypVerhalten
split, xfer, outboundGesamte Composition wird storniert (alle pending Schritte der Gruppe).
inventory, lock, destroyNur die einzelne Reservation wird storniert.

Keine Seiteneffekte auf Bestand/Unit — es wurden noch keine physischen Änderungen vorgenommen.

6. Verfügbare Menge (Bestand)

available_amount = stock.amount − Σ(reservierte Mengen aller Gruppen)

Pro Gruppe (Composition oder isoliert): Governing Reservation nach Priorität outbound > split > xfer > lock/inventory/destroy. Bei pending lock, inventory oder destroy auf demselben Bestand: available = 0.

Single source of truth: werner-backend.domain.stock-reservation.availability.

7. Referenzen

ThemaQuelle
Constraint-Implementierung Bestandwerner-backend/.../stock_reservation/constraints.clj
Constraint-Implementierung Ladeeinheit (gleiche Unit)werner-backend/.../unit_reservation/constraints.clj
Hierarchie + Batch-Feasibilitywerner-backend/.../reservation/feasibility.clj, .../reservation/rules.clj
Verfügbare Mengewerner-backend/.../stock_reservation/availability.clj
Composition-Ausführungwerner-backend/.../stock_reservation/executor.clj, .../unit_reservation/executor.clj
Unit-Reservationenwerner-backend/.../unit_reservation/
Agent-Regel (Pflichtlektüre bei Änderungen)werner/.cursor/rules/reservation-reference.mdc
Konsistenz-Axiome Bestandwerner/.cursor/rules/stock-reservation-consistency.mdc
Previous
Manueller Adressimport (CSV)