Fix product performance grouped JSON build

This commit is contained in:
M_Kececi
2026-07-06 17:01:39 +03:00
parent 5d4216d42e
commit 1448dab9d7
2 changed files with 79 additions and 27 deletions
+66 -14
View File
@@ -51,6 +51,10 @@ type productPerformanceExcelVariant struct {
UrunAnaGrubu string
UrunAltGrubu string
StockQty float64
AvgStock90 float64
AvgStock180 float64
AvgStock365 float64
AvgStockTotal float64
BasePriceUSD float64
CostPriceUSD float64
@@ -188,6 +192,10 @@ func (v *productPerformanceExcelVariant) addProductRow(row models.ProductPerform
v.SalesUSD90 += row.SalesUSD90
v.SalesUSD180 += row.SalesUSD180
v.SalesUSD365 += row.SalesUSD365
v.AvgStock90 = productPerformanceExcelFirstNonZero(v.AvgStock90, row.AvgStock90)
v.AvgStock180 = productPerformanceExcelFirstNonZero(v.AvgStock180, row.AvgStock180)
v.AvgStock365 = productPerformanceExcelFirstNonZero(v.AvgStock365, row.AvgStock365)
v.AvgStockTotal = productPerformanceExcelFirstNonZero(v.AvgStockTotal, row.AvgStockTotal)
v.SalesQtyTotalProduct += row.SalesQtyTotal
v.SalesUSDTotalProduct += row.SalesUSDTotal
v.MarketCount90 = productPerformanceExcelMaxInt(v.MarketCount90, row.MarketCount90)
@@ -407,9 +415,9 @@ func productPerformanceExcelPeriodColumns(label, suffix string, values func(*pro
qty, usd, _, _ := values(v)
return productPerformanceExcelAvgPrice(usd, qty)
}),
numberExcelColumn(label+" Stok Devir Hızı", "number", func(v *productPerformanceExcelVariant) any {
numberExcelColumn(label+" Yıllık Stok Devir", "number", func(v *productPerformanceExcelVariant) any {
qty, _, _, _ := values(v)
return productPerformanceExcelStockTurnover(qty, v.StockQty)
return productPerformanceExcelStockTurnover(qty, productPerformanceExcelAvgStock(v, suffix), productPerformanceExcelPeriodDays(v, suffix))
}),
numberExcelColumn(label+" Taban Maliyet USD", "number", func(v *productPerformanceExcelVariant) any { return v.BasePriceUSD }),
numberExcelColumn(label+" Çıplak Maliyet USD", "number", func(v *productPerformanceExcelVariant) any { return v.CostPriceUSD }),
@@ -439,7 +447,7 @@ func productPerformanceExcelPeriodColumns(label, suffix string, values func(*pro
}),
numberExcelColumn(label+" Ürün Skor", "number", func(v *productPerformanceExcelVariant) any {
qty, usd, markets, customers := values(v)
return productPerformanceExcelProductScore(suffix, usd, productPerformanceExcelStockTurnover(qty, v.StockQty), float64(markets), float64(customers), productPerformanceExcelMargin(usd, qty, v.CostPriceUSD))
return productPerformanceExcelProductScore(suffix, usd, productPerformanceExcelStockTurnover(qty, productPerformanceExcelAvgStock(v, suffix), productPerformanceExcelPeriodDays(v, suffix)), float64(markets), float64(customers), productPerformanceExcelMargin(usd, qty, v.CostPriceUSD))
}),
}
}
@@ -657,13 +665,13 @@ func productPerformanceExcelSortNumber(row *productPerformanceExcelVariant, sort
case "avg_price_usd_total":
return productPerformanceExcelAvgPrice(row.totalUSD(), row.totalQty())
case "stock_turnover_90d":
return productPerformanceExcelStockTurnover(row.SalesQty90, row.StockQty)
return productPerformanceExcelStockTurnover(row.SalesQty90, productPerformanceExcelAvgStock(row, "90d"), productPerformanceExcelPeriodDays(row, "90d"))
case "stock_turnover_180d":
return productPerformanceExcelStockTurnover(row.SalesQty180, row.StockQty)
return productPerformanceExcelStockTurnover(row.SalesQty180, productPerformanceExcelAvgStock(row, "180d"), productPerformanceExcelPeriodDays(row, "180d"))
case "stock_turnover_365d":
return productPerformanceExcelStockTurnover(row.SalesQty365, row.StockQty)
return productPerformanceExcelStockTurnover(row.SalesQty365, productPerformanceExcelAvgStock(row, "365d"), productPerformanceExcelPeriodDays(row, "365d"))
case "stock_turnover_total":
return productPerformanceExcelStockTurnover(row.totalQty(), row.StockQty)
return productPerformanceExcelStockTurnover(row.totalQty(), productPerformanceExcelAvgStock(row, "total"), productPerformanceExcelPeriodDays(row, "total"))
case "base_price_usd":
return row.BasePriceUSD
case "cost_price_usd":
@@ -677,9 +685,9 @@ func productPerformanceExcelSortNumber(row *productPerformanceExcelVariant, sort
case "customer_count_total":
return float64(row.CustomerCountTotal)
case "performance_score", "performance_score_90d":
return productPerformanceExcelProductScore("90d", row.SalesUSD90, productPerformanceExcelStockTurnover(row.SalesQty90, row.StockQty), float64(row.marketCount90()), float64(row.CustomerCount90), productPerformanceExcelMargin(row.SalesUSD90, row.SalesQty90, row.CostPriceUSD))
return productPerformanceExcelProductScore("90d", row.SalesUSD90, productPerformanceExcelStockTurnover(row.SalesQty90, productPerformanceExcelAvgStock(row, "90d"), productPerformanceExcelPeriodDays(row, "90d")), float64(row.marketCount90()), float64(row.CustomerCount90), productPerformanceExcelMargin(row.SalesUSD90, row.SalesQty90, row.CostPriceUSD))
case "performance_score_total":
return productPerformanceExcelProductScore("total", row.totalUSD(), productPerformanceExcelStockTurnover(row.totalQty(), row.StockQty), float64(row.marketCountTotal()), float64(row.CustomerCountTotal), productPerformanceExcelMargin(row.totalUSD(), row.totalQty(), row.CostPriceUSD))
return productPerformanceExcelProductScore("total", row.totalUSD(), productPerformanceExcelStockTurnover(row.totalQty(), productPerformanceExcelAvgStock(row, "total"), productPerformanceExcelPeriodDays(row, "total")), float64(row.marketCountTotal()), float64(row.CustomerCountTotal), productPerformanceExcelMargin(row.totalUSD(), row.totalQty(), row.CostPriceUSD))
default:
return 0
}
@@ -795,7 +803,7 @@ func productPerformanceExcelStatus(row *productPerformanceExcelVariant) string {
return "Stok Riski"
case productPerformanceExcelMargin(row.totalUSD(), row.totalQty(), row.CostPriceUSD) < 0:
return "Fiyat Baskısı"
case productPerformanceExcelProductScore("total", row.totalUSD(), productPerformanceExcelStockTurnover(row.totalQty(), row.StockQty), float64(row.marketCountTotal()), float64(row.CustomerCountTotal), productPerformanceExcelMargin(row.totalUSD(), row.totalQty(), row.CostPriceUSD)) >= 70:
case productPerformanceExcelProductScore("total", row.totalUSD(), productPerformanceExcelStockTurnover(row.totalQty(), productPerformanceExcelAvgStock(row, "total"), productPerformanceExcelPeriodDays(row, "total")), float64(row.marketCountTotal()), float64(row.CustomerCountTotal), productPerformanceExcelMargin(row.totalUSD(), row.totalQty(), row.CostPriceUSD)) >= 70:
return "Yıldız Ürün"
default:
return productPerformanceExcelBucketLabel(row.PerformanceBucket)
@@ -881,11 +889,55 @@ func productPerformanceExcelAvgPrice(salesUSD, qty float64) float64 {
return salesUSD / qty
}
func productPerformanceExcelStockTurnover(salesQty, stockQty float64) float64 {
if stockQty <= 0 {
const productPerformanceExcelStockTurnoverYearDays = 360.0
func productPerformanceExcelAvgStock(row *productPerformanceExcelVariant, suffix string) float64 {
switch suffix {
case "90d":
return productPerformanceExcelFirstNonZero(row.AvgStock90, row.StockQty)
case "180d":
return productPerformanceExcelFirstNonZero(row.AvgStock180, row.StockQty)
case "365d":
return productPerformanceExcelFirstNonZero(row.AvgStock365, row.StockQty)
case "total":
return productPerformanceExcelFirstNonZero(row.AvgStockTotal, row.StockQty)
default:
return row.StockQty
}
}
func productPerformanceExcelPeriodDays(row *productPerformanceExcelVariant, suffix string) float64 {
switch suffix {
case "90d":
return 90
case "180d":
return 180
case "365d":
return 360
case "total":
end, err := time.Parse("2006-01-02", strings.TrimSpace(row.KpiDate))
if err != nil {
return 0
}
start := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
if end.Before(start) {
return 0
}
return end.Sub(start).Hours()/24 + 1
default:
return 0
}
return salesQty / stockQty
}
func productPerformanceExcelStockTurnover(salesQty, avgStock, periodDays float64) float64 {
if salesQty <= 0 || avgStock <= 0 {
return 0
}
raw := salesQty / avgStock
if periodDays <= 0 {
return raw
}
return raw * productPerformanceExcelStockTurnoverYearDays / periodDays
}
func productPerformanceExcelGrossProfit(salesUSD, qty, unitCost float64) float64 {
@@ -908,7 +960,7 @@ func productPerformanceExcelProductScore(suffix string, salesUSD, stockTurnover,
}
revenueScore := productPerformanceExcelRatioScore(salesUSD, productPerformanceExcelProductRevenueTarget(suffix))
score := 0.30*productPerformanceExcelMarginScore(margin) +
0.20*productPerformanceExcelRatioScore(stockTurnover, 1.50) +
0.20*productPerformanceExcelRatioScore(stockTurnover, 4) +
0.20*revenueScore +
0.15*productPerformanceExcelRatioScore(marketCount, 8) +
0.15*productPerformanceExcelRatioScore(customerCount, 25)