Split inventory forecast by current and next lot

This commit is contained in:
gitea_admin committed 2026-09-08 18:48:53 +02:00
1 parent 77f6fee5ac
commit 959586ecc9
5 files changed
+164 -59

No files matched your search

+46 -12
View File
@@ -35,15 +35,25 @@ function lager_forecast_load_current_lots(PDO $pdo): array
{
$stmt = $pdo->query(
"SELECT p.id AS product_id, p.sku, sl.id AS lot_id,
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
COALESCE(v.qty_net, 0) AS physical_qty,
next_sl.id AS next_lot_id,
COALESCE(next_v.qty_net, 0) AS next_physical_qty
FROM product p
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 stock_lot next_sl
ON next_sl.product_id = p.id
AND next_sl.status = 'open'
AND next_sl.next_active = TRUE
AND NULLIF(TRIM(next_sl.lot_number), '') IS NOT NULL
AND next_sl.manufacturer_party_id IS NOT NULL
AND NULLIF(TRIM(next_sl.manufacturer_lot_number), '') IS NOT NULL
AND next_sl.mfg_date IS NOT NULL
AND next_sl.expiry_date IS NOT NULL
AND next_sl.purchase_date IS NOT NULL
LEFT JOIN v_stock_lot_balance next_v
ON next_v.stock_lot_id = next_sl.id
AND next_v.qty_net > 0
WHERE p.status = 'active'
ORDER BY p.id"
);
@@ -54,15 +64,25 @@ function lager_forecast_load_current_lot(PDO $pdo, int $productId): ?array
{
$stmt = $pdo->prepare(
"SELECT p.id AS product_id, p.sku, sl.id AS lot_id,
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
COALESCE(v.qty_net, 0) AS physical_qty,
next_sl.id AS next_lot_id,
COALESCE(next_v.qty_net, 0) AS next_physical_qty
FROM product p
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 stock_lot next_sl
ON next_sl.product_id = p.id
AND next_sl.status = 'open'
AND next_sl.next_active = TRUE
AND NULLIF(TRIM(next_sl.lot_number), '') IS NOT NULL
AND next_sl.manufacturer_party_id IS NOT NULL
AND NULLIF(TRIM(next_sl.manufacturer_lot_number), '') IS NOT NULL
AND next_sl.mfg_date IS NOT NULL
AND next_sl.expiry_date IS NOT NULL
AND next_sl.purchase_date IS NOT NULL
LEFT JOIN v_stock_lot_balance next_v
ON next_v.stock_lot_id = next_sl.id
AND next_v.qty_net > 0
WHERE p.status = 'active' AND p.id = :product_id
LIMIT 1"
);
@@ -235,6 +255,13 @@ function refresh_lager_stock_lot_forecast_for_product(PDO $pdo, int $productId):
$dailySales[$productId] ?? []
);
lager_forecast_persist($pdo, $lot, $forecast, $asOfDate);
if ($lot['next_lot_id'] !== null) {
lager_forecast_persist($pdo, [
'lot_id' => $lot['next_lot_id'],
'product_id' => $productId,
'physical_qty' => $lot['next_physical_qty'],
], lager_forecast_calculate($asOfDate, (float) $lot['next_physical_qty'], $dailySales[$productId] ?? []), $asOfDate);
}
}
function run_lager_stock_lot_forecast(PDO $pdo): array
@@ -260,6 +287,13 @@ function run_lager_stock_lot_forecast(PDO $pdo): array
try {
$forecast = lager_forecast_calculate($asOfDate, (float) $lot['physical_qty'], $dailySales[$productId] ?? []);
lager_forecast_persist($pdo, $lot, $forecast, $asOfDate);
if ($lot['next_lot_id'] !== null) {
lager_forecast_persist($pdo, [
'lot_id' => $lot['next_lot_id'],
'product_id' => $productId,
'physical_qty' => $lot['next_physical_qty'],
], lager_forecast_calculate($asOfDate, (float) $lot['next_physical_qty'], $dailySales[$productId] ?? []), $asOfDate);
}
$result['processed_products']++;
} catch (Throwable $error) {
$result['failed_products']++;