@@ -53,11 +53,9 @@ func productPerformanceStockQuery() string {
;WITH ActiveWarehouses AS (
SELECT WarehouseCode
FROM (VALUES
('1-0-12 '),('1.01.2014'),('1.02.2005'),('1.02.2 004 '),('1-0-43 '),
('4.02.2001 '),('1-0-55 '),('1.01.2003 '),('1-0-21'),('1-0-2 '),
('1.01.2004 '),('1-0-49 '),('1-0-37 '),('1-0-2 9'),('1-0-28 '),
('1-0-10'),('100'),('1.02.2006'),('1-0-42'),('1.01.2002'),
('1-0-52')
('1-0-14 '),('1-0-10'),('1-0-8'),('1-2-5'),('1-2-4'),('1-0-12'),('1 00'),('1-0-28 '),
('1-0-24'),('1-2-6'),('1-1-14 '),('1-0-2 '),('1-0-52'),('1-1-2 '),('1-0-21'),('1-1-3 '),
('1-0-33 '),('101 '),('1-014 '),('1-0-4 9'),('1-0-36 ')
) W(WarehouseCode)
),
Raw AS (
@@ -72,8 +70,8 @@ Raw AS (
END,
InQty = SUM(S.In_Qty1),
OutQty = SUM(S.Out_Qty1),
NetQty = SUM(S.Inventory Qty1)
FROM StockWithCost S WITH(NOLOCK)
NetQty = SUM(S.In_Qty1 - S.Out_ Qty1)
FROM tr Stock S WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(S.WarehouseCode))
WHERE S.ItemTypeCode = 1
@@ -185,6 +183,103 @@ Running AS (
ConsumptionOutQty,
CountDiffQty
FROM Collapsed
),
CurrentStock AS (
SELECT
ProductCode = LTRIM(RTRIM(S.ItemCode)),
ColorCode = LTRIM(RTRIM(ISNULL(S.ColorCode, ''))),
YakaKodu = LTRIM(RTRIM(ISNULL(S.ItemDim2Code, ''))),
InventoryQty1 = SUM(S.In_Qty1 - S.Out_Qty1)
FROM trStock S WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(S.WarehouseCode))
WHERE S.ItemTypeCode = 1
AND (
LEN(LTRIM(RTRIM(S.ItemCode))) = 13
AND (
S.ItemCode LIKE 'S%'
OR S.ItemCode LIKE 'O%'
OR S.ItemCode LIKE 'N%'
OR S.ItemCode LIKE 'X%'
OR S.ItemCode LIKE 'I%'
OR S.ItemCode LIKE 'A%'
)
)
AND (@p3 = '' OR S.ItemCode LIKE @p3 + '%')
AND S.DocumentDate < DATEADD(DAY, 1, @p2)
GROUP BY S.ItemCode, S.ColorCode, S.ItemDim2Code
),
CurrentPick AS (
SELECT
ProductCode = LTRIM(RTRIM(P.ItemCode)),
ColorCode = LTRIM(RTRIM(ISNULL(P.ColorCode, ''))),
YakaKodu = LTRIM(RTRIM(ISNULL(P.ItemDim2Code, ''))),
PickingQty1 = SUM(P.Qty1)
FROM PickingStates P WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(P.WarehouseCode))
WHERE P.ItemTypeCode = 1
AND LEN(LTRIM(RTRIM(P.ItemCode))) = 13
AND (@p3 = '' OR P.ItemCode LIKE @p3 + '%')
GROUP BY P.ItemCode, P.ColorCode, P.ItemDim2Code
),
CurrentReserve AS (
SELECT
ProductCode = LTRIM(RTRIM(R.ItemCode)),
ColorCode = LTRIM(RTRIM(ISNULL(R.ColorCode, ''))),
YakaKodu = LTRIM(RTRIM(ISNULL(R.ItemDim2Code, ''))),
ReserveQty1 = SUM(R.Qty1)
FROM ReserveStates R WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(R.WarehouseCode))
WHERE R.ItemTypeCode = 1
AND LEN(LTRIM(RTRIM(R.ItemCode))) = 13
AND (@p3 = '' OR R.ItemCode LIKE @p3 + '%')
GROUP BY R.ItemCode, R.ColorCode, R.ItemDim2Code
),
CurrentDisp AS (
SELECT
ProductCode = LTRIM(RTRIM(D.ItemCode)),
ColorCode = LTRIM(RTRIM(ISNULL(D.ColorCode, ''))),
YakaKodu = LTRIM(RTRIM(ISNULL(D.ItemDim2Code, ''))),
DispOrderQty1 = SUM(D.Qty1)
FROM DispOrderStates D WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(D.WarehouseCode))
WHERE D.ItemTypeCode = 1
AND LEN(LTRIM(RTRIM(D.ItemCode))) = 13
AND (@p3 = '' OR D.ItemCode LIKE @p3 + '%')
GROUP BY D.ItemCode, D.ColorCode, D.ItemDim2Code
),
CurrentAvailable AS (
SELECT
StockDate = @p2,
S.ProductCode,
S.ColorCode,
S.YakaKodu,
StockQty = CAST(ROUND(
ISNULL(S.InventoryQty1, 0)
- ISNULL(PK.PickingQty1, 0)
- ISNULL(RS.ReserveQty1, 0)
- ISNULL(DP.DispOrderQty1, 0),
2
) AS decimal(18,4)),
InQty = CAST(0 AS decimal(18,4)),
OutQty = CAST(0 AS decimal(18,4)),
KpiInQty = CAST(0 AS decimal(18,4)),
KpiOutQty = CAST(0 AS decimal(18,4)),
SalesMovementQty = CAST(0 AS decimal(18,4)),
ProductionInQty = CAST(0 AS decimal(18,4)),
PurchaseInQty = CAST(0 AS decimal(18,4)),
ConsumptionOutQty = CAST(0 AS decimal(18,4)),
CountDiffQty = CAST(0 AS decimal(18,4))
FROM CurrentStock S
LEFT JOIN CurrentPick PK
ON PK.ProductCode = S.ProductCode AND PK.ColorCode = S.ColorCode AND PK.YakaKodu = S.YakaKodu
LEFT JOIN CurrentReserve RS
ON RS.ProductCode = S.ProductCode AND RS.ColorCode = S.ColorCode AND RS.YakaKodu = S.YakaKodu
LEFT JOIN CurrentDisp DP
ON DP.ProductCode = S.ProductCode AND DP.ColorCode = S.ColorCode AND DP.YakaKodu = S.YakaKodu
)
SELECT
StockDate,
@@ -201,8 +296,11 @@ SELECT
PurchaseInQty,
ConsumptionOutQty,
CountDiffQty
FROM Running
WHERE StockDate BETWEEN @p1 AND @p2
FROM (
SELECT * FROM Running WHERE StockDate BETWEEN @p1 AND DATEADD(DAY, -1, @p2)
UNION ALL
SELECT * FROM CurrentAvailable
) X
ORDER BY StockDate, ProductCode, ColorCode, YakaKodu
`
}
@@ -2165,6 +2263,326 @@ LIMIT $1
return out , rows . Err ( )
}
func ListProductPerformanceSalesBreakdown ( ctx context . Context , pg * sql . DB , breakdown string , limit int ) ( [ ] models . ProductPerformanceSalesBreakdownRow , error ) {
if err := EnsureProductPerformanceTables ( pg ) ; err != nil {
return nil , err
}
if limit <= 0 || limit > 1000 {
limit = 500
}
mode := strings . ToLower ( strings . TrimSpace ( breakdown ) )
fields := map [ string ] string {
"product_code" : "s.product_code" ,
"color_code" : "s.color_code" ,
"yaka_kodu" : "s.yaka_kodu" ,
"item_description" : "MAX(s.item_description)" ,
"market_key" : "s.market_key" ,
"country" : "s.customer_country" ,
"customer_segment" : "s.customer_segment" ,
"customer_code" : "s.customer_code" ,
"customer_name" : "MAX(s.customer_name)" ,
}
selected := map [ string ] bool { }
groupCols := [ ] string { }
switch mode {
case "color_yaka_market_customer" :
selected [ "color_code" ] = true
selected [ "yaka_kodu" ] = true
selected [ "market_key" ] = true
selected [ "customer_code" ] = true
selected [ "customer_name" ] = true
groupCols = [ ] string { "s.color_code" , "s.yaka_kodu" , "s.market_key" , "s.customer_code" }
case "product_country_segment_market_customer" :
selected [ "product_code" ] = true
selected [ "item_description" ] = true
selected [ "country" ] = true
selected [ "customer_segment" ] = true
selected [ "market_key" ] = true
selected [ "customer_code" ] = true
selected [ "customer_name" ] = true
groupCols = [ ] string { "s.product_code" , "s.customer_country" , "s.customer_segment" , "s.market_key" , "s.customer_code" }
case "market_customer_product" :
selected [ "market_key" ] = true
selected [ "customer_code" ] = true
selected [ "customer_name" ] = true
selected [ "product_code" ] = true
selected [ "color_code" ] = true
selected [ "yaka_kodu" ] = true
selected [ "item_description" ] = true
groupCols = [ ] string { "s.market_key" , "s.customer_code" , "s.product_code" , "s.color_code" , "s.yaka_kodu" }
case "country_segment_market_customer_product" :
selected [ "country" ] = true
selected [ "customer_segment" ] = true
selected [ "market_key" ] = true
selected [ "customer_code" ] = true
selected [ "customer_name" ] = true
selected [ "product_code" ] = true
selected [ "color_code" ] = true
selected [ "yaka_kodu" ] = true
selected [ "item_description" ] = true
groupCols = [ ] string { "s.customer_country" , "s.customer_segment" , "s.market_key" , "s.customer_code" , "s.product_code" , "s.color_code" , "s.yaka_kodu" }
default :
mode = "color_yaka_market_customer"
selected [ "color_code" ] = true
selected [ "yaka_kodu" ] = true
selected [ "market_key" ] = true
selected [ "customer_code" ] = true
selected [ "customer_name" ] = true
groupCols = [ ] string { "s.color_code" , "s.yaka_kodu" , "s.market_key" , "s.customer_code" }
}
selectExpr := func ( name string ) string {
if selected [ name ] {
return fields [ name ] + " AS " + name
}
return "''::text AS " + name
}
query := fmt . Sprintf ( `
WITH Agg AS (
SELECT
$2::text AS breakdown,
%s,
%s,
%s,
%s,
%s,
%s,
%s,
%s,
%s,
COUNT(DISTINCT product_code) AS product_count,
COUNT(DISTINCT customer_code) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days' AND COALESCE(customer_code,'') <> '')::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,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)=0 THEN 0
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,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_qty * base_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 base_price_usd_90d,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '89 days'),0)=0 THEN 0
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,
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,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)
END AS avg_price_usd_180d,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_qty * base_price_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)
END AS base_price_usd_180d,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_qty * cost_price_usd) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '179 days'),0)
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,
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)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)
END AS avg_price_usd_365d,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_qty * base_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 base_price_usd_365d,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= current_date - INTERVAL '359 days'),0)=0 THEN 0
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,
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,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_usd) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)
END AS avg_price_usd_total,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_qty * base_price_usd) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)
END AS base_price_usd_total,
CASE WHEN COALESCE(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)=0 THEN 0
ELSE COALESCE(SUM(sales_qty * cost_price_usd) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)
/ NULLIF(SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01'),0)
END AS cost_price_usd_total,
COALESCE(to_char(MAX(sales_date),'YYYY-MM-DD'),'') AS last_sale_date
FROM (
SELECT
s.*,
COALESCE(pd.base_price_usd,0) AS base_price_usd,
COALESCE(pd.cost_price_usd,0) AS cost_price_usd
FROM mk_product_performance_sales_daily s
LEFT JOIN mk_product_performance_price_dim pd ON pd.product_code = s.product_code
) s
WHERE sales_date >= DATE '2022-01-01'
GROUP BY %s
),
Enriched AS (
SELECT
Agg.*,
sales_usd_90d - (sales_qty_90d * base_price_usd_90d) AS gross_profit_base_usd_90d,
sales_usd_90d - (sales_qty_90d * cost_price_usd_90d) AS gross_profit_cost_usd_90d,
CASE WHEN sales_usd_90d <= 0 THEN 0 ELSE (sales_usd_90d - (sales_qty_90d * base_price_usd_90d)) / NULLIF(sales_usd_90d,0) END AS gross_margin_base_90d,
CASE WHEN sales_usd_90d <= 0 THEN 0 ELSE (sales_usd_90d - (sales_qty_90d * cost_price_usd_90d)) / NULLIF(sales_usd_90d,0) END AS gross_margin_cost_90d,
sales_usd_180d - (sales_qty_180d * base_price_usd_180d) AS gross_profit_base_usd_180d,
sales_usd_180d - (sales_qty_180d * cost_price_usd_180d) AS gross_profit_cost_usd_180d,
CASE WHEN sales_usd_180d <= 0 THEN 0 ELSE (sales_usd_180d - (sales_qty_180d * base_price_usd_180d)) / NULLIF(sales_usd_180d,0) END AS gross_margin_base_180d,
CASE WHEN sales_usd_180d <= 0 THEN 0 ELSE (sales_usd_180d - (sales_qty_180d * cost_price_usd_180d)) / NULLIF(sales_usd_180d,0) END AS gross_margin_cost_180d,
sales_usd_365d - (sales_qty_365d * base_price_usd_365d) AS gross_profit_base_usd_365d,
sales_usd_365d - (sales_qty_365d * cost_price_usd_365d) AS gross_profit_cost_usd_365d,
CASE WHEN sales_usd_365d <= 0 THEN 0 ELSE (sales_usd_365d - (sales_qty_365d * base_price_usd_365d)) / NULLIF(sales_usd_365d,0) END AS gross_margin_base_365d,
CASE WHEN sales_usd_365d <= 0 THEN 0 ELSE (sales_usd_365d - (sales_qty_365d * cost_price_usd_365d)) / NULLIF(sales_usd_365d,0) END AS gross_margin_cost_365d,
sales_usd_total - (sales_qty_total * base_price_usd_total) AS gross_profit_base_usd_total,
sales_usd_total - (sales_qty_total * cost_price_usd_total) AS gross_profit_cost_usd_total,
CASE WHEN sales_usd_total <= 0 THEN 0 ELSE (sales_usd_total - (sales_qty_total * base_price_usd_total)) / NULLIF(sales_usd_total,0) END AS gross_margin_base_total,
CASE WHEN sales_usd_total <= 0 THEN 0 ELSE (sales_usd_total - (sales_qty_total * cost_price_usd_total)) / NULLIF(sales_usd_total,0) END AS gross_margin_cost_total,
(base_price_usd_total > 0 AND cost_price_usd_total > 0) AS has_cost
FROM Agg
),
Scored AS (
SELECT
Enriched.*,
CASE WHEN AVG(NULLIF(sales_usd_90d,0)) OVER () IS NULL THEN 0
ELSE sales_usd_90d / NULLIF(AVG(NULLIF(sales_usd_90d,0)) OVER (),0)
END AS sales_index_90d
FROM Enriched
)
SELECT
breakdown,
product_code,
color_code,
yaka_kodu,
item_description,
market_key,
country,
customer_segment,
customer_code,
customer_name,
product_count,
customer_count_90d,
invoice_count_90d,
sales_qty_90d,
sales_usd_90d,
avg_price_usd_90d,
base_price_usd_90d,
cost_price_usd_90d,
gross_profit_base_usd_90d,
gross_profit_cost_usd_90d,
gross_margin_base_90d,
gross_margin_cost_90d,
customer_count_180d,
invoice_count_180d,
sales_qty_180d,
sales_usd_180d,
avg_price_usd_180d,
base_price_usd_180d,
cost_price_usd_180d,
gross_profit_base_usd_180d,
gross_profit_cost_usd_180d,
gross_margin_base_180d,
gross_margin_cost_180d,
sales_qty_365d,
sales_usd_365d,
avg_price_usd_365d,
base_price_usd_365d,
cost_price_usd_365d,
gross_profit_base_usd_365d,
gross_profit_cost_usd_365d,
gross_margin_base_365d,
gross_margin_cost_365d,
customer_count_total,
invoice_count_total,
sales_qty_total,
sales_usd_total,
avg_price_usd_total,
base_price_usd_total,
cost_price_usd_total,
gross_profit_base_usd_total,
gross_profit_cost_usd_total,
gross_margin_base_total,
gross_margin_cost_total,
has_cost,
sales_index_90d,
CASE WHEN NOT has_cost THEN 0 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)
+ CASE WHEN last_sale_date >= to_char(current_date - INTERVAL '30 days','YYYY-MM-DD') THEN 10 ELSE 0 END,
4
)
END AS performance_score,
CASE
WHEN NOT has_cost THEN 'MALIYET_YOK'
WHEN sales_index_90d >= 1.25 AND customer_count_90d >= 2 THEN 'YILDIZ_URUN'
WHEN sales_qty_90d = 0 AND sales_qty_365d > 0 THEN 'STOK_RISKI'
WHEN gross_margin_cost_90d < 0 THEN 'FIYAT_BASKISI'
WHEN sales_index_90d < 0.75 THEN 'TAKIP'
ELSE 'TAKIP'
END AS performance_bucket,
CASE
WHEN sales_index_90d >= 1.25 AND customer_count_90d >= 2 THEN 'Güçlü satış kı rı lı mı '
WHEN sales_qty_90d = 0 AND sales_qty_365d > 0 THEN 'Son 90 gün zayı f, kontrol et'
ELSE 'Takip'
END AS recommendation,
last_sale_date
FROM Scored
ORDER BY sales_usd_90d DESC, sales_qty_90d DESC
LIMIT $1
` ,
selectExpr ( "product_code" ) ,
selectExpr ( "color_code" ) ,
selectExpr ( "yaka_kodu" ) ,
selectExpr ( "item_description" ) ,
selectExpr ( "market_key" ) ,
selectExpr ( "country" ) ,
selectExpr ( "customer_segment" ) ,
selectExpr ( "customer_code" ) ,
selectExpr ( "customer_name" ) ,
strings . Join ( groupCols , ", " ) ,
)
rows , err := pg . QueryContext ( ctx , query , limit , mode )
if err != nil {
return nil , err
}
defer rows . Close ( )
out := make ( [ ] models . ProductPerformanceSalesBreakdownRow , 0 , limit )
for rows . Next ( ) {
var r models . ProductPerformanceSalesBreakdownRow
if err := rows . Scan (
& r . Breakdown , & r . ProductCode , & r . ColorCode , & r . YakaKodu , & r . ItemDescription ,
& r . MarketKey , & r . Country , & r . CustomerSegment , & r . CustomerCode , & r . CustomerName ,
& r . ProductCount , & r . CustomerCount90 , & r . InvoiceCount90 , & r . SalesQty90 , & r . SalesUSD90 ,
& r . AvgPriceUSD90 , & r . BasePriceUSD90 , & r . CostPriceUSD90 , & r . GrossProfitBase90 ,
& r . GrossProfitCost90 , & r . GrossMarginBase90 , & r . GrossMarginCost90 , & r . CustomerCount180 ,
& r . InvoiceCount180 , & r . SalesQty180 , & r . SalesUSD180 , & r . AvgPriceUSD180 , & r . BasePriceUSD180 ,
& r . CostPriceUSD180 , & r . GrossProfitBase180 , & r . GrossProfitCost180 , & r . GrossMarginBase180 ,
& r . GrossMarginCost180 , & r . SalesQty365 , & r . SalesUSD365 , & r . AvgPriceUSD365 , & r . BasePriceUSD365 ,
& r . CostPriceUSD365 , & r . GrossProfitBase365 , & r . GrossProfitCost365 , & r . GrossMarginBase365 ,
& r . GrossMarginCost365 , & r . CustomerCountTotal , & r . InvoiceCountTotal , & r . SalesQtyTotal , & r . SalesUSDTotal ,
& r . AvgPriceUSDTotal , & r . BasePriceUSDTotal , & r . CostPriceUSDTotal , & r . GrossProfitBaseTotal ,
& r . GrossProfitCostTotal , & r . GrossMarginBaseTotal , & r . GrossMarginCostTotal , & r . HasCost ,
& r . SalesIndex90 , & r . PerformanceScore ,
& r . PerformanceBucket , & r . Recommendation , & r . LastSaleDate ,
) ; err != nil {
return nil , err
}
out = append ( out , r )
}
return out , rows . Err ( )
}
func ListProductPerformanceSalesDetails ( ctx context . Context , pg * sql . DB , productCode , colorCode , yakaKodu string , limit int ) ( [ ] models . ProductPerformanceSalesDetailRow , error ) {
if limit <= 0 || limit > 500 {
limit = 100
@@ -2211,26 +2629,83 @@ func ListProductPerformanceStockSizes(ctx context.Context, productCode, colorCod
;WITH ActiveWarehouses AS (
SELECT WarehouseCode
FROM (VALUES
('1-0-12 '),('1.01.2014'),('1.02.2005'),('1.02.2 004 '),('1-0-43 '),
('4.02.2001 '),('1-0-55 '),('1.01.2003 '),('1-0-21'),('1-0-2 '),
('1.01.2004 '),('1-0-49 '),('1-0-37 '),('1-0-2 9'),('1-0-28 '),
('1-0-10'),('100'),('1.02.2006'),('1-0-42'),('1.01.2002'),
('1-0-52')
('1-0-14 '),('1-0-10'),('1-0-8'),('1-2-5'),('1-2-4'),('1-0-12'),('1 00'),('1-0-28 '),
('1-0-24'),('1-2-6'),('1-1-14 '),('1-0-2 '),('1-0-52'),('1-1-2 '),('1-0-21'),('1-1-3 '),
('1-0-33 '),('101 '),('1-014 '),('1-0-4 9'),('1-0-36 ')
) W(WarehouseCode)
),
Stock AS (
SELECT
SizeCode = LTRIM(RTRIM(ISNULL(S.ItemDim1Code, ''))),
InventoryQty1 = SUM(S.In_Qty1 - S.Out_Qty1)
FROM trStock S WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(S.WarehouseCode))
WHERE S.ItemTypeCode = 1
AND LTRIM(RTRIM(S.ItemCode)) = @p1
AND LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) = @p2
AND LTRIM(RTRIM(ISNULL(S.ItemDim2Code, ''))) = @p3
GROUP BY LTRIM(RTRIM(ISNULL(S.ItemDim1Code, '')))
),
Pick AS (
SELECT
SizeCode = LTRIM(RTRIM(ISNULL(P.ItemDim1Code, ''))),
PickingQty1 = SUM(P.Qty1)
FROM PickingStates P WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(P.WarehouseCode))
WHERE P.ItemTypeCode = 1
AND LTRIM(RTRIM(P.ItemCode)) = @p1
AND LTRIM(RTRIM(ISNULL(P.ColorCode, ''))) = @p2
AND LTRIM(RTRIM(ISNULL(P.ItemDim2Code, ''))) = @p3
GROUP BY LTRIM(RTRIM(ISNULL(P.ItemDim1Code, '')))
),
Reserve AS (
SELECT
SizeCode = LTRIM(RTRIM(ISNULL(R.ItemDim1Code, ''))),
ReserveQty1 = SUM(R.Qty1)
FROM ReserveStates R WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(R.WarehouseCode))
WHERE R.ItemTypeCode = 1
AND LTRIM(RTRIM(R.ItemCode)) = @p1
AND LTRIM(RTRIM(ISNULL(R.ColorCode, ''))) = @p2
AND LTRIM(RTRIM(ISNULL(R.ItemDim2Code, ''))) = @p3
GROUP BY LTRIM(RTRIM(ISNULL(R.ItemDim1Code, '')))
),
Disp AS (
SELECT
SizeCode = LTRIM(RTRIM(ISNULL(D.ItemDim1Code, ''))),
DispOrderQty1 = SUM(D.Qty1)
FROM DispOrderStates D WITH(NOLOCK)
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(D.WarehouseCode))
WHERE D.ItemTypeCode = 1
AND LTRIM(RTRIM(D.ItemCode)) = @p1
AND LTRIM(RTRIM(ISNULL(D.ColorCode, ''))) = @p2
AND LTRIM(RTRIM(ISNULL(D.ItemDim2Code, ''))) = @p3
GROUP BY LTRIM(RTRIM(ISNULL(D.ItemDim1Code, '')))
)
SELECT
SizeCode = LTRIM(RTRIM(ISNULL(S.ItemDim1Code, ''))) ,
StockQty = SUM(S.InventoryQty1)
FROM StockWithCost S WITH(NOLOCK )
INNER JOIN ActiveWarehouses W
ON W.WarehouseCode = LTRIM(RTRIM(S.WarehouseCode) )
WHERE S.ItemTypeCode = 1
AND LTRIM(RTRIM(S.ItemCode)) = @p1
AND LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) = @p2
AND LTRIM(RTRIM(ISNULL(S.ItemDim2Code, ''))) = @p3
GROUP BY LTRIM(RTRIM(ISNULL(S.ItemDim1Code, '')))
HAVING SUM(S.InventoryQty1) <> 0
ORDER BY LTRIM(RTRIM(ISNULL(S.ItemDim1Code, '')))
S. SizeCode,
StockQty = CAST(ROUND(
ISNULL(S.InventoryQty1, 0 )
- ISNULL(P.PickingQty1, 0)
- ISNULL(R.ReserveQty1, 0 )
- ISNULL(D.DispOrderQty1, 0),
2
) AS FLOAT)
FROM Stock S
LEFT JOIN Pick P ON P.SizeCode = S.SizeCode
LEFT JOIN Reserve R ON R.SizeCode = S.SizeCode
LEFT JOIN Disp D ON D.SizeCode = S.SizeCode
WHERE (
ISNULL(S.InventoryQty1, 0)
- ISNULL(P.PickingQty1, 0)
- ISNULL(R.ReserveQty1, 0)
- ISNULL(D.DispOrderQty1, 0)
) <> 0
ORDER BY S.SizeCode
` , strings . TrimSpace ( productCode ) , strings . TrimSpace ( colorCode ) , strings . TrimSpace ( yakaKodu ) )
if err != nil {
return nil , err