product performance grouped kpi improvements
This commit is contained in:
@@ -505,9 +505,19 @@ UPDATE mk_product_performance_kpi_daily
|
||||
SET askili_yan = '', updated_at = now()
|
||||
WHERE btrim(askili_yan) = '-'`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS sales_qty_180d NUMERIC(18,4) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS sales_qty_total NUMERIC(18,4) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS sales_usd_180d NUMERIC(18,4) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS sales_usd_total NUMERIC(18,4) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS avg_daily_sales_180d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS avg_daily_sales_365d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS avg_daily_sales_total NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_days_180d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_days_365d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_days_total NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_turnover_90d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_turnover_180d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_turnover_365d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS stock_turnover_total NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS avg_price_usd_180d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS gross_profit_usd_180d NUMERIC(18,4) NOT NULL DEFAULT 0`,
|
||||
`ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS gross_margin_180d NUMERIC(18,6) NOT NULL DEFAULT 0`,
|
||||
@@ -1073,9 +1083,12 @@ func ListProductPerformance(ctx context.Context, pg *sql.DB, f ProductPerformanc
|
||||
SELECT
|
||||
to_char(kpi_date,'YYYY-MM-DD'), product_code, color_code, yaka_kodu, item_description,
|
||||
kategori, seri, yas_grubu, askili_yan, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu, market_key, stock_qty,
|
||||
sales_qty_30d, sales_qty_90d, sales_qty_180d, sales_qty_365d, sales_qty_730d,
|
||||
sales_usd_30d, sales_usd_90d, sales_usd_180d, sales_usd_365d, avg_daily_sales_90d, avg_daily_sales_180d,
|
||||
stock_days_90d, stock_days_180d, avg_price_usd_90d, avg_price_usd_180d, cost_price_usd, base_price_usd, base_price_try,
|
||||
sales_qty_30d, sales_qty_90d, sales_qty_180d, sales_qty_365d, sales_qty_730d, sales_qty_total,
|
||||
sales_usd_30d, sales_usd_90d, sales_usd_180d, sales_usd_365d, sales_usd_total,
|
||||
avg_daily_sales_90d, avg_daily_sales_180d, avg_daily_sales_365d, avg_daily_sales_total,
|
||||
stock_days_90d, stock_days_180d, stock_days_365d, stock_days_total,
|
||||
stock_turnover_90d, stock_turnover_180d, stock_turnover_365d, stock_turnover_total,
|
||||
avg_price_usd_90d, avg_price_usd_180d, cost_price_usd, base_price_usd, base_price_try,
|
||||
gross_profit_usd_90d, gross_profit_usd_180d, gross_margin_90d, gross_margin_180d,
|
||||
unit_profit_cost_90d, unit_profit_cost_180d, unit_profit_base_90d, unit_profit_base_180d, market_count_90d, customer_count_90d, sales_index_90d,
|
||||
price_index_90d, margin_index_90d, performance_score, performance_bucket,
|
||||
@@ -1095,9 +1108,12 @@ LIMIT $`+fmt.Sprint(len(args)-1)+` OFFSET $`+fmt.Sprint(len(args)), args...)
|
||||
if err := rows.Scan(
|
||||
&r.KpiDate, &r.ProductCode, &r.ColorCode, &r.YakaKodu, &r.ItemDescription,
|
||||
&r.Kategori, &r.Seri, &r.YasGrubu, &r.AskiliYan, &r.UrunIlkGrubu, &r.UrunAnaGrubu, &r.UrunAltGrubu, &r.MarketKey, &r.StockQty,
|
||||
&r.SalesQty30, &r.SalesQty90, &r.SalesQty180, &r.SalesQty365, &r.SalesQty730,
|
||||
&r.SalesUSD30, &r.SalesUSD90, &r.SalesUSD180, &r.SalesUSD365, &r.AvgDailySales90, &r.AvgDailySales180,
|
||||
&r.StockDays90, &r.StockDays180, &r.AvgPriceUSD90, &r.AvgPriceUSD180, &r.CostPriceUSD, &r.BasePriceUSD, &r.BasePriceTRY,
|
||||
&r.SalesQty30, &r.SalesQty90, &r.SalesQty180, &r.SalesQty365, &r.SalesQty730, &r.SalesQtyTotal,
|
||||
&r.SalesUSD30, &r.SalesUSD90, &r.SalesUSD180, &r.SalesUSD365, &r.SalesUSDTotal,
|
||||
&r.AvgDailySales90, &r.AvgDailySales180, &r.AvgDailySales365, &r.AvgDailySalesTotal,
|
||||
&r.StockDays90, &r.StockDays180, &r.StockDays365, &r.StockDaysTotal,
|
||||
&r.StockTurnover90, &r.StockTurnover180, &r.StockTurnover365, &r.StockTurnoverTotal,
|
||||
&r.AvgPriceUSD90, &r.AvgPriceUSD180, &r.CostPriceUSD, &r.BasePriceUSD, &r.BasePriceTRY,
|
||||
&r.GrossProfitUSD90, &r.GrossProfitUSD180, &r.GrossMargin90, &r.GrossMargin180,
|
||||
&r.UnitProfitCost90, &r.UnitProfitCost180, &r.UnitProfitBase90, &r.UnitProfitBase180, &r.MarketCount90, &r.CustomerCount90, &r.SalesIndex90,
|
||||
&r.PriceIndex90, &r.MarginIndex90, &r.PerformanceScore, &r.PerformanceBucket,
|
||||
@@ -1232,6 +1248,16 @@ StockAgg AS (
|
||||
WHERE s.stock_date = (SELECT stock_date FROM LatestStockDate)
|
||||
GROUP BY s.product_code, s.color_code, s.yaka_kodu
|
||||
),
|
||||
StockTotalStart AS (
|
||||
SELECT DISTINCT ON (s.product_code, s.color_code, s.yaka_kodu)
|
||||
s.product_code,
|
||||
s.color_code,
|
||||
s.yaka_kodu,
|
||||
s.stock_qty
|
||||
FROM mk_product_performance_stock_daily s
|
||||
WHERE s.stock_date <= DATE '2022-01-01'
|
||||
ORDER BY s.product_code, s.color_code, s.yaka_kodu, s.stock_date DESC
|
||||
),
|
||||
Dim AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code,
|
||||
@@ -1354,7 +1380,7 @@ Scored AS (
|
||||
b.sales_qty_total / GREATEST(1, (Bounds.period_end - Bounds.period_start + 1)) AS avg_daily_sales_total,
|
||||
CASE
|
||||
WHEN b.sales_qty_total <= 0 THEN 9999
|
||||
ELSE COALESCE(st.stock_qty, 0) / NULLIF(b.sales_qty_total / GREATEST(1, (Bounds.period_end - Bounds.period_start + 1)), 0)
|
||||
ELSE ((COALESCE(st_start.stock_qty, 0) + COALESCE(st.stock_qty, 0)) / 2.0) / NULLIF(b.sales_qty_total / GREATEST(1, (Bounds.period_end - Bounds.period_start + 1)), 0)
|
||||
END AS stock_days_total,
|
||||
CASE WHEN b.sales_qty_total <= 0 THEN 0 ELSE b.sales_usd_total / NULLIF(b.sales_qty_total,0) END AS avg_price_usd_total,
|
||||
COALESCE(pd.cost_price_usd,0) AS cost_price_usd,
|
||||
@@ -1379,6 +1405,10 @@ Scored AS (
|
||||
ON st.product_code = b.product_code
|
||||
AND st.color_code = b.color_code
|
||||
AND st.yaka_kodu = b.yaka_kodu
|
||||
LEFT JOIN StockTotalStart st_start
|
||||
ON st_start.product_code = b.product_code
|
||||
AND st_start.color_code = b.color_code
|
||||
AND st_start.yaka_kodu = b.yaka_kodu
|
||||
LEFT JOIN mk_product_performance_price_dim pd ON pd.product_code = b.product_code
|
||||
LEFT JOIN Spread sp
|
||||
ON sp.product_code = b.product_code
|
||||
@@ -2548,6 +2578,46 @@ StockAgg AS (
|
||||
WHERE stock_date = (SELECT MAX(stock_date) FROM mk_product_performance_stock_daily)
|
||||
GROUP BY product_code, color_code, yaka_kodu
|
||||
),
|
||||
Stock90Start AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code,
|
||||
color_code,
|
||||
yaka_kodu,
|
||||
stock_qty
|
||||
FROM mk_product_performance_stock_daily
|
||||
WHERE stock_date <= current_date - INTERVAL '89 days'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
Stock180Start AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code,
|
||||
color_code,
|
||||
yaka_kodu,
|
||||
stock_qty
|
||||
FROM mk_product_performance_stock_daily
|
||||
WHERE stock_date <= current_date - INTERVAL '179 days'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
Stock365Start AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code,
|
||||
color_code,
|
||||
yaka_kodu,
|
||||
stock_qty
|
||||
FROM mk_product_performance_stock_daily
|
||||
WHERE stock_date <= current_date - INTERVAL '359 days'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
StockTotalStart AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code,
|
||||
color_code,
|
||||
yaka_kodu,
|
||||
stock_qty
|
||||
FROM mk_product_performance_stock_daily
|
||||
WHERE stock_date <= DATE '2022-01-01'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
Agg AS (
|
||||
SELECT
|
||||
$2::text AS breakdown,
|
||||
@@ -2567,6 +2637,10 @@ Agg AS (
|
||||
%s,
|
||||
COUNT(DISTINCT product_code) AS product_count,
|
||||
COALESCE(MAX(stock_qty),0) AS stock_qty,
|
||||
COALESCE(MAX(avg_stock_90d),0) AS avg_stock_90d,
|
||||
COALESCE(MAX(avg_stock_180d),0) AS avg_stock_180d,
|
||||
COALESCE(MAX(avg_stock_365d),0) AS avg_stock_365d,
|
||||
COALESCE(MAX(avg_stock_total),0) AS avg_stock_total,
|
||||
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days' AND COALESCE(customer_code,'') <> '')::integer AS customer_count_90d,
|
||||
COALESCE(SUM(invoice_count) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)::integer AS invoice_count_90d,
|
||||
COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0) AS sales_qty_90d,
|
||||
@@ -2637,11 +2711,19 @@ Agg AS (
|
||||
s.*,
|
||||
COALESCE(pd.base_price_usd,0) AS base_price_usd,
|
||||
COALESCE(pd.cost_price_usd,0) AS cost_price_usd,
|
||||
COALESCE(st.stock_qty,0) AS stock_qty
|
||||
COALESCE(st.stock_qty,0) AS stock_qty,
|
||||
(COALESCE(s90.stock_qty,0) + COALESCE(st.stock_qty,0)) / 2.0 AS avg_stock_90d,
|
||||
(COALESCE(s180.stock_qty,0) + COALESCE(st.stock_qty,0)) / 2.0 AS avg_stock_180d,
|
||||
(COALESCE(s365.stock_qty,0) + COALESCE(st.stock_qty,0)) / 2.0 AS avg_stock_365d,
|
||||
(COALESCE(stotal.stock_qty,0) + COALESCE(st.stock_qty,0)) / 2.0 AS avg_stock_total
|
||||
FROM mk_product_performance_sales_daily s
|
||||
LEFT JOIN mk_product_performance_price_dim pd ON pd.product_code = s.product_code
|
||||
LEFT JOIN LatestKPI k ON k.product_code = s.product_code AND k.color_code = s.color_code AND k.yaka_kodu = s.yaka_kodu
|
||||
LEFT JOIN StockAgg st ON st.product_code = s.product_code AND st.color_code = s.color_code AND st.yaka_kodu = s.yaka_kodu
|
||||
LEFT JOIN Stock90Start s90 ON s90.product_code = s.product_code AND s90.color_code = s.color_code AND s90.yaka_kodu = s.yaka_kodu
|
||||
LEFT JOIN Stock180Start s180 ON s180.product_code = s.product_code AND s180.color_code = s.color_code AND s180.yaka_kodu = s.yaka_kodu
|
||||
LEFT JOIN Stock365Start s365 ON s365.product_code = s.product_code AND s365.color_code = s.color_code AND s365.yaka_kodu = s.yaka_kodu
|
||||
LEFT JOIN StockTotalStart stotal ON stotal.product_code = s.product_code AND stotal.color_code = s.color_code AND stotal.yaka_kodu = s.yaka_kodu
|
||||
) s
|
||||
WHERE sales_date >= DATE '2022-01-01'
|
||||
GROUP BY %s
|
||||
@@ -2738,10 +2820,10 @@ SELECT
|
||||
gross_profit_cost_usd_total,
|
||||
gross_margin_base_total,
|
||||
gross_margin_cost_total,
|
||||
CASE WHEN stock_qty > 0 THEN sales_qty_90d / NULLIF(stock_qty,0) ELSE 0 END AS stock_turnover_90d,
|
||||
CASE WHEN stock_qty > 0 THEN sales_qty_180d / NULLIF(stock_qty,0) ELSE 0 END AS stock_turnover_180d,
|
||||
CASE WHEN stock_qty > 0 THEN sales_qty_365d / NULLIF(stock_qty,0) ELSE 0 END AS stock_turnover_365d,
|
||||
CASE WHEN stock_qty > 0 THEN sales_qty_total / NULLIF(stock_qty,0) ELSE 0 END AS stock_turnover_total,
|
||||
CASE WHEN avg_stock_90d > 0 THEN sales_qty_90d / NULLIF(avg_stock_90d,0) ELSE 0 END AS stock_turnover_90d,
|
||||
CASE WHEN avg_stock_180d > 0 THEN sales_qty_180d / NULLIF(avg_stock_180d,0) ELSE 0 END AS stock_turnover_180d,
|
||||
CASE WHEN avg_stock_365d > 0 THEN sales_qty_365d / NULLIF(avg_stock_365d,0) ELSE 0 END AS stock_turnover_365d,
|
||||
CASE WHEN avg_stock_total > 0 THEN sales_qty_total / NULLIF(avg_stock_total,0) ELSE 0 END AS stock_turnover_total,
|
||||
has_cost,
|
||||
sales_index_90d,
|
||||
CASE WHEN NOT has_cost THEN 0 ELSE
|
||||
@@ -2786,7 +2868,7 @@ SELECT
|
||||
+ LEAST(30, GREATEST(gross_margin_cost_90d,0) * 60)
|
||||
+ LEAST(15, invoice_count_90d * 1.5)
|
||||
+ LEAST(10, sales_qty_90d / 10)
|
||||
+ LEAST(10, (CASE WHEN stock_qty > 0 THEN sales_qty_90d / NULLIF(stock_qty,0) ELSE 0 END) * 5),
|
||||
+ LEAST(10, (CASE WHEN avg_stock_90d > 0 THEN sales_qty_90d / NULLIF(avg_stock_90d,0) ELSE 0 END) * 5),
|
||||
4
|
||||
)
|
||||
END AS performance_score,
|
||||
@@ -2982,9 +3064,11 @@ SELECT jsonb_build_object(
|
||||
'sales_qty_90d', sales_qty_90d,
|
||||
'sales_qty_180d', sales_qty_180d,
|
||||
'sales_qty_365d', sales_qty_365d,
|
||||
'sales_qty_total', sales_qty_total,
|
||||
'sales_usd_90d', sales_usd_90d,
|
||||
'sales_usd_180d', sales_usd_180d,
|
||||
'sales_usd_365d', sales_usd_365d,
|
||||
'sales_usd_total', sales_usd_total,
|
||||
'avg_price_usd_90d', avg_price_usd_90d,
|
||||
'avg_price_usd_180d', avg_price_usd_180d,
|
||||
'cost_price_usd', cost_price_usd,
|
||||
@@ -3006,9 +3090,14 @@ SELECT jsonb_build_object(
|
||||
'performance_score', performance_score,
|
||||
'performance_bucket', performance_bucket,
|
||||
'idle_cost_usd', idle_cost_usd,
|
||||
'stock_turnover_90d', CASE WHEN stock_qty > 0 THEN sales_qty_90d / NULLIF(stock_qty,0) ELSE 0 END,
|
||||
'stock_turnover_180d', CASE WHEN stock_qty > 0 THEN sales_qty_180d / NULLIF(stock_qty,0) ELSE 0 END,
|
||||
'stock_turnover_365d', CASE WHEN stock_qty > 0 THEN sales_qty_365d / NULLIF(stock_qty,0) ELSE 0 END
|
||||
'stock_days_90d', stock_days_90d,
|
||||
'stock_days_180d', stock_days_180d,
|
||||
'stock_days_365d', stock_days_365d,
|
||||
'stock_days_total', stock_days_total,
|
||||
'stock_turnover_90d', CASE WHEN avg_stock_90d > 0 THEN sales_qty_90d / NULLIF(avg_stock_90d,0) ELSE 0 END,
|
||||
'stock_turnover_180d', CASE WHEN avg_stock_180d > 0 THEN sales_qty_180d / NULLIF(avg_stock_180d,0) ELSE 0 END,
|
||||
'stock_turnover_365d', CASE WHEN avg_stock_365d > 0 THEN sales_qty_365d / NULLIF(avg_stock_365d,0) ELSE 0 END,
|
||||
'stock_turnover_total', CASE WHEN avg_stock_total > 0 THEN sales_qty_total / NULLIF(avg_stock_total,0) ELSE 0 END
|
||||
) AS row_json
|
||||
FROM (
|
||||
SELECT
|
||||
@@ -3028,12 +3117,22 @@ FROM (
|
||||
COALESCE((ARRAY_AGG(NULLIF(urun_alt_grubu,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS urun_alt_grubu,
|
||||
COALESCE((ARRAY_AGG(NULLIF(market_key,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS market_key,
|
||||
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) AS stock_qty,
|
||||
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN avg_stock_90d ELSE 0 END),0) AS avg_stock_90d,
|
||||
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN avg_stock_180d ELSE 0 END),0) AS avg_stock_180d,
|
||||
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN avg_stock_365d ELSE 0 END),0) AS avg_stock_365d,
|
||||
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN avg_stock_total ELSE 0 END),0) AS avg_stock_total,
|
||||
COALESCE(SUM(sales_qty_90d),0) AS sales_qty_90d,
|
||||
COALESCE(SUM(sales_qty_180d),0) AS sales_qty_180d,
|
||||
COALESCE(SUM(sales_qty_365d),0) AS sales_qty_365d,
|
||||
COALESCE(SUM(sales_qty_total),0) AS sales_qty_total,
|
||||
COALESCE(SUM(sales_usd_90d),0) AS sales_usd_90d,
|
||||
COALESCE(SUM(sales_usd_180d),0) AS sales_usd_180d,
|
||||
COALESCE(SUM(sales_usd_365d),0) AS sales_usd_365d,
|
||||
COALESCE(SUM(sales_usd_total),0) AS sales_usd_total,
|
||||
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_days_90d * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE 0 END AS stock_days_90d,
|
||||
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_days_180d * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE 0 END AS stock_days_180d,
|
||||
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_days_365d * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE 0 END AS stock_days_365d,
|
||||
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_days_total * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE 0 END AS stock_days_total,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(sales_usd_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS avg_price_usd_90d,
|
||||
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(sales_usd_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE 0 END AS avg_price_usd_180d,
|
||||
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN cost_price_usd * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE 0 END AS cost_price_usd,
|
||||
@@ -3082,9 +3181,10 @@ func queryProductPerformanceSQLLeafRows(ctx context.Context, pg *sql.DB, mode st
|
||||
query := productPerformanceSQLSourceCTE(mode) + fmt.Sprintf(`
|
||||
SELECT to_jsonb(t) || jsonb_build_object(
|
||||
'row_key', 'leaf|' || product_code || '|' || color_code || '|' || yaka_kodu || '|' || market_key,
|
||||
'stock_turnover_90d', CASE WHEN stock_qty > 0 THEN sales_qty_90d / NULLIF(stock_qty,0) ELSE 0 END,
|
||||
'stock_turnover_180d', CASE WHEN stock_qty > 0 THEN sales_qty_180d / NULLIF(stock_qty,0) ELSE 0 END,
|
||||
'stock_turnover_365d', CASE WHEN stock_qty > 0 THEN sales_qty_365d / NULLIF(stock_qty,0) ELSE 0 END
|
||||
'stock_turnover_90d', CASE WHEN avg_stock_90d > 0 THEN sales_qty_90d / NULLIF(avg_stock_90d,0) ELSE 0 END,
|
||||
'stock_turnover_180d', CASE WHEN avg_stock_180d > 0 THEN sales_qty_180d / NULLIF(avg_stock_180d,0) ELSE 0 END,
|
||||
'stock_turnover_365d', CASE WHEN avg_stock_365d > 0 THEN sales_qty_365d / NULLIF(avg_stock_365d,0) ELSE 0 END,
|
||||
'stock_turnover_total', CASE WHEN avg_stock_total > 0 THEN sales_qty_total / NULLIF(avg_stock_total,0) ELSE 0 END
|
||||
) AS row_json
|
||||
FROM Source t
|
||||
%s
|
||||
@@ -3123,7 +3223,39 @@ func productPerformanceSQLSourceCTE(mode string) string {
|
||||
AND (performance_bucket = 'STOK_RISKI' OR COALESCE(sales_qty_90d,0) = 0 OR COALESCE(stock_days_90d,0) > 180)`
|
||||
}
|
||||
return `
|
||||
WITH Source AS (
|
||||
WITH LatestKPIDate AS (
|
||||
SELECT MAX(kpi_date) AS kpi_date
|
||||
FROM mk_product_performance_kpi_daily
|
||||
),
|
||||
Stock90Start AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code, color_code, yaka_kodu, stock_qty
|
||||
FROM mk_product_performance_stock_daily, LatestKPIDate
|
||||
WHERE stock_date <= LatestKPIDate.kpi_date - INTERVAL '89 days'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
Stock180Start AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code, color_code, yaka_kodu, stock_qty
|
||||
FROM mk_product_performance_stock_daily, LatestKPIDate
|
||||
WHERE stock_date <= LatestKPIDate.kpi_date - INTERVAL '179 days'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
Stock365Start AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code, color_code, yaka_kodu, stock_qty
|
||||
FROM mk_product_performance_stock_daily, LatestKPIDate
|
||||
WHERE stock_date <= LatestKPIDate.kpi_date - INTERVAL '359 days'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
StockTotalStart AS (
|
||||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||||
product_code, color_code, yaka_kodu, stock_qty
|
||||
FROM mk_product_performance_stock_daily
|
||||
WHERE stock_date <= DATE '2022-01-01'
|
||||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||||
),
|
||||
Source AS (
|
||||
SELECT
|
||||
product_code,
|
||||
color_code,
|
||||
@@ -3142,12 +3274,22 @@ WITH Source AS (
|
||||
urun_alt_grubu,
|
||||
market_key,
|
||||
COALESCE(stock_qty,0) AS stock_qty,
|
||||
(COALESCE((SELECT s.stock_qty FROM Stock90Start s WHERE s.product_code = mk_product_performance_kpi_daily.product_code AND s.color_code = mk_product_performance_kpi_daily.color_code AND s.yaka_kodu = mk_product_performance_kpi_daily.yaka_kodu),0) + COALESCE(stock_qty,0)) / 2.0 AS avg_stock_90d,
|
||||
(COALESCE((SELECT s.stock_qty FROM Stock180Start s WHERE s.product_code = mk_product_performance_kpi_daily.product_code AND s.color_code = mk_product_performance_kpi_daily.color_code AND s.yaka_kodu = mk_product_performance_kpi_daily.yaka_kodu),0) + COALESCE(stock_qty,0)) / 2.0 AS avg_stock_180d,
|
||||
(COALESCE((SELECT s.stock_qty FROM Stock365Start s WHERE s.product_code = mk_product_performance_kpi_daily.product_code AND s.color_code = mk_product_performance_kpi_daily.color_code AND s.yaka_kodu = mk_product_performance_kpi_daily.yaka_kodu),0) + COALESCE(stock_qty,0)) / 2.0 AS avg_stock_365d,
|
||||
(COALESCE((SELECT s.stock_qty FROM StockTotalStart s WHERE s.product_code = mk_product_performance_kpi_daily.product_code AND s.color_code = mk_product_performance_kpi_daily.color_code AND s.yaka_kodu = mk_product_performance_kpi_daily.yaka_kodu),0) + COALESCE(stock_qty,0)) / 2.0 AS avg_stock_total,
|
||||
COALESCE(sales_qty_90d,0) AS sales_qty_90d,
|
||||
COALESCE(sales_qty_180d,0) AS sales_qty_180d,
|
||||
COALESCE(sales_qty_365d,0) AS sales_qty_365d,
|
||||
COALESCE(sales_qty_total,0) AS sales_qty_total,
|
||||
COALESCE(sales_usd_90d,0) AS sales_usd_90d,
|
||||
COALESCE(sales_usd_180d,0) AS sales_usd_180d,
|
||||
COALESCE(sales_usd_365d,0) AS sales_usd_365d,
|
||||
COALESCE(sales_usd_total,0) AS sales_usd_total,
|
||||
COALESCE(stock_days_90d,0) AS stock_days_90d,
|
||||
COALESCE(stock_days_180d,0) AS stock_days_180d,
|
||||
COALESCE(stock_days_365d,0) AS stock_days_365d,
|
||||
COALESCE(stock_days_total,0) AS stock_days_total,
|
||||
COALESCE(avg_price_usd_90d,0) AS avg_price_usd_90d,
|
||||
COALESCE(avg_price_usd_180d,0) AS avg_price_usd_180d,
|
||||
COALESCE(cost_price_usd,0) AS cost_price_usd,
|
||||
@@ -3430,7 +3572,7 @@ func deriveProductPerformanceGroupMetrics(out map[string]any, groupField string)
|
||||
sales := floatFromMap(out, "sales_usd_"+suffix)
|
||||
qty := floatFromMap(out, "sales_qty_"+suffix)
|
||||
stockQty := floatFromMap(out, "stock_qty")
|
||||
if stockQty > 0 {
|
||||
if _, exists := out["stock_turnover_"+suffix]; !exists && stockQty > 0 {
|
||||
out["stock_turnover_"+suffix] = qty / stockQty
|
||||
}
|
||||
if qty > 0 {
|
||||
@@ -4012,10 +4154,20 @@ func productPerformanceOrderBy(sortBy string, desc bool) string {
|
||||
"stock_qty": "stock_qty",
|
||||
"sales_qty_90d": "sales_qty_90d",
|
||||
"sales_qty_180d": "sales_qty_180d",
|
||||
"sales_qty_365d": "sales_qty_365d",
|
||||
"sales_qty_total": "sales_qty_total",
|
||||
"sales_usd_90d": "sales_usd_90d",
|
||||
"sales_usd_180d": "sales_usd_180d",
|
||||
"sales_usd_365d": "sales_usd_365d",
|
||||
"sales_usd_total": "sales_usd_total",
|
||||
"stock_days_90d": "stock_days_90d",
|
||||
"stock_days_180d": "stock_days_180d",
|
||||
"stock_days_365d": "stock_days_365d",
|
||||
"stock_days_total": "stock_days_total",
|
||||
"stock_turnover_90d": "stock_turnover_90d",
|
||||
"stock_turnover_180d": "stock_turnover_180d",
|
||||
"stock_turnover_365d": "stock_turnover_365d",
|
||||
"stock_turnover_total": "stock_turnover_total",
|
||||
"avg_price_usd_90d": "avg_price_usd_90d",
|
||||
"avg_price_usd_180d": "avg_price_usd_180d",
|
||||
"base_price_usd": "base_price_usd",
|
||||
|
||||
Reference in New Issue
Block a user