ui: update ProductPerformanceProfitability page to enhance table views and tabs management
This commit is contained in:
@@ -670,8 +670,10 @@ func ListProductPerformance(ctx context.Context, pg *sql.DB, f ProductPerformanc
|
||||
return nil, 0, err
|
||||
}
|
||||
limit := f.Limit
|
||||
if limit <= 0 || limit > 500 {
|
||||
if limit <= 0 {
|
||||
limit = 100
|
||||
} else if limit > 50000 {
|
||||
limit = 50000
|
||||
}
|
||||
page := f.Page
|
||||
if page <= 0 {
|
||||
@@ -741,6 +743,25 @@ KPI AS (
|
||||
FROM mk_product_performance_kpi_daily
|
||||
WHERE kpi_date = (SELECT kpi_date FROM Latest)
|
||||
),
|
||||
VariantStock AS (
|
||||
SELECT
|
||||
product_code,
|
||||
color_code,
|
||||
yaka_kodu,
|
||||
MAX(stock_qty) AS stock_qty,
|
||||
MAX(cost_price_usd) AS cost_price_usd,
|
||||
BOOL_OR(performance_bucket IN ('STOK_RISKI','TAKIP')) AS has_risk_bucket,
|
||||
SUM(COALESCE(sales_qty_90d,0)) AS sales_qty_90d
|
||||
FROM KPI
|
||||
GROUP BY product_code, color_code, yaka_kodu
|
||||
),
|
||||
StockTotals AS (
|
||||
SELECT
|
||||
COALESCE(SUM(stock_qty),0) AS total_stock,
|
||||
COALESCE(SUM(stock_qty * cost_price_usd),0) AS stock_cost_usd,
|
||||
COALESCE(SUM(CASE WHEN has_risk_bucket AND COALESCE(sales_qty_90d,0)=0 THEN stock_qty * cost_price_usd ELSE 0 END),0) AS risk_cost_usd
|
||||
FROM VariantStock
|
||||
),
|
||||
Sales90 AS (
|
||||
SELECT
|
||||
COUNT(DISTINCT market_key) AS market_count_90d,
|
||||
@@ -754,9 +775,9 @@ SELECT
|
||||
COUNT(*) FILTER (WHERE performance_bucket='YILDIZ_URUN'),
|
||||
COUNT(*) FILTER (WHERE performance_bucket='STOK_RISKI'),
|
||||
COUNT(*) FILTER (WHERE performance_bucket='STOKSUZ_TALEP'),
|
||||
COALESCE(SUM(stock_qty),0),
|
||||
COALESCE(SUM(stock_qty * cost_price_usd),0),
|
||||
COALESCE(SUM(CASE WHEN performance_bucket IN ('STOK_RISKI','TAKIP') AND COALESCE(sales_qty_90d,0)=0 THEN stock_qty * cost_price_usd ELSE 0 END),0),
|
||||
COALESCE(MAX(StockTotals.total_stock),0),
|
||||
COALESCE(MAX(StockTotals.stock_cost_usd),0),
|
||||
COALESCE(MAX(StockTotals.risk_cost_usd),0),
|
||||
COALESCE(SUM(sales_qty_90d),0),
|
||||
COALESCE(SUM(sales_usd_90d),0),
|
||||
COALESCE(SUM(gross_profit_usd_90d),0),
|
||||
@@ -765,6 +786,7 @@ SELECT
|
||||
COALESCE(to_char(MAX(updated_at),'YYYY-MM-DD HH24:MI:SS'),'')
|
||||
FROM KPI
|
||||
CROSS JOIN Sales90
|
||||
CROSS JOIN StockTotals
|
||||
`).Scan(&s.KpiDate, &s.TotalRows, &s.StarCount, &s.StockRisk, &s.NoStockDemand, &s.TotalStock, &s.StockCostUSD, &s.RiskCostUSD, &s.SalesQty90, &s.SalesUSD90, &s.GrossProfit90, &s.MarketCount90, &s.CustomerCount90, &s.UpdatedAt)
|
||||
return s, err
|
||||
}
|
||||
@@ -2007,10 +2029,22 @@ func ListProductPerformanceStockSizes(ctx context.Context, productCode, colorCod
|
||||
return nil, fmt.Errorf("mssql db nil")
|
||||
}
|
||||
rows, err := db.MssqlDB.QueryContext(ctx, `
|
||||
;WITH ActiveWarehouses AS (
|
||||
SELECT WarehouseCode
|
||||
FROM (VALUES
|
||||
('1-0-12'),('1.01.2014'),('1.02.2005'),('1.02.2004'),('1-0-43'),
|
||||
('4.02.2001'),('1-0-55'),('1.01.2003'),('1-0-21'),('1-0-2'),
|
||||
('1.01.2004'),('1-0-49'),('1-0-37'),('1-0-29'),('1-0-28'),
|
||||
('1-0-10'),('100'),('1.02.2006'),('1-0-42'),('1.01.2002'),
|
||||
('1-0-52')
|
||||
) W(WarehouseCode)
|
||||
)
|
||||
SELECT
|
||||
SizeCode = LTRIM(RTRIM(ISNULL(S.ItemDim1Code, ''))),
|
||||
StockQty = SUM(S.InventoryQty1)
|
||||
FROM StockWithCost S WITH(NOLOCK)
|
||||
INNER JOIN ActiveWarehouses W
|
||||
ON W.WarehouseCode = LTRIM(RTRIM(S.WarehouseCode))
|
||||
WHERE S.ItemTypeCode = 1
|
||||
AND LTRIM(RTRIM(S.ItemCode)) = @p1
|
||||
AND LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) = @p2
|
||||
@@ -2068,39 +2102,43 @@ func productPerformanceWhere(f ProductPerformanceFilters) (string, []any) {
|
||||
|
||||
func productPerformanceOrderBy(sortBy string, desc bool) string {
|
||||
allowed := map[string]string{
|
||||
"product_code": "product_code",
|
||||
"color_code": "color_code",
|
||||
"yaka_kodu": "yaka_kodu",
|
||||
"item_description": "item_description",
|
||||
"kategori": "kategori",
|
||||
"urun_ilk_grubu": "urun_ilk_grubu",
|
||||
"askili_yan": "askili_yan",
|
||||
"urun_ana_grubu": "urun_ana_grubu",
|
||||
"urun_alt_grubu": "urun_alt_grubu",
|
||||
"market_key": "market_key",
|
||||
"stock_qty": "stock_qty",
|
||||
"sales_qty_90d": "sales_qty_90d",
|
||||
"sales_qty_180d": "sales_qty_180d",
|
||||
"sales_usd_90d": "sales_usd_90d",
|
||||
"sales_usd_180d": "sales_usd_180d",
|
||||
"stock_days_90d": "stock_days_90d",
|
||||
"stock_days_180d": "stock_days_180d",
|
||||
"avg_price_usd_90d": "avg_price_usd_90d",
|
||||
"avg_price_usd_180d": "avg_price_usd_180d",
|
||||
"base_price_usd": "base_price_usd",
|
||||
"cost_price_usd": "cost_price_usd",
|
||||
"unit_profit_base_90d": "unit_profit_base_90d",
|
||||
"unit_profit_cost_90d": "unit_profit_cost_90d",
|
||||
"unit_profit_base_180d": "unit_profit_base_180d",
|
||||
"unit_profit_cost_180d": "unit_profit_cost_180d",
|
||||
"gross_margin_90d": "gross_margin_90d",
|
||||
"gross_margin_180d": "gross_margin_180d",
|
||||
"market_count_90d": "market_count_90d",
|
||||
"customer_count_90d": "customer_count_90d",
|
||||
"sales_index_90d": "sales_index_90d",
|
||||
"performance_score": "performance_score",
|
||||
"performance_bucket": "performance_bucket",
|
||||
"last_sale_date": "last_sale_date",
|
||||
"product_code": "product_code",
|
||||
"color_code": "color_code",
|
||||
"yaka_kodu": "yaka_kodu",
|
||||
"item_description": "item_description",
|
||||
"kategori": "kategori",
|
||||
"urun_ilk_grubu": "urun_ilk_grubu",
|
||||
"askili_yan": "askili_yan",
|
||||
"urun_ana_grubu": "urun_ana_grubu",
|
||||
"urun_alt_grubu": "urun_alt_grubu",
|
||||
"market_key": "market_key",
|
||||
"stock_qty": "stock_qty",
|
||||
"sales_qty_90d": "sales_qty_90d",
|
||||
"sales_qty_180d": "sales_qty_180d",
|
||||
"sales_usd_90d": "sales_usd_90d",
|
||||
"sales_usd_180d": "sales_usd_180d",
|
||||
"stock_days_90d": "stock_days_90d",
|
||||
"stock_days_180d": "stock_days_180d",
|
||||
"avg_price_usd_90d": "avg_price_usd_90d",
|
||||
"avg_price_usd_180d": "avg_price_usd_180d",
|
||||
"base_price_usd": "base_price_usd",
|
||||
"cost_price_usd": "cost_price_usd",
|
||||
"unit_profit_base_90d": "unit_profit_base_90d",
|
||||
"unit_profit_cost_90d": "unit_profit_cost_90d",
|
||||
"unit_profit_base_180d": "unit_profit_base_180d",
|
||||
"unit_profit_cost_180d": "unit_profit_cost_180d",
|
||||
"gross_margin_base_90d": "(CASE WHEN COALESCE(sales_usd_90d,0) <= 0 THEN 0 ELSE (sales_usd_90d - (sales_qty_90d * COALESCE(base_price_usd,0))) / NULLIF(sales_usd_90d,0) END)",
|
||||
"gross_margin_cost_90d": "gross_margin_90d",
|
||||
"gross_margin_base_180d": "(CASE WHEN COALESCE(sales_usd_180d,0) <= 0 THEN 0 ELSE (sales_usd_180d - (sales_qty_180d * COALESCE(base_price_usd,0))) / NULLIF(sales_usd_180d,0) END)",
|
||||
"gross_margin_cost_180d": "gross_margin_180d",
|
||||
"gross_margin_90d": "gross_margin_90d",
|
||||
"gross_margin_180d": "gross_margin_180d",
|
||||
"market_count_90d": "market_count_90d",
|
||||
"customer_count_90d": "customer_count_90d",
|
||||
"sales_index_90d": "sales_index_90d",
|
||||
"performance_score": "performance_score",
|
||||
"performance_bucket": "performance_bucket",
|
||||
"last_sale_date": "last_sale_date",
|
||||
}
|
||||
col := allowed[strings.TrimSpace(sortBy)]
|
||||
if col == "" {
|
||||
|
||||
@@ -216,10 +216,11 @@ func productPerformanceStockSQL() string {
|
||||
;WITH ActiveWarehouses AS (
|
||||
SELECT WarehouseCode
|
||||
FROM (VALUES
|
||||
('1-0-14'),('1-0-10'),('1-0-8'),('1-2-5'),('1-2-4'),('1-0-12'),
|
||||
('100'),('1-0-28'),('1-0-24'),('1-2-6'),('1-1-14'),('1-0-2'),
|
||||
('1-0-52'),('1-1-2'),('1-0-21'),('1-1-3'),('1-0-33'),('101'),
|
||||
('1-014'),('1-0-49'),('1-0-36')
|
||||
('1-0-12'),('1.01.2014'),('1.02.2005'),('1.02.2004'),('1-0-43'),
|
||||
('4.02.2001'),('1-0-55'),('1.01.2003'),('1-0-21'),('1-0-2'),
|
||||
('1.01.2004'),('1-0-49'),('1-0-37'),('1-0-29'),('1-0-28'),
|
||||
('1-0-10'),('100'),('1.02.2006'),('1-0-42'),('1.01.2002'),
|
||||
('1-0-52')
|
||||
) W(WarehouseCode)
|
||||
),
|
||||
Raw AS (
|
||||
|
||||
Reference in New Issue
Block a user