Erlaube mehrere offene Lagerchargen
This commit is contained in:
1 parent
e656841de2
commit
ca5cf5a03f
4 files changed
+23
-12
No files matched your search
@@ -15,6 +15,8 @@
|
|||||||
11. `db/migrations/0015_sales_order_payments.sql`
|
11. `db/migrations/0015_sales_order_payments.sql`
|
||||||
12. `db/migrations/0016_stock_lot_forecast_history.sql`
|
12. `db/migrations/0016_stock_lot_forecast_history.sql`
|
||||||
13. `db/migrations/0017_manufacturer_lot_traceability.sql`
|
13. `db/migrations/0017_manufacturer_lot_traceability.sql`
|
||||||
|
14. `db/migrations/0018_shopify_delta_sync_state.sql`
|
||||||
|
15. `db/migrations/0019_allow_multiple_open_stock_lots.sql`
|
||||||
|
|
||||||
## Beispielausfuehrung
|
## Beispielausfuehrung
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS uq_stock_lot_one_open_per_product;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -13,17 +13,17 @@ Direkt ausgeführter Lager-Prozess mit zwei Triggern: synchron nach jeder erfolg
|
|||||||
## 3. Input
|
## 3. Input
|
||||||
|
|
||||||
- optional eine einzelne `product_id` bei synchronem Verkaufstrigger
|
- optional eine einzelne `product_id` bei synchronem Verkaufstrigger
|
||||||
- aktive Produkte, aktuelle Chargen, eingetragene Mengen der offenen Folgecharge, physischer Chargenbestand und gültige Verkaufsallokationen aus dem eigenen Datenbestand
|
- aktive Produkte, aktuelle Chargen, eingetragene Mengen aller offenen Folgechargen, physischer Chargenbestand und gültige Verkaufsallokationen aus dem eigenen Datenbestand
|
||||||
|
|
||||||
## 4. Exakter Prozessablauf
|
## 4. Exakter Prozessablauf
|
||||||
|
|
||||||
1. Bei einem Verkaufstrigger die betroffenen Produkt-IDs aus der erfolgreichen Allokation übernehmen; beim Cron-Trigger alle aktiven Produkte bestimmen.
|
1. Bei einem Verkaufstrigger die betroffenen Produkt-IDs aus der erfolgreichen Allokation übernehmen; beim Cron-Trigger alle aktiven Produkte bestimmen.
|
||||||
2. Aktive Produkte, ihre aktuelle Charge und den Nettobestand einer bereits angelegten offenen Folgecharge aus `product`, `stock_lot` und `v_stock_lot_balance` laden. Die Menge der offenen Folgecharge wird nur berücksichtigt, wenn sie positiv ist.
|
2. Aktive Produkte, ihre aktuelle Charge und die Nettobestände aller bereits angelegten offenen Folgechargen aus `product`, `stock_lot` und `v_stock_lot_balance` laden. Je offene Folgecharge wird nur eine positive Menge berücksichtigt.
|
||||||
3. Verkaufsallokationen der letzten 365 Tage aus `sales_order_line_lot_allocation`, `sales_order_line` und `sales_order` laden.
|
3. Verkaufsallokationen der letzten 365 Tage aus `sales_order_line_lot_allocation`, `sales_order_line` und `sales_order` laden.
|
||||||
4. `allocated`- und `reserved`-Mengen nach Bestell- beziehungsweise OTC-Verkaufsdatum je Produkt und Kalendertag aggregieren.
|
4. `allocated`- und `reserved`-Mengen nach Bestell- beziehungsweise OTC-Verkaufsdatum je Produkt und Kalendertag aggregieren.
|
||||||
5. Stornierte Auftrags- und Positionsmengen aus der Nachfrage herausrechnen.
|
5. Stornierte Auftrags- und Positionsmengen aus der Nachfrage herausrechnen.
|
||||||
6. Den gewichteten Tagesabsatz mit einer Halbwertszeit von 60 Tagen berechnen.
|
6. Den gewichteten Tagesabsatz mit einer Halbwertszeit von 60 Tagen berechnen.
|
||||||
7. Für jede aktuelle Charge das Leer-Datum aus ihrem physischen Bestand zuzüglich der eingetragenen Menge der offenen Folgecharge und der gewichteten Nachfrage berechnen.
|
7. Für jede aktuelle Charge das Leer-Datum aus ihrem physischen Bestand zuzüglich der eingetragenen Mengen aller offenen Folgechargen und der gewichteten Nachfrage berechnen.
|
||||||
8. Jede erfolgreiche Berechnung in `stock_lot_forecast_history` speichern und den aktuellen Snapshot in `stock_lot` aktualisieren.
|
8. Jede erfolgreiche Berechnung in `stock_lot_forecast_history` speichern und den aktuellen Snapshot in `stock_lot` aktualisieren.
|
||||||
9. Im Cron Fehler einzelner Produkte sammeln und mit den übrigen Produkten fortfahren.
|
9. Im Cron Fehler einzelner Produkte sammeln und mit den übrigen Produkten fortfahren.
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ Ein normalisiertes JSON-Ergebnis mit Gesamtzahl, erfolgreich verarbeiteten Produ
|
|||||||
|
|
||||||
## 7. Erfolgskriterien
|
## 7. Erfolgskriterien
|
||||||
|
|
||||||
- Jede aktuelle Charge erhält täglich einen aktuellen Prognosesnapshot, der eine eingetragene Menge der offenen Folgecharge berücksichtigt.
|
- Jede aktuelle Charge erhält täglich einen aktuellen Prognosesnapshot, der eingetragene Mengen aller offenen Folgechargen berücksichtigt.
|
||||||
- Verkäufe ohne Bestand über virtuelle `reserved`-Allokationen beeinflussen die Nachfrage.
|
- Verkäufe ohne Bestand über virtuelle `reserved`-Allokationen beeinflussen die Nachfrage.
|
||||||
- Die vollständige Berechnungshistorie bleibt erhalten.
|
- Die vollständige Berechnungshistorie bleibt erhalten.
|
||||||
- Ein einzelner Produktfehler verhindert keine weiteren Berechnungen.
|
- Ein einzelner Produktfehler verhindert keine weiteren Berechnungen.
|
||||||
|
|||||||
@@ -35,13 +35,15 @@ function lager_forecast_load_current_lots(PDO $pdo): array
|
|||||||
{
|
{
|
||||||
$stmt = $pdo->query(
|
$stmt = $pdo->query(
|
||||||
"SELECT p.id AS product_id, p.sku, sl.id AS lot_id,
|
"SELECT p.id AS product_id, p.sku, sl.id AS lot_id,
|
||||||
COALESCE(v.qty_net, 0) + GREATEST(COALESCE(open_v.qty_net, 0), 0) AS physical_qty
|
COALESCE(v.qty_net, 0) + COALESCE((
|
||||||
|
SELECT SUM(GREATEST(COALESCE(open_v.qty_net, 0), 0))
|
||||||
|
FROM stock_lot open_lot
|
||||||
|
LEFT JOIN v_stock_lot_balance open_v ON open_v.stock_lot_id = open_lot.id
|
||||||
|
WHERE open_lot.product_id = p.id AND open_lot.status = 'open'
|
||||||
|
), 0) AS physical_qty
|
||||||
FROM product p
|
FROM product p
|
||||||
LEFT JOIN stock_lot sl ON sl.product_id = p.id AND sl.status = 'current'
|
LEFT JOIN stock_lot sl ON sl.product_id = p.id AND sl.status = 'current'
|
||||||
LEFT JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
LEFT JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
||||||
LEFT JOIN stock_lot open_lot
|
|
||||||
ON open_lot.product_id = p.id AND open_lot.status = 'open'
|
|
||||||
LEFT JOIN v_stock_lot_balance open_v ON open_v.stock_lot_id = open_lot.id
|
|
||||||
WHERE p.status = 'active'
|
WHERE p.status = 'active'
|
||||||
ORDER BY p.id"
|
ORDER BY p.id"
|
||||||
);
|
);
|
||||||
@@ -52,13 +54,15 @@ function lager_forecast_load_current_lot(PDO $pdo, int $productId): ?array
|
|||||||
{
|
{
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT p.id AS product_id, p.sku, sl.id AS lot_id,
|
"SELECT p.id AS product_id, p.sku, sl.id AS lot_id,
|
||||||
COALESCE(v.qty_net, 0) + GREATEST(COALESCE(open_v.qty_net, 0), 0) AS physical_qty
|
COALESCE(v.qty_net, 0) + COALESCE((
|
||||||
|
SELECT SUM(GREATEST(COALESCE(open_v.qty_net, 0), 0))
|
||||||
|
FROM stock_lot open_lot
|
||||||
|
LEFT JOIN v_stock_lot_balance open_v ON open_v.stock_lot_id = open_lot.id
|
||||||
|
WHERE open_lot.product_id = p.id AND open_lot.status = 'open'
|
||||||
|
), 0) AS physical_qty
|
||||||
FROM product p
|
FROM product p
|
||||||
LEFT JOIN stock_lot sl ON sl.product_id = p.id AND sl.status = 'current'
|
LEFT JOIN stock_lot sl ON sl.product_id = p.id AND sl.status = 'current'
|
||||||
LEFT JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
LEFT JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
||||||
LEFT JOIN stock_lot open_lot
|
|
||||||
ON open_lot.product_id = p.id AND open_lot.status = 'open'
|
|
||||||
LEFT JOIN v_stock_lot_balance open_v ON open_v.stock_lot_id = open_lot.id
|
|
||||||
WHERE p.status = 'active' AND p.id = :product_id
|
WHERE p.status = 'active' AND p.id = :product_id
|
||||||
LIMIT 1"
|
LIMIT 1"
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user