Fix product performance grouped JSON build

This commit is contained in:
M_Kececi
2026-07-07 01:21:07 +03:00
parent 289f204752
commit 005d2eafac
3 changed files with 65 additions and 49 deletions
+38 -20
View File
@@ -4361,7 +4361,11 @@ func listProductPerformanceGroupedSQL(ctx context.Context, pg *sql.DB, req Produ
out := make([]map[string]any, 0, 512)
filters := productPerformanceGroupedBaseFilters(req)
err := appendProductPerformanceGroupedSQLRows(ctx, pg, &out, mode, levels, 0, 0, []string{"tab:" + mode}, filters, req.ExpandedKeys, req.ExpandThroughLevel, req.Limit)
return out, true, err
if err != nil {
return out, true, err
}
out = sortProductPerformancePreparedGroupedRows(out, req.SortBy, req.Descending)
return out, true, nil
}
func productPerformanceGroupedBaseFilters(req ProductPerformanceGroupedRequest) []productPerformanceSQLGroupFilter {
@@ -4439,6 +4443,7 @@ func appendProductPerformanceGroupedSQLRows(ctx context.Context, pg *sql.DB, out
row["label"] = value
row["__group"] = true
row[field] = value
deriveProductPerformanceGroupMetrics(row, field)
*out = append(*out, row)
if expandedKeys[key] || level <= expandThroughLevel {
nextFilters := append(append([]productPerformanceSQLGroupFilter{}, filters...), productPerformanceSQLGroupFilter{Field: field, Value: value})
@@ -4464,6 +4469,8 @@ SELECT (
jsonb_build_object(
'group_value', group_value,
'label', group_value,
'period_start', '2022-01-01',
'period_end', COALESCE(to_char((SELECT kpi_date FROM LatestKPIDate),'YYYY-MM-DD'), ''),
'count', row_count,
'recommendation', CASE WHEN recommendation <> '' THEN recommendation ELSE row_count::text || ' satir' END,
'image_product_code', image_product_code,
@@ -4482,6 +4489,10 @@ SELECT (
)
|| jsonb_build_object(
'stock_qty', stock_qty,
'avg_stock_90d', avg_stock_90d,
'avg_stock_180d', avg_stock_180d,
'avg_stock_365d', avg_stock_365d,
'avg_stock_total', avg_stock_total,
'sales_qty_90d', sales_qty_90d,
'sales_qty_180d', sales_qty_180d,
'sales_qty_365d', sales_qty_365d,
@@ -4506,8 +4517,17 @@ SELECT (
'unit_profit_base_90d', unit_profit_base_90d,
'unit_profit_base_180d', unit_profit_base_180d,
'market_count_90d', market_count_90d,
'market_count_180d', market_count_180d,
'market_count_365d', market_count_365d,
'market_count_total', market_count_total,
'customer_count_90d', customer_count_90d,
'customer_count_180d', customer_count_180d,
'customer_count_365d', customer_count_365d,
'customer_count_total', customer_count_total,
'sales_index_90d', sales_index_90d,
'sales_index_180d', sales_index_180d,
'sales_index_365d', sales_index_365d,
'sales_index_total', sales_index_total,
'price_index_90d', price_index_90d,
'margin_index_90d', margin_index_90d,
'performance_score', performance_score,
@@ -4586,8 +4606,17 @@ FROM (
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(unit_profit_base_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS unit_profit_base_90d,
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(unit_profit_base_180d * sales_qty_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE 0 END AS unit_profit_base_180d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE COALESCE(sales_usd_90d,0) > 0)::integer AS market_count_90d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE COALESCE(sales_usd_180d,0) > 0)::integer AS market_count_180d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE COALESCE(sales_usd_365d,0) > 0)::integer AS market_count_365d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE COALESCE(sales_usd_total,0) > 0)::integer AS market_count_total,
COALESCE(SUM(CASE WHEN COALESCE(sales_usd_90d,0) > 0 THEN customer_count_90d ELSE 0 END),0)::integer AS customer_count_90d,
COALESCE(SUM(CASE WHEN COALESCE(sales_usd_180d,0) > 0 THEN customer_count_180d ELSE 0 END),0)::integer AS customer_count_180d,
COALESCE(SUM(CASE WHEN COALESCE(sales_usd_365d,0) > 0 THEN customer_count_365d ELSE 0 END),0)::integer AS customer_count_365d,
COALESCE(SUM(CASE WHEN COALESCE(sales_usd_total,0) > 0 THEN customer_count_total ELSE 0 END),0)::integer AS customer_count_total,
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(sales_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS sales_index_90d,
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(sales_index_180d * sales_qty_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE 0 END AS sales_index_180d,
CASE WHEN SUM(sales_qty_365d) > 0 THEN SUM(sales_index_365d * sales_qty_365d) / NULLIF(SUM(sales_qty_365d),0) ELSE 0 END AS sales_index_365d,
CASE WHEN SUM(sales_qty_total) > 0 THEN SUM(sales_index_total * sales_qty_total) / NULLIF(SUM(sales_qty_total),0) ELSE 0 END AS sales_index_total,
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(price_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS price_index_90d,
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(margin_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS margin_index_90d,
CASE
@@ -5966,15 +5995,8 @@ func productPerformanceMapVariantKey(row map[string]any) string {
func deriveProductPerformanceGroupMetrics(out map[string]any, groupField string) {
normalizeProductPerformanceCostFields(out)
preservedPerformanceScores := map[string]float64{}
if score, ok := productPerformanceOptionalFloat(out, "performance_score"); ok {
preservedPerformanceScores["90d"] = score
}
preservedCustomerScores := map[string]float64{}
for _, suffix := range productPerformancePeriodSuffixes() {
if score, ok := productPerformanceOptionalFloat(out, "performance_score_"+suffix); ok {
preservedPerformanceScores[suffix] = score
}
if score, ok := productPerformanceOptionalFloat(out, "customer_score_"+suffix); ok {
preservedCustomerScores[suffix] = score
}
@@ -6058,11 +6080,7 @@ func deriveProductPerformanceGroupMetrics(out map[string]any, groupField string)
} else {
out["customer_score_"+suffix] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, suffix))
}
if score, ok := preservedPerformanceScores[suffix]; ok {
out["performance_score_"+suffix] = score
} else {
out["performance_score_"+suffix] = productPerformanceSalesPeriodScore(out, suffix)
}
out["performance_score_"+suffix] = productPerformanceSalesPeriodScore(out, suffix)
}
out["performance_score"] = out["performance_score_90d"]
if floatFromMap(out, "order_qty") > 0 || floatFromMap(out, "order_usd") > 0 {
@@ -6282,8 +6300,8 @@ func productPerformanceProductScore(suffix string, salesUSD, salesIndex, margin,
score := 0.30*productPerformanceMarginComponentScore(margin) +
0.20*productPerformanceRatioScore(stockTurnover, productPerformanceStockTurnoverTarget(suffix)) +
0.20*revenueScore +
0.15*productPerformanceRatioScore(marketCount, productPerformanceMarketSpreadTarget(suffix)) +
0.15*productPerformanceRatioScore(customerCount, productPerformanceCustomerSpreadTarget(suffix))
0.05*productPerformanceRatioScore(marketCount, productPerformanceMarketSpreadTarget(suffix)) +
0.25*productPerformanceRatioScore(customerCount, productPerformanceCustomerSpreadTarget(suffix))
return productPerformanceRoundScore(score)
}
@@ -6296,11 +6314,11 @@ func productPerformanceMarketSpreadTarget(suffix string) float64 {
case "90d":
return 3
case "180d":
return 5
return 3
case "365d":
return 6
default:
return 8
return 6
}
}
@@ -6309,11 +6327,11 @@ func productPerformanceCustomerSpreadTarget(suffix string) float64 {
case "90d":
return 8
case "180d":
return 15
return 20
case "365d":
return 18
return 50
default:
return 25
return 50
}
}