Fix product performance grouped JSON build

This commit is contained in:
M_Kececi
2026-07-05 22:06:43 +03:00
parent fbdde54eee
commit 9e1ecb9b3f
5 changed files with 766 additions and 564 deletions
+58 -59
View File
@@ -1978,7 +1978,7 @@ SalesAgg AS (
MAX(last_ref_number) AS last_ref_number,
COALESCE(SUM(sales_qty),0) AS sales_qty_total,
COALESCE(SUM(sales_usd),0) AS sales_usd_total,
COALESCE(COUNT(DISTINCT NULLIF(customer_code, '-')),0)::integer AS customer_count_total,
COALESCE(COUNT(DISTINCT NULLIF(customer_code, '-')) FILTER (WHERE COALESCE(sales_usd,0) > 0),0)::integer AS customer_count_total,
COALESCE(SUM(invoice_count),0)::integer AS invoice_count_total
FROM mk_product_performance_sales_daily, Bounds
WHERE sales_date BETWEEN Bounds.period_start AND Bounds.period_end
@@ -2102,8 +2102,8 @@ Spread AS (
product_code,
color_code,
yaka_kodu,
COUNT(DISTINCT NULLIF(market_key, 'STOK'))::integer AS market_count_total,
COUNT(DISTINCT NULLIF(customer_code, '-'))::integer AS customer_count_total_all
COUNT(DISTINCT NULLIF(market_key, 'STOK')) FILTER (WHERE COALESCE(sales_usd,0) > 0)::integer AS market_count_total,
COUNT(DISTINCT NULLIF(customer_code, '-')) FILTER (WHERE COALESCE(sales_usd,0) > 0)::integer AS customer_count_total_all
FROM mk_product_performance_sales_daily, Bounds
WHERE sales_date BETWEEN Bounds.period_start AND Bounds.period_end
AND upper(translate(btrim(COALESCE(urun_ilk_grubu,'')), U&'\0130\015E\011E\00DC\00D6\00C7\0131\015F\011F\00FC\00F6\00E7', 'ISGUOCisguoc')) NOT IN ('MALZEMELI FASON', 'MALZEMESIZ FASON', 'MAZLEMELI FASON', 'MAZEMESIZ FASON', 'DIGER')
@@ -2140,8 +2140,8 @@ Scored AS (
CASE WHEN b.sales_usd_total <= 0 THEN 0 ELSE (b.sales_usd_total - (b.sales_qty_total * COALESCE(pd.cost_price_usd,0))) / NULLIF(b.sales_usd_total,0) END AS gross_margin_total,
CASE WHEN b.sales_qty_total <= 0 THEN 0 ELSE (b.sales_usd_total / NULLIF(b.sales_qty_total,0)) - COALESCE(pd.cost_price_usd,0) END AS unit_profit_cost_total,
CASE WHEN b.sales_qty_total <= 0 THEN 0 ELSE (b.sales_usd_total / NULLIF(b.sales_qty_total,0)) - COALESCE(pd.base_price_usd,0) END AS unit_profit_base_total,
COALESCE(sp.market_count_total,0) AS market_count_total,
COALESCE(sp.customer_count_total_all, b.customer_count_total) AS customer_count_total,
CASE WHEN b.market_key <> 'STOK' AND b.sales_usd_total > 0 THEN 1 ELSE 0 END AS market_count_total,
b.customer_count_total AS customer_count_total,
b.invoice_count_total,
CASE
WHEN AVG(b.sales_qty_total) OVER (PARTITION BY b.market_key, b.kategori, b.urun_ana_grubu) <= 0 THEN 0
@@ -3174,7 +3174,7 @@ SELECT
ELSE COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)
END AS avg_price_usd_90d,
COALESCE(SUM(customer_count) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)::integer AS customer_count_90d,
COUNT(DISTINCT NULLIF(customer_code, '-')) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days' AND COALESCE(sales_usd,0) > 0)::integer AS customer_count_90d,
COALESCE(SUM(invoice_count) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)::integer AS invoice_count_90d,
COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '364 days'),0) AS sales_qty_365d,
COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '364 days'),0) AS sales_usd_365d
@@ -3507,16 +3507,16 @@ Agg AS (
COUNT(DISTINCT COALESCE(NULLIF(urun_ana_grubu,''), NULLIF(urun_alt_grubu,''), NULLIF(kategori,''), product_code)) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days')::integer AS product_group_count_180d,
COUNT(DISTINCT COALESCE(NULLIF(urun_ana_grubu,''), NULLIF(urun_alt_grubu,''), NULLIF(kategori,''), product_code)) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days')::integer AS product_group_count_365d,
COUNT(DISTINCT COALESCE(NULLIF(urun_ana_grubu,''), NULLIF(urun_alt_grubu,''), NULLIF(kategori,''), product_code)) FILTER (WHERE sales_date >= DATE '2022-01-01')::integer AS product_group_count_total,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days')::integer AS market_count_90d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days')::integer AS market_count_180d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days')::integer AS market_count_365d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= DATE '2022-01-01')::integer AS market_count_total,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days' AND COALESCE(sales_usd,0) > 0)::integer AS market_count_90d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days' AND COALESCE(sales_usd,0) > 0)::integer AS market_count_180d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days' AND COALESCE(sales_usd,0) > 0)::integer AS market_count_365d,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE sales_date >= DATE '2022-01-01' AND COALESCE(sales_usd,0) > 0)::integer AS market_count_total,
COALESCE(MAX(stock_qty),0) AS stock_qty,
COALESCE(MAX(avg_stock_90d),0) AS avg_stock_90d,
COALESCE(MAX(avg_stock_180d),0) AS avg_stock_180d,
COALESCE(MAX(avg_stock_365d),0) AS avg_stock_365d,
COALESCE(MAX(avg_stock_total),0) AS avg_stock_total,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days' AND COALESCE(customer_code,'') <> '')::integer AS customer_count_90d,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days' AND COALESCE(customer_code,'') <> '' AND COALESCE(sales_usd,0) > 0)::integer AS customer_count_90d,
COALESCE(SUM(invoice_count) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)::integer AS invoice_count_90d,
COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0) AS sales_qty_90d,
COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0) AS sales_usd_90d,
@@ -3532,7 +3532,7 @@ Agg AS (
ELSE COALESCE(SUM(sales_qty * cost_price_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)
END AS cost_price_usd_90d,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days' AND COALESCE(customer_code,'') <> '')::integer AS customer_count_180d,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days' AND COALESCE(customer_code,'') <> '' AND COALESCE(sales_usd,0) > 0)::integer AS customer_count_180d,
COALESCE(SUM(invoice_count) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)::integer AS invoice_count_180d,
COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0) AS sales_qty_180d,
COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0) AS sales_usd_180d,
@@ -3550,7 +3550,7 @@ Agg AS (
END AS cost_price_usd_180d,
COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0) AS sales_qty_365d,
COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0) AS sales_usd_365d,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days' AND COALESCE(customer_code,'') <> '')::integer AS customer_count_365d,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days' AND COALESCE(customer_code,'') <> '' AND COALESCE(sales_usd,0) > 0)::integer AS customer_count_365d,
COALESCE(SUM(invoice_count) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)::integer AS invoice_count_365d,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)
@@ -3564,7 +3564,7 @@ Agg AS (
ELSE COALESCE(SUM(sales_qty * cost_price_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)
END AS cost_price_usd_365d,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= DATE '2022-01-01' AND COALESCE(customer_code,'') <> '')::integer AS customer_count_total,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= DATE '2022-01-01' AND COALESCE(customer_code,'') <> '' AND COALESCE(sales_usd,0) > 0)::integer AS customer_count_total,
COALESCE(SUM(invoice_count) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)::integer AS invoice_count_total,
COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0) AS sales_qty_total,
COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= DATE '2022-01-01'),0) AS sales_usd_total,
@@ -3710,49 +3710,45 @@ SELECT
CASE WHEN avg_stock_total > 0 THEN sales_qty_total / NULLIF(avg_stock_total,0) ELSE 0 END AS stock_turnover_total,
has_cost,
sales_index_90d,
CASE WHEN NOT has_cost THEN 0 ELSE
CASE WHEN NOT has_cost THEN 0 WHEN sales_usd_90d <= 0 THEN 1 ELSE
ROUND((
LEAST(35, sales_usd_90d / 1000)
+ LEAST(25, GREATEST(gross_margin_cost_90d,0) * 55)
+ LEAST(20, invoice_count_90d * 2)
+ LEAST(10, sales_qty_90d / 10)
+ LEAST(10, product_count)
LEAST(35, sales_usd_90d / 25000 * 35)
+ LEAST(30, GREATEST(gross_margin_cost_90d,0) / 0.40 * 30)
+ LEAST(20, product_group_count_90d / 8.0 * 20)
+ LEAST(15, sales_qty_90d / 500 * 15)
)::numeric, 4)
END AS customer_score_90d,
CASE WHEN NOT has_cost THEN 0 ELSE
CASE WHEN NOT has_cost THEN 0 WHEN sales_usd_180d <= 0 THEN 1 ELSE
ROUND((
LEAST(35, sales_usd_180d / 1000)
+ LEAST(25, GREATEST(gross_margin_cost_180d,0) * 55)
+ LEAST(20, invoice_count_180d * 2)
+ LEAST(10, sales_qty_180d / 10)
+ LEAST(10, product_count)
LEAST(35, sales_usd_180d / 50000 * 35)
+ LEAST(30, GREATEST(gross_margin_cost_180d,0) / 0.40 * 30)
+ LEAST(20, product_group_count_180d / 8.0 * 20)
+ LEAST(15, sales_qty_180d / 1000 * 15)
)::numeric, 4)
END AS customer_score_180d,
CASE WHEN NOT has_cost THEN 0 ELSE
CASE WHEN NOT has_cost THEN 0 WHEN sales_usd_365d <= 0 THEN 1 ELSE
ROUND((
LEAST(35, sales_usd_365d / 1000)
+ LEAST(25, GREATEST(gross_margin_cost_365d,0) * 55)
+ LEAST(20, invoice_count_365d * 2)
+ LEAST(10, sales_qty_365d / 10)
+ LEAST(10, product_count)
LEAST(35, sales_usd_365d / 100000 * 35)
+ LEAST(30, GREATEST(gross_margin_cost_365d,0) / 0.40 * 30)
+ LEAST(20, product_group_count_365d / 8.0 * 20)
+ LEAST(15, sales_qty_365d / 2000 * 15)
)::numeric, 4)
END AS customer_score_365d,
CASE WHEN NOT has_cost THEN 0 ELSE
CASE WHEN NOT has_cost THEN 0 WHEN sales_usd_total <= 0 THEN 1 ELSE
ROUND((
LEAST(35, sales_usd_total / 1000)
+ LEAST(25, GREATEST(gross_margin_cost_total,0) * 55)
+ LEAST(20, invoice_count_total * 2)
+ LEAST(10, sales_qty_total / 10)
+ LEAST(10, product_count)
LEAST(35, sales_usd_total / 300000 * 35)
+ LEAST(30, GREATEST(gross_margin_cost_total,0) / 0.40 * 30)
+ LEAST(20, product_group_count_total / 8.0 * 20)
+ LEAST(15, sales_qty_total / 6000 * 15)
)::numeric, 4)
END AS customer_score_total,
CASE WHEN NOT has_cost THEN 0 ELSE
CASE WHEN NOT has_cost THEN 0 WHEN sales_usd_90d <= 0 THEN 1 ELSE
ROUND(
LEAST(35, sales_index_90d * 18)
+ LEAST(30, GREATEST(gross_margin_cost_90d,0) * 60)
+ LEAST(15, invoice_count_90d * 1.5)
+ LEAST(10, sales_qty_90d / 10)
+ LEAST(10, (CASE WHEN avg_stock_90d > 0 THEN sales_qty_90d / NULLIF(avg_stock_90d,0) ELSE 0 END) * 5),
LEAST(30, GREATEST(gross_margin_cost_90d,0) / 0.40 * 30)
+ LEAST(20, (CASE WHEN avg_stock_90d > 0 THEN sales_qty_90d / NULLIF(avg_stock_90d,0) ELSE 0 END) / 1.5 * 20)
+ LEAST(20, sales_usd_90d / 10000 * 20)
+ LEAST(15, market_count_90d / 8.0 * 15)
+ LEAST(15, customer_count_90d / 25.0 * 15),
4
)
END AS performance_score,
@@ -4485,8 +4481,8 @@ FROM (
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,
COUNT(DISTINCT NULLIF(NULLIF(market_key,'STOK'),'')) FILTER (WHERE COALESCE(sales_usd_90d,0) > 0)::integer AS market_count_90d,
COALESCE(SUM(CASE WHEN COALESCE(sales_usd_90d,0) > 0 THEN customer_count_90d ELSE 0 END),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 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,
@@ -5296,13 +5292,13 @@ func (n *productPerformanceGroupedSnapshotNode) add(row map[string]any) {
func (n *productPerformanceGroupedSnapshotNode) addDistinctSpread(row map[string]any) {
market := displayProductPerformanceMarketName(stringFromMap(row, "market_key"))
if market != "" && market != "STOK" {
if floatFromMap(row, "sales_qty_90d") > 0 || floatFromMap(row, "sales_usd_90d") > 0 {
if floatFromMap(row, "sales_usd_90d") > 0 {
if n.Market90Seen == nil {
n.Market90Seen = map[string]bool{}
}
n.Market90Seen[market] = true
}
if floatFromMap(row, "sales_qty_total") > 0 || floatFromMap(row, "sales_usd_total") > 0 {
if floatFromMap(row, "sales_usd_total") > 0 {
if n.MarketTotalSeen == nil {
n.MarketTotalSeen = map[string]bool{}
}
@@ -5311,13 +5307,13 @@ func (n *productPerformanceGroupedSnapshotNode) addDistinctSpread(row map[string
}
customer := strings.TrimSpace(stringFromMap(row, "customer_code"))
if customer != "" && customer != "-" {
if floatFromMap(row, "sales_qty_90d") > 0 || floatFromMap(row, "sales_usd_90d") > 0 {
if floatFromMap(row, "sales_usd_90d") > 0 {
if n.Customer90Seen == nil {
n.Customer90Seen = map[string]bool{}
}
n.Customer90Seen[customer] = true
}
if floatFromMap(row, "sales_qty_total") > 0 || floatFromMap(row, "sales_usd_total") > 0 {
if floatFromMap(row, "sales_usd_total") > 0 {
if n.CustomerTotalSeen == nil {
n.CustomerTotalSeen = map[string]bool{}
}
@@ -5530,19 +5526,19 @@ func aggregateProductPerformanceRows(rows []map[string]any, groupField string) m
func addProductPerformanceDistinctSpread(row map[string]any, market90Seen, marketTotalSeen, customer90Seen, customerTotalSeen map[string]bool) {
market := displayProductPerformanceMarketName(stringFromMap(row, "market_key"))
if market != "" && market != "STOK" {
if floatFromMap(row, "sales_qty_90d") > 0 || floatFromMap(row, "sales_usd_90d") > 0 {
if floatFromMap(row, "sales_usd_90d") > 0 {
market90Seen[market] = true
}
if floatFromMap(row, "sales_qty_total") > 0 || floatFromMap(row, "sales_usd_total") > 0 {
if floatFromMap(row, "sales_usd_total") > 0 {
marketTotalSeen[market] = true
}
}
customer := strings.TrimSpace(stringFromMap(row, "customer_code"))
if customer != "" && customer != "-" {
if floatFromMap(row, "sales_qty_90d") > 0 || floatFromMap(row, "sales_usd_90d") > 0 {
if floatFromMap(row, "sales_usd_90d") > 0 {
customer90Seen[customer] = true
}
if floatFromMap(row, "sales_qty_total") > 0 || floatFromMap(row, "sales_usd_total") > 0 {
if floatFromMap(row, "sales_usd_total") > 0 {
customerTotalSeen[customer] = true
}
}
@@ -5561,7 +5557,7 @@ func applyProductPerformanceDistinctSpread(row map[string]any, market90Seen, mar
if len(customerTotalSeen) > 0 {
row["customer_count_total"] = len(customerTotalSeen)
}
if floatFromMap(row, "sales_qty_90d") > 0 || floatFromMap(row, "sales_usd_90d") > 0 {
if floatFromMap(row, "sales_usd_90d") > 0 {
if intFromMap(row, "market_count_90d") == 0 {
row["market_count_90d"] = 1
}
@@ -5569,7 +5565,7 @@ func applyProductPerformanceDistinctSpread(row map[string]any, market90Seen, mar
row["customer_count_90d"] = 1
}
}
if floatFromMap(row, "sales_qty_total") > 0 || floatFromMap(row, "sales_usd_total") > 0 {
if floatFromMap(row, "sales_usd_total") > 0 {
if intFromMap(row, "market_count_total") == 0 {
row["market_count_total"] = maxInt(1, intFromMap(row, "market_count_90d"))
}
@@ -5860,6 +5856,9 @@ func productPerformanceCustomerSalesPeriodScore(row map[string]any) float64 {
}
func productPerformanceProductScore(suffix string, salesUSD, salesIndex, margin, stockTurnover, marketCount, customerCount float64) float64 {
if salesUSD <= 0 {
return 1
}
revenueScore := productPerformanceRevenueScore(suffix, salesUSD, salesIndex, productPerformanceProductRevenueTarget(suffix))
score := 0.30*productPerformanceMarginComponentScore(margin) +
0.20*productPerformanceRatioScore(stockTurnover, 1.50) +
@@ -5870,6 +5869,9 @@ func productPerformanceProductScore(suffix string, salesUSD, salesIndex, margin,
}
func productPerformanceCustomerScore(suffix string, salesUSD, margin, productGroupCount, salesQty float64) float64 {
if salesUSD <= 0 {
return 1
}
score := 0.35*productPerformanceRatioScore(salesUSD, productPerformanceCustomerRevenueTarget(suffix)) +
0.30*productPerformanceMarginComponentScore(margin) +
0.20*productPerformanceRatioScore(productGroupCount, 8) +
@@ -5878,9 +5880,6 @@ func productPerformanceCustomerScore(suffix string, salesUSD, margin, productGro
}
func productPerformanceRevenueScore(suffix string, salesUSD, salesIndex, absoluteTarget float64) float64 {
if salesIndex > 0 {
return productPerformanceRatioScore(salesIndex, 2)
}
return productPerformanceRatioScore(salesUSD, absoluteTarget)
}
+58 -20
View File
@@ -76,16 +76,19 @@ func productPerformanceSalesSQL() string {
), SPACE(0)))
END,
Qty1 = ISNULL(I.Qty1, 0),
TLAmount = ISNULL(I.Doc_Amount, 0) * ISNULL(I.Loc_ExchangeRate, 0),
USDAmount = (ISNULL(I.Doc_Amount, 0) * ISNULL(I.Loc_ExchangeRate, 0)) / ISNULL((
SELECT TOP 1 Rate
FROM AllExchangeRates WITH(NOLOCK)
WHERE CurrencyCode = 'USD'
AND RelationCurrencyCode = 'TRY'
AND ExchangeTypeCode = 6
AND Rate > 1
ORDER BY ABS(DATEDIFF(DAY, AllExchangeRates.Date, I.InvoiceDate)) ASC
), 1),
TLAmount = CASE
WHEN Amount.DocCurrencyCode = 'TRY' THEN Amount.DocNetAmount
WHEN CurRate.Rate > 0 THEN Amount.DocNetAmount * CurRate.Rate
WHEN ISNULL(I.Loc_ExchangeRate, 0) > 0 THEN Amount.DocNetAmount * I.Loc_ExchangeRate
ELSE 0
END,
USDAmount = CASE
WHEN Amount.DocCurrencyCode = 'USD' THEN Amount.DocNetAmount
WHEN Amount.DocCurrencyCode = 'TRY' AND UsdRate.Rate > 0 THEN Amount.DocNetAmount / UsdRate.Rate
WHEN CurRate.Rate > 0 AND UsdRate.Rate > 0 THEN (Amount.DocNetAmount * CurRate.Rate) / UsdRate.Rate
WHEN ISNULL(I.Loc_ExchangeRate, 0) > 0 AND UsdRate.Rate > 0 THEN (Amount.DocNetAmount * I.Loc_ExchangeRate) / UsdRate.Rate
ELSE 0
END,
RN = ROW_NUMBER() OVER (
PARTITION BY I.InvoiceLineID
ORDER BY I.InvoiceDate DESC, I.InvoiceNumber
@@ -96,6 +99,39 @@ func productPerformanceSalesSQL() string {
AND CAF.CurrAccCode = I.CurrAccCode
LEFT OUTER JOIN ProductAttributesFilter PAF WITH(NOLOCK)
ON PAF.ItemCode = I.ItemCode
LEFT OUTER JOIN dbo.trInvoiceLineCurrency ILC WITH(NOLOCK)
ON ILC.InvoiceLineID = I.InvoiceLineID
AND UPPER(LTRIM(RTRIM(ILC.CurrencyCode))) = UPPER(LTRIM(RTRIM(ISNULL(NULLIF(LTRIM(RTRIM(I.Doc_CurrencyCode)), ''), 'TRY'))))
OUTER APPLY (
SELECT
DocCurrencyCode = UPPER(LTRIM(RTRIM(ISNULL(NULLIF(LTRIM(RTRIM(I.Doc_CurrencyCode)), ''), ISNULL(NULLIF(LTRIM(RTRIM(ILC.CurrencyCode)), ''), 'TRY'))))),
DocNetAmount = COALESCE(
NULLIF(ISNULL(ILC.NetAmount, 0), 0),
NULLIF(ISNULL(I.Doc_Amount, 0), 0),
NULLIF(ISNULL(I.Doc_Price, 0) * ISNULL(I.Qty1, 0), 0),
0
)
) Amount
OUTER APPLY (
SELECT TOP 1 Rate
FROM AllExchangeRates WITH(NOLOCK)
WHERE CurrencyCode = 'USD'
AND RelationCurrencyCode = 'TRY'
AND ExchangeTypeCode = 6
AND Rate > 0
AND Date <= CAST(I.InvoiceDate AS date)
ORDER BY Date DESC
) UsdRate
OUTER APPLY (
SELECT TOP 1 Rate
FROM AllExchangeRates WITH(NOLOCK)
WHERE CurrencyCode = Amount.DocCurrencyCode
AND RelationCurrencyCode = 'TRY'
AND ExchangeTypeCode = 6
AND Rate > 0
AND Date <= CAST(I.InvoiceDate AS date)
ORDER BY Date DESC
) CurRate
WHERE I.InvoiceDate >= @p1
AND I.InvoiceDate < DATEADD(DAY, 1, @p2)
AND I.ItemTypeCode = 1
@@ -449,7 +485,7 @@ SalesAgg AS (
SUM(sales_usd) FILTER (WHERE sales_date >= $1::date - INTERVAL '179 days') AS sales_usd_180d,
SUM(sales_usd) FILTER (WHERE sales_date >= $1::date - INTERVAL '359 days') AS sales_usd_365d,
SUM(sales_usd) FILTER (WHERE sales_date >= DATE '2022-01-01') AS sales_usd_total,
COUNT(DISTINCT NULLIF(customer_code, '-')) FILTER (WHERE sales_date >= $1::date - INTERVAL '89 days') AS customer_count_90d,
COUNT(DISTINCT NULLIF(customer_code, '-')) FILTER (WHERE sales_date >= $1::date - INTERVAL '89 days' AND COALESCE(sales_usd, 0) > 0) AS customer_count_90d,
MAX(sales_date) AS last_sale_date,
MAX(last_ref_number) AS last_ref_number
FROM mk_product_performance_sales_daily
@@ -566,9 +602,9 @@ Spread AS (
product_code,
color_code,
yaka_kodu,
COUNT(DISTINCT market_key) AS market_count_90d
COUNT(DISTINCT NULLIF(NULLIF(market_key, 'STOK'), '')) AS market_count_90d
FROM SalesAgg
WHERE COALESCE(sales_qty_90d, 0) > 0
WHERE COALESCE(sales_usd_90d, 0) > 0
GROUP BY product_code, color_code, yaka_kodu
),
Market AS (
@@ -622,13 +658,15 @@ SELECT
COALESCE(gross_profit_usd_90d, 0), COALESCE(gross_profit_usd_180d, 0), COALESCE(gross_margin_90d, 0), COALESCE(gross_margin_180d, 0),
COALESCE(unit_profit_cost_90d, 0), COALESCE(unit_profit_cost_180d, 0), COALESCE(unit_profit_base_90d, 0), COALESCE(unit_profit_base_180d, 0), COALESCE(market_count_90d, 0), COALESCE(customer_count_90d, 0),
COALESCE(sales_index_90d, 0), COALESCE(price_index_90d, 0), COALESCE(margin_index_90d, 0),
ROUND(
LEAST(35, COALESCE(sales_index_90d, 0) * 18)
+ LEAST(25, GREATEST(COALESCE(gross_margin_90d, 0), 0) * 50)
+ LEAST(20, COALESCE(customer_count_90d, 0) * 2)
+ LEAST(10, COALESCE(market_count_90d, 0) * 3)
+ CASE WHEN COALESCE(stock_days_90d, 0) BETWEEN 10 AND 90 THEN 10 WHEN COALESCE(stock_days_90d, 0) > 180 THEN -10 ELSE 0 END
, 4) AS performance_score,
CASE WHEN COALESCE(sales_usd_90d, 0) <= 0 THEN 1 ELSE
ROUND(
LEAST(35, COALESCE(sales_index_90d, 0) * 18)
+ LEAST(25, GREATEST(COALESCE(gross_margin_90d, 0), 0) * 50)
+ LEAST(20, COALESCE(customer_count_90d, 0) * 2)
+ LEAST(10, COALESCE(market_count_90d, 0) * 3)
+ CASE WHEN COALESCE(stock_days_90d, 0) BETWEEN 10 AND 90 THEN 10 WHEN COALESCE(stock_days_90d, 0) > 180 THEN -10 ELSE 0 END
, 4)
END AS performance_score,
CASE
WHEN COALESCE(sales_index_90d,0) >= 1.25 AND COALESCE(gross_margin_90d,0) >= 0.25 THEN 'YILDIZ_URUN'
WHEN COALESCE(stock_qty,0) <= 0 AND COALESCE(sales_qty_90d,0) > 0 THEN 'STOKSUZ_TALEP'