265 lines
8.9 KiB
Markdown
265 lines
8.9 KiB
Markdown
# Phase 1 Component Specification
|
|
|
|
## Dokumentstatus
|
|
|
|
1. Typ: `operational`
|
|
2. Zweck: verbindliche Umsetzungs-Spezifikation fuer Schritt 1 Komponenten
|
|
3. Normative Referenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/CONCEPT.md`
|
|
4. Abgeleitete Referenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/SCHEMA_PHASE1.sql`
|
|
5. Prozessreferenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/PROCESS_PHASE1.md`
|
|
6. Implementierungsreferenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/db/migrations/`
|
|
|
|
## Scope
|
|
|
|
Diese Spezifikation deckt alle Schritt-1-Komponenten ab:
|
|
|
|
1. Bestellerfassung
|
|
2. Kontakt- und Adressdaten
|
|
3. Artikel-Mapping und Stuecklisten
|
|
4. Lagerverwaltung mit Chargen, MHD, Zu-/Abgaengen
|
|
5. Chargenrueckverfolgung
|
|
6. Teil-/Vollstorno
|
|
7. Inbound/Outbound Webhooks
|
|
8. Audit und technische Guardrails
|
|
|
|
## Globale Invarianten
|
|
|
|
1. `sales_order.external_ref` ist eindeutig und dient als Upsert-Schluessel (Shop: `BestellungNr`, Direktverkauf: `DIR-...`).
|
|
2. Datensaetze werden nicht geloescht; Statusaenderungen und Audit-Trail werden verwendet.
|
|
3. Verkaufsbewegungen sind immer chargengebunden.
|
|
4. Negativbestand ist unzulaessig.
|
|
5. Pro Produkt existieren exakt eine `current`-Charge und eine `open`-Charge.
|
|
6. `open` darf nie fehlen.
|
|
7. Zahlungsstatus aus Shop wird intern auf `paid` normalisiert.
|
|
8. Direktverkaeufe haben `order_source = direct` und `external_ref` mit `DIR-`-Praefix.
|
|
|
|
## Komponente 1: Bestellerfassung
|
|
|
|
### Ziel
|
|
|
|
Persistente Erfassung von Bestellungen aus Shop und Direktverkauf inkl. Positionen, Summen und Import-/Erfassungsdaten.
|
|
|
|
### Eingangsquelle
|
|
|
|
1. n8n Inbound Webhook mit Shop-JSON (`order_source = wix`)
|
|
2. Manuelle ERP-Erfassung fuer Direktverkauf (`order_source = direct`)
|
|
|
|
### Datenregeln
|
|
|
|
1. Upsert auf `sales_order.external_ref` fuer Shop-Bestellungen.
|
|
2. Direktbestellungen erhalten ERP-interne Nummern mit `DIR-`-Praefix.
|
|
3. `order_status` initial `imported`.
|
|
4. Summenfelder werden direkt gespeichert (`amount_net`, `amount_shipping`, `amount_tax`, `amount_discount`, `total_amount`).
|
|
5. `webhook_payload` wird fuer Shop-Rohdaten gespeichert (Nachvollziehbarkeit).
|
|
6. Fuer Direktverkauf darf `party_id` leer sein (Laufkundschaft).
|
|
|
|
### Fehlerverhalten
|
|
|
|
1. Bei fehlender `BestellungNr`: Import ablehnen, Audit-Log `import_rejected`.
|
|
2. Bei unbekanntem Artikelfehler: Bestellung speichern, Position mit Rohdaten speichern, Mapping-Luecke markieren.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Wiederholter Import derselben `BestellungNr` erzeugt kein Duplikat.
|
|
2. Direktbestellungen sind ueber den `DIR-`-Praefix eindeutig erkennbar.
|
|
3. Positionsdaten bleiben stabil und auditierbar.
|
|
|
|
## Komponente 2: Kontakt- und Adressdaten
|
|
|
|
### Ziel
|
|
|
|
Speicherung von Kundenkontakt, Lieferadresse und optionaler Rechnungsadresse.
|
|
|
|
### Datenregeln
|
|
|
|
1. Rechnungsadresse darf vollstaendig `NULL` sein.
|
|
2. Lieferadresse wird als eigener Datensatz gespeichert.
|
|
3. Land wird immer doppelt gespeichert: `country_name` + `country_iso2`.
|
|
4. Keine serverseitige Adressvalidierung in Phase 1.
|
|
5. Ausnahmefaelle bei Name/Firma werden unveraendert uebernommen.
|
|
6. Bei Direktverkauf ist keine Kontakt-/Adressanlage erforderlich.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Bestellung kann ohne Rechnungsadresse gespeichert werden.
|
|
2. Liefer- und Rechnungsadresse sind getrennt auswertbar.
|
|
|
|
## Komponente 3: Artikel-Mapping und Stuecklisten
|
|
|
|
### Ziel
|
|
|
|
Stabile Entkopplung von Shop-Artikeln und lagergefuehrten Produkten.
|
|
|
|
### Datenmodell
|
|
|
|
1. `sellable_item`: verkaufbarer Artikel (auch Bundles).
|
|
2. `external_item_alias`: Mapping Shop-Artikelnummer/Titel -> `sellable_item`.
|
|
3. `sellable_item_component`: Stueckliste `sellable_item` -> `product` mit Menge.
|
|
|
|
### Aufloesungsreihenfolge
|
|
|
|
1. Match ueber `external_article_number`.
|
|
2. Fallback ueber normalisierten Titel.
|
|
3. Wenn beides fehlschlaegt: Position als unmapped speichern und auditieren.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Bundle-Artikel koennen auf mehrere Lagerprodukte aufgeloest werden.
|
|
2. Ohne Mapping bleibt Bestellung dennoch erfassbar.
|
|
|
|
## Komponente 4: Lagerverwaltung und Chargen
|
|
|
|
### Ziel
|
|
|
|
Konsistente Bestandsfuehrung je Charge inklusive Auto-Wechsel.
|
|
|
|
### Statusmodell Charge
|
|
|
|
1. `open`: vorbereitete Charge
|
|
2. `current`: aktive Entnahmecharge
|
|
3. `closed`: abgeschlossene Charge
|
|
|
|
### Lebenszyklus
|
|
|
|
1. `open -> current -> closed`
|
|
2. Wenn `current` auf `qty_net <= 0` faellt:
|
|
1. alte `current` wird `closed`
|
|
2. vorhandene `open` wird `current`
|
|
3. neue `open` wird auto-angelegt
|
|
|
|
### Feldregeln
|
|
|
|
1. `lot_number` bei `open` darf leer sein.
|
|
2. `lot_number` fuer `current/closed` ist Pflicht.
|
|
3. Chargennummer ist pro Produkt eindeutig.
|
|
4. Chargensalden werden aus `stock_move` berechnet (`v_stock_lot_balance`).
|
|
5. Abverkaufprognose pro aktueller Charge wird im System gepflegt (`sellout_date`, `warning_state`).
|
|
|
|
### Korrekturregeln
|
|
|
|
1. Korrekturen erfolgen ueber `adjustment`-Bewegungen.
|
|
2. Keine direkten Netto-Setzungen als Betriebsprozess.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Nach jeder Entnahme bleibt die Invariante `1x current + 1x open` erhalten.
|
|
2. Negativbestand wird technisch verhindert.
|
|
3. Warnstatus fuer UI ist ohne E-Mail nutzbar (`none`, `due_60d`, `due_now`).
|
|
|
|
## Komponente 5: Chargenrueckverfolgung
|
|
|
|
### Ziel
|
|
|
|
Lueckenlose Rueckverfolgung Bestellung -> Position -> Produkt -> Charge -> Lagerbewegung.
|
|
|
|
### Datenregeln
|
|
|
|
1. Jede Entnahme schreibt `stock_move` (`move_type = out`) mit `lot_id`.
|
|
2. Pro Entnahme wird `sales_order_line_lot_allocation` geschrieben.
|
|
3. `allocation_status` in Phase 1 standardmaessig `allocated`.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Fuer jede ausgelieferte Position ist die verwendete Charge abfragbar.
|
|
2. Rueckverfolgung funktioniert auch nach Teilstorno.
|
|
|
|
## Komponente 6: Storno (Teil/Voll)
|
|
|
|
### Ziel
|
|
|
|
Revisionssicheres Storno ohne physisches Loeschen.
|
|
|
|
### Datenregeln
|
|
|
|
1. Teil- und Vollstorno sind erlaubt.
|
|
2. `sales_order_line.qty_cancelled` wird fortgeschrieben.
|
|
3. `line_status`: `allocated`, `partially_cancelled`, `cancelled`.
|
|
4. Bei Storno von bereits `allocated` Mengen erfolgt Gegenbuchung als `adjustment in` auf dieselbe Charge.
|
|
5. Bestellung bleibt erhalten; Statuswechsel statt Delete.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Historische Ursprungs- und Korrekturbewegungen bleiben sichtbar.
|
|
2. Vollstorno setzt `sales_order.order_status = cancelled`.
|
|
|
|
## Komponente 7: Webhooks
|
|
|
|
### Inbound (n8n -> ERP)
|
|
|
|
1. Transport: JSON via HTTP.
|
|
2. Idempotenzschluessel: `BestellungNr`.
|
|
3. Verarbeitung: Upsert Bestellung, Kontakt, Positionen, Lagerabgang, Audit.
|
|
4. Quelle wird als `order_source = wix` gespeichert.
|
|
|
|
### Direkt (ERP intern)
|
|
|
|
1. Transport: manuelle Erfassung in ERP-Maske.
|
|
2. Nummernlogik: ERP erzeugt `external_ref` mit `DIR-`-Praefix.
|
|
3. Verarbeitung: Bestellung (optional ohne Kontakt), Positionen, Lagerabgang, Audit.
|
|
|
|
### Outbound (ERP -> n8n)
|
|
|
|
1. Transport: Queue-basierter POST ueber `outbound_webhook_event`.
|
|
2. Events Phase 1:
|
|
1. `order.imported`
|
|
2. `order.cancelled.partial`
|
|
3. `order.cancelled.full`
|
|
4. `lot.auto_switched`
|
|
3. Signatur: `X-ERP-Signature` (HMAC-SHA256).
|
|
4. Zustellung: Retry mit Backoff; final `dead_letter`.
|
|
|
|
### Akzeptanzkriterien
|
|
|
|
1. Event-Zustellung ist idempotent (`event_key` eindeutig).
|
|
2. Fehlgeschlagene Events sind operativ auffindbar.
|
|
3. Outbound-Payload enthaelt die Quelle (`order_source`), damit `wix` und `direct` getrennt auswertbar sind.
|
|
|
|
## Komponente 8: Audit und Betriebssicherheit
|
|
|
|
### Audit
|
|
|
|
1. Jede fachliche Aenderung schreibt `audit_log`.
|
|
2. Pflichtfelder: `entity_name`, `entity_id`, `action`, `changed_at`.
|
|
3. Vorher/Nachher-Daten werden als JSON gespeichert, wenn verfuegbar.
|
|
|
|
### Guardrails
|
|
|
|
1. Check-Constraints fuer Statuswerte.
|
|
2. Check-Constraints fuer Mengenbereiche.
|
|
3. Unique-Constraints fuer kritische Eindeutigkeiten.
|
|
4. Outbox-Statusmaschine fuer robuste externe Zustellung.
|
|
|
|
## Komponenten-Matrix
|
|
|
|
1. `Bestellerfassung`
|
|
Zustandsquelle: `sales_order`, `sales_order_line`
|
|
Hauptereignisse: `order.imported`, `order.cancelled.*`
|
|
2. `Kontakt/Adressen`
|
|
Zustandsquelle: `party`, `contact`, `address`
|
|
Hauptereignisse: `order.imported`
|
|
3. `Artikel-Mapping`
|
|
Zustandsquelle: `sellable_item`, `external_item_alias`, `sellable_item_component`
|
|
Hauptereignisse: `order.imported`
|
|
4. `Lagerverwaltung`
|
|
Zustandsquelle: `stock_lot`, `stock_move`, `v_stock_lot_balance`
|
|
Hauptereignisse: `order.imported`, `lot.auto_switched`, `order.cancelled.*`
|
|
5. `Rueckverfolgung`
|
|
Zustandsquelle: `sales_order_line_lot_allocation`
|
|
Hauptereignisse: alle Abgaenge und Stornos
|
|
6. `Outbound-Integration`
|
|
Zustandsquelle: `outbound_webhook_event`
|
|
Hauptereignisse: alle publizierten Domain-Events
|
|
|
|
## Nicht in Phase 1
|
|
|
|
1. Rechnungswesen, Buchungssaetze, OCR-Verarbeitung.
|
|
2. Automatisierte Preis-/Steuerneuberechnung.
|
|
3. Vollautomatische Chargennummerngenerierung nach Produktklasse.
|
|
|
|
## Change Governance
|
|
|
|
1. Konzeptaenderungen zuerst in `CONCEPT.md`.
|
|
2. Prozess- und Betriebsablauf in `PROCESS_PHASE1.md`.
|
|
3. Technische Ableitung in `SCHEMA_PHASE1.sql`.
|
|
4. Diese Spezifikation synchronisiert alle Komponenten auf Umsetzungsniveau.
|