product performance grouped kpi improvements
This commit is contained in:
@@ -2921,7 +2921,7 @@ SELECT jsonb_build_object(
|
||||
) AS row_json
|
||||
FROM (
|
||||
SELECT
|
||||
COALESCE(NULLIF(%s,''), '-') AS group_value,
|
||||
COALESCE(%s, '') AS group_value,
|
||||
COUNT(*)::integer AS row_count,
|
||||
(ARRAY_AGG(product_code ORDER BY performance_score DESC NULLS LAST))[1] AS image_product_code,
|
||||
(ARRAY_AGG(color_code ORDER BY performance_score DESC NULLS LAST))[1] AS image_color_code,
|
||||
@@ -2945,36 +2945,36 @@ FROM (
|
||||
COALESCE(SUM(sales_usd_365d),0) AS sales_usd_365d,
|
||||
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 AVG(cost_price_usd) END AS cost_price_usd,
|
||||
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 base_price_usd * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE AVG(base_price_usd) END AS base_price_usd,
|
||||
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 base_price_try * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE AVG(base_price_try) END AS base_price_try,
|
||||
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,
|
||||
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 base_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 base_price_usd,
|
||||
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 base_price_try * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE 0 END AS base_price_try,
|
||||
COALESCE(SUM(gross_profit_usd_90d),0) AS gross_profit_usd_90d,
|
||||
COALESCE(SUM(gross_profit_usd_180d),0) AS gross_profit_usd_180d,
|
||||
CASE WHEN SUM(sales_usd_90d) > 0 THEN SUM(gross_profit_usd_90d) / NULLIF(SUM(sales_usd_90d),0) ELSE 0 END AS gross_margin_90d,
|
||||
CASE WHEN SUM(sales_usd_180d) > 0 THEN SUM(gross_profit_usd_180d) / NULLIF(SUM(sales_usd_180d),0) ELSE 0 END AS gross_margin_180d,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(unit_profit_cost_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(unit_profit_cost_90d) END AS unit_profit_cost_90d,
|
||||
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(unit_profit_cost_180d * sales_qty_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE AVG(unit_profit_cost_180d) END AS unit_profit_cost_180d,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(unit_profit_base_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(unit_profit_base_90d) 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 AVG(unit_profit_base_180d) END AS unit_profit_base_180d,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(unit_profit_cost_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS unit_profit_cost_90d,
|
||||
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(unit_profit_cost_180d * sales_qty_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE 0 END AS unit_profit_cost_180d,
|
||||
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,
|
||||
COALESCE(SUM(market_count_90d),0)::integer AS market_count_90d,
|
||||
COALESCE(SUM(customer_count_90d),0)::integer AS customer_count_90d,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(sales_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(sales_index_90d) END AS sales_index_90d,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(price_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(price_index_90d) 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 AVG(margin_index_90d) END AS margin_index_90d,
|
||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(performance_score * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(performance_score) END AS performance_score,
|
||||
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_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 WHEN SUM(sales_qty_90d) > 0 THEN SUM(performance_score * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS performance_score,
|
||||
MODE() WITHIN GROUP (ORDER BY performance_bucket) AS performance_bucket,
|
||||
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN idle_cost_usd ELSE 0 END),0) AS idle_cost_usd
|
||||
FROM (
|
||||
SELECT
|
||||
Source.*,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY COALESCE(NULLIF(%s,''), '-'), product_code, color_code, yaka_kodu
|
||||
PARTITION BY COALESCE(%s, ''), product_code, color_code, yaka_kodu
|
||||
ORDER BY performance_score DESC NULLS LAST
|
||||
) AS stock_variant_rank
|
||||
FROM Source
|
||||
%s
|
||||
) s
|
||||
GROUP BY COALESCE(NULLIF(%s,''), '-')
|
||||
GROUP BY COALESCE(%s, '')
|
||||
) g
|
||||
ORDER BY group_value
|
||||
`, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, groupExpr, groupExpr, whereSQL, groupExpr)
|
||||
@@ -3107,7 +3107,7 @@ func productPerformanceSQLFilterWhere(filters []productPerformanceSQLGroupFilter
|
||||
return "", nil, fmt.Errorf("unsupported product performance filter field: %s", filter.Field)
|
||||
}
|
||||
args = append(args, normalizeProductPerformanceGroupValue(filter.Value))
|
||||
parts = append(parts, fmt.Sprintf("COALESCE(NULLIF(%s,''), '-') = $%d", expr, len(args)))
|
||||
parts = append(parts, fmt.Sprintf("COALESCE(%s, '') = $%d", expr, len(args)))
|
||||
}
|
||||
return "WHERE " + strings.Join(parts, " AND "), args, nil
|
||||
}
|
||||
@@ -3310,17 +3310,8 @@ func distinctProductPerformanceVariantStockCost(rows []map[string]any) float64 {
|
||||
|
||||
func productPerformanceMapVariantKey(row map[string]any) string {
|
||||
productCode := stringFromMap(row, "product_code")
|
||||
if productCode == "" {
|
||||
productCode = stringFromMap(row, "image_product_code")
|
||||
}
|
||||
colorCode := stringFromMap(row, "color_code")
|
||||
if colorCode == "" {
|
||||
colorCode = stringFromMap(row, "image_color_code")
|
||||
}
|
||||
yakaKodu := stringFromMap(row, "yaka_kodu")
|
||||
if yakaKodu == "" {
|
||||
yakaKodu = stringFromMap(row, "image_yaka_kodu")
|
||||
}
|
||||
if productCode == "" && colorCode == "" && yakaKodu == "" {
|
||||
return ""
|
||||
}
|
||||
@@ -3391,9 +3382,6 @@ func isProductPerformanceCustomerGroup(groupField string) bool {
|
||||
func productPerformanceSalesGroupScore(row map[string]any) float64 {
|
||||
salesIndex := floatFromMap(row, "sales_index_90d")
|
||||
margin := floatFromMap(row, "gross_margin_cost_90d")
|
||||
if margin == 0 {
|
||||
margin = floatFromMap(row, "gross_margin_90d")
|
||||
}
|
||||
invoiceCount := floatFromMap(row, "invoice_count_90d")
|
||||
salesQty := floatFromMap(row, "sales_qty_90d")
|
||||
stockTurnover := floatFromMap(row, "stock_turnover_90d")
|
||||
@@ -3435,9 +3423,6 @@ func productPerformanceCustomerSalesGroupScore(row map[string]any) float64 {
|
||||
func productPerformanceCustomerSalesPeriodScore(row map[string]any) float64 {
|
||||
salesUSD := floatFromMap(row, "sales_usd")
|
||||
margin := floatFromMap(row, "gross_margin_cost")
|
||||
if margin == 0 {
|
||||
margin = floatFromMap(row, "gross_margin")
|
||||
}
|
||||
invoiceCount := floatFromMap(row, "invoice_count")
|
||||
salesQty := floatFromMap(row, "sales_qty")
|
||||
productCount := floatFromMap(row, "product_count")
|
||||
@@ -3589,8 +3574,7 @@ func productPerformanceMetricWeightField(field string) string {
|
||||
}
|
||||
|
||||
func weightedAverageProductPerformanceRows(rows []map[string]any, valueField, qtyField string) float64 {
|
||||
var weighted, qty, sum float64
|
||||
var count int
|
||||
var weighted, qty float64
|
||||
for _, row := range rows {
|
||||
value := floatFromMap(row, valueField)
|
||||
weight := floatFromMap(row, qtyField)
|
||||
@@ -3598,17 +3582,10 @@ func weightedAverageProductPerformanceRows(rows []map[string]any, valueField, qt
|
||||
weighted += value * weight
|
||||
qty += weight
|
||||
}
|
||||
if value != 0 {
|
||||
sum += value
|
||||
count++
|
||||
}
|
||||
}
|
||||
if qty > 0 {
|
||||
return weighted / qty
|
||||
}
|
||||
if count > 0 {
|
||||
return sum / float64(count)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -3667,11 +3644,7 @@ func cloneMap(row map[string]any) map[string]any {
|
||||
}
|
||||
|
||||
func normalizeProductPerformanceGroupValue(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return "-"
|
||||
}
|
||||
return value
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
|
||||
func displayProductPerformanceMarketName(value string) string {
|
||||
@@ -3926,9 +3899,9 @@ func productPerformanceOrderBy(sortBy string, desc bool) string {
|
||||
"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_cost_90d": "(CASE WHEN COALESCE(sales_usd_90d,0) <= 0 THEN 0 ELSE (sales_usd_90d - (sales_qty_90d * COALESCE(cost_price_usd,0))) / NULLIF(sales_usd_90d,0) END)",
|
||||
"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_cost_180d": "(CASE WHEN COALESCE(sales_usd_180d,0) <= 0 THEN 0 ELSE (sales_usd_180d - (sales_qty_180d * COALESCE(cost_price_usd,0))) / NULLIF(sales_usd_180d,0) END)",
|
||||
"gross_margin_90d": "gross_margin_90d",
|
||||
"gross_margin_180d": "gross_margin_180d",
|
||||
"market_count_90d": "market_count_90d",
|
||||
|
||||
Reference in New Issue
Block a user