Fix product performance grouped JSON build
This commit is contained in:
@@ -4677,25 +4677,16 @@ FROM (
|
||||
CASE
|
||||
WHEN SUM(CASE
|
||||
WHEN COALESCE(sales_qty_90d,0) > 0 THEN sales_qty_90d
|
||||
WHEN COALESCE(sales_usd_90d,0) > 0 THEN sales_usd_90d
|
||||
WHEN COALESCE(stock_qty,0) > 0 AND COALESCE(cost_price_usd,0) > 0 THEN stock_qty * cost_price_usd
|
||||
WHEN COALESCE(stock_qty,0) > 0 THEN stock_qty
|
||||
ELSE 1
|
||||
ELSE 0
|
||||
END) > 0
|
||||
THEN SUM(performance_score * CASE
|
||||
WHEN COALESCE(sales_qty_90d,0) > 0 THEN sales_qty_90d
|
||||
WHEN COALESCE(sales_usd_90d,0) > 0 THEN sales_usd_90d
|
||||
WHEN COALESCE(stock_qty,0) > 0 AND COALESCE(cost_price_usd,0) > 0 THEN stock_qty * cost_price_usd
|
||||
WHEN COALESCE(stock_qty,0) > 0 THEN stock_qty
|
||||
ELSE 1
|
||||
ELSE 0
|
||||
END) / NULLIF(SUM(CASE
|
||||
WHEN COALESCE(sales_qty_90d,0) > 0 THEN sales_qty_90d
|
||||
WHEN COALESCE(sales_usd_90d,0) > 0 THEN sales_usd_90d
|
||||
WHEN COALESCE(stock_qty,0) > 0 AND COALESCE(cost_price_usd,0) > 0 THEN stock_qty * cost_price_usd
|
||||
WHEN COALESCE(stock_qty,0) > 0 THEN stock_qty
|
||||
ELSE 1
|
||||
ELSE 0
|
||||
END),0)
|
||||
ELSE 0
|
||||
ELSE COALESCE(AVG(performance_score),0)
|
||||
END AS performance_score,
|
||||
MODE() WITHIN GROUP (ORDER BY performance_bucket) AS performance_bucket,
|
||||
COALESCE(MODE() WITHIN GROUP (ORDER BY NULLIF(recommendation,'')), '') AS recommendation,
|
||||
@@ -6841,20 +6832,7 @@ func productPerformanceScoreWeight(row map[string]any, suffix string) float64 {
|
||||
if weight := floatFromMap(row, "sales_qty_"+suffix); weight > 0 {
|
||||
return weight
|
||||
}
|
||||
if weight := floatFromMap(row, "sales_usd_"+suffix); weight > 0 {
|
||||
return weight
|
||||
}
|
||||
stockQty := floatFromMap(row, "stock_qty")
|
||||
if stockQty <= 0 {
|
||||
return 1
|
||||
}
|
||||
if cost := floatFromMap(row, "cost_price_usd_"+suffix); cost > 0 {
|
||||
return stockQty * cost
|
||||
}
|
||||
if cost := floatFromMap(row, "cost_price_usd"); cost > 0 {
|
||||
return stockQty * cost
|
||||
}
|
||||
return stockQty
|
||||
return 0
|
||||
}
|
||||
|
||||
func productPerformanceCostWeight(row map[string]any) float64 {
|
||||
|
||||
@@ -4011,12 +4011,7 @@ function scoreSuffixForMetric (field) {
|
||||
function scoreWeight (row, suffix) {
|
||||
const salesQty = Number(row?.[`sales_qty_${suffix}`] || 0)
|
||||
if (salesQty > 0) return salesQty
|
||||
const salesUsd = Number(row?.[`sales_usd_${suffix}`] || 0)
|
||||
if (salesUsd > 0) return salesUsd
|
||||
const stockQty = Number(row?.stock_qty || 0)
|
||||
if (stockQty <= 0) return 1
|
||||
const costPrice = Number(row?.[`cost_price_usd_${suffix}`] || row?.cost_price_usd || 0)
|
||||
return costPrice > 0 ? stockQty * costPrice : stockQty
|
||||
return 0
|
||||
}
|
||||
|
||||
function weightedAverageScore (sourceRows, valueField, suffix) {
|
||||
@@ -4256,10 +4251,10 @@ function withProductMargins (row) {
|
||||
const out = {
|
||||
...next,
|
||||
avg_price_usd_365d: Number(next?.sales_qty_365d || 0) > 0 ? Number(next?.sales_usd_365d || 0) / Number(next?.sales_qty_365d || 0) : 0,
|
||||
stock_turnover_90d: existingOrStockTurnover(next?.stock_turnover_90d, next?.sales_qty_90d, next?.avg_stock_90d || next?.stock_qty, 90),
|
||||
stock_turnover_180d: existingOrStockTurnover(next?.stock_turnover_180d, next?.sales_qty_180d, next?.avg_stock_180d || next?.stock_qty, 180),
|
||||
stock_turnover_365d: existingOrStockTurnover(next?.stock_turnover_365d, next?.sales_qty_365d, next?.avg_stock_365d || next?.stock_qty, 360),
|
||||
stock_turnover_total: existingOrStockTurnover(next?.stock_turnover_total, next?.sales_qty_total, next?.avg_stock_total || next?.stock_qty, productPerformancePeriodDays(next, 'total'))
|
||||
stock_turnover_90d: groupedOrExistingStockTurnover(next, '90d', 90),
|
||||
stock_turnover_180d: groupedOrExistingStockTurnover(next, '180d', 180),
|
||||
stock_turnover_365d: groupedOrExistingStockTurnover(next, '365d', 360),
|
||||
stock_turnover_total: groupedOrExistingStockTurnover(next, 'total', productPerformancePeriodDays(next, 'total'))
|
||||
}
|
||||
for (const suffix of ['90d', '180d', '365d', 'total']) {
|
||||
applyPeriodProfitFields(out, suffix)
|
||||
@@ -4272,7 +4267,7 @@ function withGeneralMargins (row) {
|
||||
applyPeriodProfitFields(out, 'total')
|
||||
return {
|
||||
...out,
|
||||
stock_turnover_total: existingOrStockTurnover(out?.stock_turnover_total, out?.sales_qty_total, out?.avg_stock_total || out?.stock_qty, productPerformancePeriodDays(out, 'total'))
|
||||
stock_turnover_total: groupedOrExistingStockTurnover(out, 'total', productPerformancePeriodDays(out, 'total'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4348,6 +4343,15 @@ function existingOrStockTurnover (value, salesQty, stockQty, periodDays) {
|
||||
return value !== undefined && value !== null && Number.isFinite(current) ? current : stockTurnover(salesQty, stockQty, periodDays)
|
||||
}
|
||||
|
||||
function groupedOrExistingStockTurnover (row, suffix, periodDays) {
|
||||
const stockBase = Number(row?.[`avg_stock_${suffix}`] || row?.stock_qty || 0)
|
||||
const salesQty = Number(row?.[`sales_qty_${suffix}`] || 0)
|
||||
if (row?.__group) {
|
||||
return stockTurnover(salesQty, stockBase, periodDays)
|
||||
}
|
||||
return existingOrStockTurnover(row?.[`stock_turnover_${suffix}`], salesQty, stockBase, periodDays)
|
||||
}
|
||||
|
||||
function filterKey (tableKey, name) {
|
||||
return `${tableKey}:${name}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user