DEV-Ist-Stand fuer Phase 1 dokumentiert
This commit is contained in:
@@ -0,0 +1,501 @@
|
||||
# Phase 1: DEV-Ist-Stand Tabellen- und Prozesskonzept
|
||||
Stand: 2026-06-02
|
||||
Status: Verbindlicher DEV-Ist-Stand fuer Phase 1
|
||||
|
||||
## 1. Uebersicht
|
||||
|
||||
Dieses Dokument beschreibt die technische Wahrheit des aktuellen DEV-Standes auf Basis von:
|
||||
|
||||
- `docs/CONCEPT.md`
|
||||
- `docs/SCHEMA_PHASE1.sql`
|
||||
- `docs/PROCESS_PHASE1.md`
|
||||
- `db/migrations/0001_phase1_core.sql` bis `db/migrations/0006_phase1_otc_products.sql`
|
||||
- `order-import.php`
|
||||
- `n8n/exports/current/*.json`
|
||||
|
||||
Wichtige Einordnung:
|
||||
|
||||
- `SCHEMA_PHASE1.sql` bleibt ein Draft und ist nicht identisch mit der live DB.
|
||||
- Die live DB hat 18 Base Tables und 1 View.
|
||||
- Die Forecast-Erweiterung aus `0003_phase1_inventory_forecast.sql` ist im live Schema nicht aktiv.
|
||||
- Die Doku unten trennt deshalb zwischen implementiertem Ist-Stand und nicht gefundenen Zielbild-Teilen.
|
||||
|
||||
Tabellen:
|
||||
|
||||
- `party`
|
||||
- `address`
|
||||
- `contact`
|
||||
- `product`
|
||||
- `sellable_item`
|
||||
- `external_item_alias`
|
||||
- `sellable_item_component`
|
||||
- `warehouse`
|
||||
- `location`
|
||||
- `stock_lot`
|
||||
- `payment_method`
|
||||
- `shipping_method`
|
||||
- `sales_order`
|
||||
- `sales_order_line`
|
||||
- `stock_move`
|
||||
- `sales_order_line_lot_allocation`
|
||||
- `audit_log`
|
||||
- `outbound_webhook_event`
|
||||
|
||||
View:
|
||||
|
||||
- `v_stock_lot_balance`
|
||||
|
||||
Prozesse:
|
||||
|
||||
- `n8n.bestell-eingang-online-shop`
|
||||
- `order-import.php`
|
||||
- `db.trigger.sales_order`
|
||||
- `db.trigger.sales_order_line`
|
||||
- `db.trigger.stock_move`
|
||||
- `db.trigger.product`
|
||||
- `n8n.adressetikette-erstellen`
|
||||
- Outbox-Ablage ueber `outbound_webhook_event`
|
||||
|
||||
## 2. Zweck
|
||||
|
||||
Dieses Dokument beschreibt die aktuelle DB- und Prozesswahrheit fuer Phase 1 auf dem DEV-Stand.
|
||||
|
||||
Es ist eine technische Uebersicht fuer Analyse, Umsetzung und Review.
|
||||
|
||||
Nicht Bestandteil dieses Dokuments sind:
|
||||
|
||||
- API-Details
|
||||
- UI-Details
|
||||
- Migrations-Rollout-Planung
|
||||
- offene Zielbilddiskussionen ausserhalb des aktuellen DEV-Standes
|
||||
|
||||
## 3. Normatives Datenmodell
|
||||
|
||||
### 3.1 `party`
|
||||
|
||||
Zweck:
|
||||
|
||||
- gemeinsamer Kontaktstamm fuer Kunden und Lieferanten
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `type` ist `customer`, `supplier` oder `both`
|
||||
- `status` ist `active` oder `inactive`
|
||||
- `email` wird fuer Match/Upsert genutzt
|
||||
|
||||
### 3.2 `address`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Rechnungs- und Lieferadressen pro `party`
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `type` ist `billing` oder `shipping`
|
||||
- `raw_payload` speichert die Rohdaten des Eingangsdokuments
|
||||
|
||||
### 3.3 `contact`
|
||||
|
||||
Zweck:
|
||||
|
||||
- zusaetzliche Ansprechpartnerdaten pro `party`
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- keine weitere Prozesslogik im Code gefunden
|
||||
|
||||
### 3.4 `product`
|
||||
|
||||
Zweck:
|
||||
|
||||
- lagergefuehrtes Produkt mit Bestand und Charge
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `sku` ist eindeutig
|
||||
- beim Insert erzeugt der Trigger `trg_product_bootstrap_lots` sofort eine `current`- und eine `open`-Charge
|
||||
|
||||
### 3.5 `sellable_item`
|
||||
|
||||
Zweck:
|
||||
|
||||
- verkaufbarer Shop-Artikel
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- Bestellungen referenzieren zuerst `sellable_item`
|
||||
- der Import kann neue `sellable_item`-Datensaetze automatisch erzeugen
|
||||
|
||||
### 3.6 `external_item_alias`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Mapping externer Shop-Daten auf `sellable_item`
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `source_system = 'wix'`
|
||||
- Aufloesung ueber Artikelnummer, normalisierten Titel oder Originaltitel
|
||||
|
||||
### 3.7 `sellable_item_component`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Stueckliste eines `sellable_item` auf lagergefuehrte Produkte
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `qty_per_item > 0`
|
||||
- wird vom Import und von Seed-Skripten gepflegt
|
||||
|
||||
### 3.8 `warehouse`
|
||||
|
||||
Zweck:
|
||||
|
||||
- oberer Lagerstandort
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- im Seed ist ein Hauptlager vorgesehen
|
||||
|
||||
### 3.9 `location`
|
||||
|
||||
Zweck:
|
||||
|
||||
- konkreter Lagerort innerhalb eines `warehouse`
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `type` ist `storage`, `receiving`, `dispatch` oder `adjustment`
|
||||
|
||||
### 3.10 `stock_lot`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Charge eines Produkts
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `status` ist `open`, `current` oder `closed`
|
||||
- pro Produkt sind `current` und `open` per Unique Index abgesichert
|
||||
- die live DB hat keine `sellout_date`- oder `warning_state`-Spalten
|
||||
- die Sicht `v_stock_lot_balance` ist die Bestandswahrheit
|
||||
|
||||
### 3.11 `payment_method`
|
||||
|
||||
Zweck:
|
||||
|
||||
- normalisierte Zahlungsart
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- Seed-Werte im DEV: `card`, `twint`, `bank_transfer`, `cash`, `paypal`
|
||||
|
||||
### 3.12 `shipping_method`
|
||||
|
||||
Zweck:
|
||||
|
||||
- normalisierte Versandart
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- Seed-Werte im DEV: `post_standard`, `pickup`
|
||||
|
||||
### 3.13 `sales_order`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Bestellkopf fuer Online-Import und Direktverkauf
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `external_ref` ist eindeutig
|
||||
- `order_source` ist `wix` oder `direct`
|
||||
- `party_id` ist nullable
|
||||
- `payment_status` ist faktisch auf `paid` beschraenkt
|
||||
- `shipping_date` existiert im live Schema und wird per Trigger berechnet, falls leer
|
||||
|
||||
### 3.14 `sales_order_line`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Bestellposition
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `qty_cancelled` und `line_status` werden per Trigger synchronisiert
|
||||
- `sellable_item_id` kann `NULL` sein
|
||||
|
||||
### 3.15 `stock_move`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Bewegungsjournal fuer Zu- und Abgaenge
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `move_type` ist `in`, `out`, `transfer` oder `adjustment`
|
||||
- Bewegungen werden vor Insert/Update gegen Negativbestand validiert
|
||||
|
||||
### 3.16 `sales_order_line_lot_allocation`
|
||||
|
||||
Zweck:
|
||||
|
||||
- explizite Rueckverfolgung zwischen Bestellposition und Charge
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- `allocation_status` ist `reserved`, `allocated`, `released` oder `cancelled`
|
||||
- im Import wird `allocated` verwendet
|
||||
|
||||
### 3.17 `audit_log`
|
||||
|
||||
Zweck:
|
||||
|
||||
- technische Historisierung
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- im Schema vorhanden
|
||||
- im geprüften PHP- und n8n-Flow nicht als zentraler Pflichtpfad sichtbar
|
||||
|
||||
### 3.18 `outbound_webhook_event`
|
||||
|
||||
Zweck:
|
||||
|
||||
- Outbox fuer ERP-Events
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- Spalten: `event_type`, `event_key`, `aggregate_type`, `aggregate_id`, `payload`, `status`, `attempt_count`, `next_attempt_at`, `last_attempt_at`, `last_error`, `created_at`, `sent_at`
|
||||
- `fn_enqueue_event(...)` schreibt idempotent in diese Tabelle
|
||||
- ein Dispatcher/Worker fuer die Auslieferung wurde im geprüften DEV-Baum nicht gefunden
|
||||
|
||||
### 3.19 `v_stock_lot_balance`
|
||||
|
||||
Zweck:
|
||||
|
||||
- berechneter Chargensaldo
|
||||
|
||||
Ist-Stand:
|
||||
|
||||
- die Sicht ermittelt `qty_in`, `qty_out` und `qty_net`
|
||||
- sie ist die Grundlage fuer Bestandspruefung und Auto-Switch
|
||||
|
||||
## 4. Normatives Prozessmodell
|
||||
|
||||
Alle Prozesse gehoeren fachlich zur Phase-1-Bestell-, Lager- und Integrationslogik.
|
||||
|
||||
### 4.1 `n8n.bestell-eingang-online-shop`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- E-Mail auf `Neue Bestellung` erkennen
|
||||
- Payload in ERP-JSON umformen
|
||||
- JSON per HTTP POST an `order-import.php` senden
|
||||
|
||||
Liest:
|
||||
|
||||
- IMAP-Eingang
|
||||
- n8n-Extraktionslogik
|
||||
|
||||
Schreibt:
|
||||
|
||||
- keine DB direkt
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- n8n ist hier nur die Integrationshuelle fuer den ERP-Import
|
||||
|
||||
### 4.2 `order-import.php`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- eingehende Bestelldaten idempotent in die ERP-DB schreiben
|
||||
- Kontakte, Adressen, Bestellkopf, Positionen und Chargenrueckverfolgung aufbauen
|
||||
- bei Reimport vorhandene Allokationen zurueckbuchen
|
||||
- nach Commit die Label- und Excel-Flows direkt anstossen
|
||||
|
||||
Liest:
|
||||
|
||||
- `.env`
|
||||
- eingehendes Webhook-JSON
|
||||
- `party`, `address`, `sales_order`, `sales_order_line`
|
||||
- `external_item_alias`
|
||||
- `sellable_item_component`
|
||||
- `stock_lot`
|
||||
- `v_stock_lot_balance`
|
||||
|
||||
Schreibt:
|
||||
|
||||
- `party`
|
||||
- `address`
|
||||
- `sales_order`
|
||||
- `sales_order_line`
|
||||
- `sellable_item`
|
||||
- `external_item_alias`
|
||||
- `sellable_item_component`
|
||||
- `warehouse`
|
||||
- `location`
|
||||
- `stock_lot`
|
||||
- `stock_move`
|
||||
- `sales_order_line_lot_allocation`
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- die Bestellung wird im ERP gespeichert und mit Lagerbewegung verknuepft
|
||||
- vorhandene Allokationen derselben `external_ref` werden vor dem Neuimport rueckwaerts gebucht
|
||||
- nach erfolgreichem Commit werden Label- und Excel-N8N-Flows direkt per HTTP ausgelöst
|
||||
|
||||
### 4.3 `db.trigger.sales_order`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- `shipping_date` aus `order_date` ableiten
|
||||
- `order.imported` und `order.cancelled.full` in die Outbox schreiben
|
||||
- `direct`-Bestellungen automatisch mit `DIR-...` Nummer versehen
|
||||
|
||||
Liest:
|
||||
|
||||
- `sales_order`
|
||||
- `fn_next_business_day(timestamp)`
|
||||
|
||||
Schreibt:
|
||||
|
||||
- `sales_order.shipping_date`
|
||||
- `outbound_webhook_event`
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- fehlendes `shipping_date` wird auf den naechsten Werktag gesetzt
|
||||
- neue Auftraege und Vollstornos werden als Event in die Outbox gelegt
|
||||
- direkte Auftraege erhalten bei leerer Nummer automatisch einen `DIR-...`-Ref
|
||||
|
||||
### 4.4 `db.trigger.sales_order_line`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- `line_status` aus `qty_cancelled` ableiten
|
||||
- Partial-Cancel-Event enqueuen
|
||||
|
||||
Liest:
|
||||
|
||||
- `sales_order_line`
|
||||
|
||||
Schreibt:
|
||||
|
||||
- `sales_order_line.line_status`
|
||||
- `outbound_webhook_event`
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- `allocated`, `partially_cancelled` und `cancelled` werden deterministisch gesetzt
|
||||
- ein Wechsel auf `partially_cancelled` erzeugt ein `order.cancelled.partial`-Event
|
||||
|
||||
### 4.5 `db.trigger.stock_move`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- Negativbestand verhindern
|
||||
- Chargenwechsel bei leerer `current`-Charge ausloesen
|
||||
|
||||
Liest:
|
||||
|
||||
- `stock_move`
|
||||
- `stock_lot`
|
||||
- `v_stock_lot_balance`
|
||||
|
||||
Schreibt:
|
||||
|
||||
- `stock_lot`
|
||||
- `outbound_webhook_event`
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- `out`-Bewegungen sind nur auf `current`-Chargen erlaubt
|
||||
- bei `qty_net <= 0` wird die naechste `open`-Charge `current`
|
||||
- danach wird wieder eine neue `open`-Charge angelegt
|
||||
|
||||
### 4.6 `db.trigger.product`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- neue Produkte sofort chargenfaehig machen
|
||||
|
||||
Liest:
|
||||
|
||||
- `product`
|
||||
|
||||
Schreibt:
|
||||
|
||||
- `stock_lot`
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- jedes neue Produkt bekommt direkt eine `current`- und eine `open`-Charge
|
||||
|
||||
### 4.7 `n8n.adressetikette-erstellen`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- Lieferadresse entgegennehmen
|
||||
- Felder normalisieren
|
||||
- HTML/CSS in PDF/PNG umsetzen
|
||||
- Ergebnis per SFTP hochladen
|
||||
|
||||
Liest:
|
||||
|
||||
- Webhook-Input
|
||||
- Gotenberg / pdf2png / SFTP-Ziele
|
||||
|
||||
Schreibt:
|
||||
|
||||
- keine ERP-DB
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- eigenstaendiger Ausgabekanal fuer Versandetiketten
|
||||
|
||||
### 4.8 Outbox-Ablage ueber `outbound_webhook_event`
|
||||
|
||||
Fachliche Aufgabe:
|
||||
|
||||
- Eventdaten fuer spaetere Auslieferung sammeln
|
||||
|
||||
Liest:
|
||||
|
||||
- `fn_enqueue_event`
|
||||
|
||||
Schreibt:
|
||||
|
||||
- `outbound_webhook_event`
|
||||
|
||||
Fachliche Wirkung:
|
||||
|
||||
- Queue wird im geprüften DEV-Stand befuellt
|
||||
- ein dazugehoeriger Dispatcher/Worker wurde im Code nicht gefunden
|
||||
|
||||
## 5. Technische Einbettung
|
||||
|
||||
Die reale Phase-1-Logik bildet einen kleinen operativen Kern mit vier Schwerpunkten:
|
||||
|
||||
1. Kontakt- und Adressstamm
|
||||
2. Bestellimport via n8n -> PHP -> DB
|
||||
3. Chargen- und Lagerbewegung mit Trigger-Logik
|
||||
4. Label-Generierung als separater n8n-Ausgang
|
||||
|
||||
Wichtige Abweichungen zum alten Zielbild:
|
||||
|
||||
- Sellout-Forecast ist im live Schema nicht aktiv.
|
||||
- Ein Dispatcher fuer `outbound_webhook_event` wurde im geprüften DEV-Baum nicht gefunden.
|
||||
- Eine separate Direct-Sale-Eingabestrecke wurde im geprüften DEV-Baum nicht gefunden; vorhanden ist nur die DB-/Trigger-Unterstuetzung fuer `order_source = direct`.
|
||||
|
||||
## 6. Kurzfazit
|
||||
|
||||
Die aktuelle technische Wahrheit von Phase 1 ist auf Nachvollziehbarkeit und direkte Integrationspfade ausgerichtet:
|
||||
|
||||
- Bestellungen werden idempotent gespeichert
|
||||
- Lagerbestand wird ueber Chargen und Bewegungen abgebildet
|
||||
- Rueckverfolgung erfolgt ueber explizite Allokationen
|
||||
- n8n importiert und erzeugt Labels direkt
|
||||
- Outbox-Events werden geschrieben, aber ein Dispatcher ist im geprüften DEV-Stand nicht vorhanden
|
||||
Reference in New Issue
Block a user