| Version 1 (modified by , 5 days ago) ( diff ) |
|---|
Прогноза за потрошувачка на состојки врз основа на продажби
Опис
Извештајот предвидува колку од секоја состојка ќе биде потрошена во следните 30 дена, врз основа на просечната дневна потрошувачка во последните 90 дена. Користи три нивоа на вгнездување: (1) продажби по производ по ден, (2) агрегација по состојка преку рецепт, (3) споредба со моменталната залиха за да се најдат состојки што ќе треба наскоро да се нарачаат.
SQL решение
CREATE OR REPLACE FUNCTION project.get_ingredient_consumption_forecast()
RETURNS TABLE (
ingredient_id INT,
ingredient_name TEXT,
avg_daily_usage NUMERIC,
forecast_30d NUMERIC,
current_stock NUMERIC,
days_until_empty NUMERIC,
action TEXT
)
LANGUAGE sql
AS $$
WITH daily_product_sales AS (
SELECT
oi.product_id,
DATE(o.created_at) AS sale_date,
SUM(oi.quantity) AS qty_sold
FROM project.order_item oi
JOIN project.orders o ON o.order_id = oi.order_id
WHERE o.status = 'ПЛАТЕНА'
AND o.created_at >= NOW() - INTERVAL '90 days'
GROUP BY oi.product_id, DATE(o.created_at)
),
ingredient_usage AS (
SELECT
ri.ingredient_id AS ing_id,
SUM(dps.qty_sold * ri.quantity_needed)::numeric AS total_used
FROM daily_product_sales dps
JOIN project.recipe r ON r.product_id = dps.product_id
JOIN project.recipe_item ri ON ri.recipe_id = r.recipe_id
GROUP BY ri.ingredient_id
),
stock AS (
SELECT
ii.ingredient_id AS ing_id,
COALESCE(SUM(ii.quantity_change), 0)::numeric AS current_stock
FROM project.ingredient_inventory ii
GROUP BY ii.ingredient_id
)
SELECT
i.ingredient_id,
i.name::TEXT,
ROUND(iu.total_used / 90.0, 3),
ROUND((iu.total_used / 90.0) * 30, 2),
COALESCE(s.current_stock, 0),
CASE
WHEN (iu.total_used / 90.0) > 0
THEN ROUND(COALESCE(s.current_stock, 0) / (iu.total_used / 90.0), 1)
ELSE NULL
END,
CASE
WHEN COALESCE(s.current_stock, 0) < (iu.total_used / 90.0) * 30
AND i.min_stock > COALESCE(s.current_stock, 0) THEN 'ИТНО НАРАЧАЈ'
WHEN COALESCE(s.current_stock, 0) < (iu.total_used / 90.0) * 30 THEN 'НАРАЧАЈ'
ELSE 'ОК'
END::TEXT
FROM project.ingredient i
JOIN ingredient_usage iu ON iu.ing_id = i.ingredient_id
LEFT JOIN stock s ON s.ing_id = i.ingredient_id
WHERE i.active = TRUE
ORDER BY 6 ASC NULLS LAST;
$$;
Релациона алгебра
OI(order_id, product_id, quantity, unit_price)
O(order_id, status, created_at)
R(recipe_id, product_id)
RI(recipe_id, ingredient_id, quantity_needed)
I(ingredient_id, name, min_stock, active)
II(id, ingredient_id, quantity_change)
J1 ← OI ⨝ OI.order_id = O.order_id O
F1 ← σ status='ПЛАТЕНА' ∧ created_at ≥ NOW() - INTERVAL '90 days' (J1)
G1 ← γ product_id, sale_date; SUM(quantity) → qty_sold (F1)
J2 ← G1 ⨝ G1.product_id = R.product_id R
J3 ← J2 ⨝ R.recipe_id = RI.recipe_id RI
G2 ← γ ingredient_id; SUM(qty_sold * quantity_needed) → total_used (J3)
G3 ← γ ingredient_id; COALESCE(SUM(quantity_change), 0) → current_stock (II)
J4 ← I ⨝ G2 ⨝ G3
F2 ← σ active=TRUE (J4)
R ← π ingredient_id, ingredient_name, avg_daily_usage, forecast_30d,
current_stock, days_until_empty, action (F2)
R_final ← τ days_until_empty ASC (R)
Note:
See TracWiki
for help on using the wiki.
