654 lines
30 KiB
Go
654 lines
30 KiB
Go
package queries
|
||
|
||
func productPerformanceSalesSQL() string {
|
||
return `
|
||
;WITH SalesLines AS (
|
||
SELECT
|
||
I.InvoiceLineID,
|
||
SalesDate = CAST(I.InvoiceDate AS date),
|
||
I.InvoiceHeaderID,
|
||
I.InvoiceNumber,
|
||
ProductCode = UPPER(LTRIM(RTRIM(I.ItemCode))),
|
||
ColorCode = UPPER(LTRIM(RTRIM(ISNULL(I.ColorCode, '')))),
|
||
YakaKodu = UPPER(LTRIM(RTRIM(ISNULL(I.ItemDim2Code, '')))),
|
||
ItemDescription = dbo.HG_Temizlik(ISNULL((
|
||
SELECT ItemDescription
|
||
FROM cdItemDesc WITH(NOLOCK)
|
||
WHERE cdItemDesc.ItemTypeCode = I.ItemTypeCode
|
||
AND cdItemDesc.ItemCode = I.ItemCode
|
||
AND cdItemDesc.LangCode = 'TR'
|
||
), SPACE(0))),
|
||
UrunAnaGrubu = dbo.HG_Temizlik(ISNULL(PAF.ProductAtt01, SPACE(0))),
|
||
UrunAltGrubu = dbo.HG_Temizlik(ISNULL(PAF.ProductAtt02, SPACE(0))),
|
||
Kategori = dbo.HG_Temizlik(ISNULL(PAF.ProductAtt44, SPACE(0))),
|
||
UrunIlkGrubu = dbo.HG_Temizlik(ISNULL(PAF.ProductAtt42, SPACE(0))),
|
||
AskiliYan = dbo.HG_Temizlik(ISNULL(PAF.ProductAtt45, SPACE(0))),
|
||
ChannelCode = CASE
|
||
WHEN I.ProcessCode IN ('R') THEN dbo.HG_Temizlik(ISNULL((
|
||
SELECT OfficeDescription
|
||
FROM cdOfficeDesc WITH(NOLOCK)
|
||
WHERE cdOfficeDesc.OfficeCode = I.OfficeCode
|
||
AND cdOfficeDesc.LangCode = 'TR'
|
||
), SPACE(0)))
|
||
ELSE dbo.HG_Temizlik(ISNULL((
|
||
SELECT AttributeDescription
|
||
FROM cdCurrAccAttributeDesc WITH(NOLOCK)
|
||
WHERE cdCurrAccAttributeDesc.CurrAccTypeCode = 3
|
||
AND AttributeTypeCode = 1
|
||
AND CAF.CustomerAtt01 = AttributeCode
|
||
AND cdCurrAccAttributeDesc.LangCode = 'TR'
|
||
), SPACE(0)))
|
||
END,
|
||
CustomerCountry = dbo.HG_Temizlik(ISNULL((
|
||
SELECT AttributeDescription
|
||
FROM cdCurrAccAttributeDesc WITH(NOLOCK)
|
||
WHERE cdCurrAccAttributeDesc.CurrAccTypeCode = 3
|
||
AND AttributeTypeCode = 5
|
||
AND CAF.CustomerAtt05 = AttributeCode
|
||
AND cdCurrAccAttributeDesc.LangCode = 'TR'
|
||
), SPACE(0))),
|
||
CustomerSegment = dbo.HG_Temizlik(ISNULL((
|
||
SELECT AttributeDescription
|
||
FROM cdCurrAccAttributeDesc WITH(NOLOCK)
|
||
WHERE cdCurrAccAttributeDesc.CurrAccTypeCode = 3
|
||
AND AttributeTypeCode = 11
|
||
AND CAF.CustomerAtt11 = AttributeCode
|
||
AND cdCurrAccAttributeDesc.LangCode = 'TR'
|
||
), SPACE(0))),
|
||
CustomerCode = CASE
|
||
WHEN I.ProcessCode = 'R' THEN dbo.HG_Temizlik(ISNULL(I.StoreCode, ''))
|
||
ELSE dbo.HG_Temizlik(ISNULL(I.CurrAccCode, ''))
|
||
END,
|
||
CustomerDescription = CASE
|
||
WHEN I.ProcessCode = 'R' THEN dbo.HG_Temizlik(ISNULL((
|
||
SELECT CurrAccDescription
|
||
FROM cdCurrAccDesc WITH(NOLOCK)
|
||
WHERE cdCurrAccDesc.CurrAccTypeCode = 5
|
||
AND cdCurrAccDesc.CurrAccCode = I.StoreCode
|
||
AND cdCurrAccDesc.LangCode = 'TR'
|
||
), SPACE(0)))
|
||
ELSE dbo.HG_Temizlik(ISNULL((
|
||
SELECT CurrAccDescription
|
||
FROM cdCurrAccDesc WITH(NOLOCK)
|
||
WHERE cdCurrAccDesc.CurrAccTypeCode = I.CurrAccTypeCode
|
||
AND cdCurrAccDesc.CurrAccCode = I.CurrAccCode
|
||
AND cdCurrAccDesc.LangCode = 'TR'
|
||
), 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),
|
||
RN = ROW_NUMBER() OVER (
|
||
PARTITION BY I.InvoiceLineID
|
||
ORDER BY I.InvoiceDate DESC, I.InvoiceNumber
|
||
)
|
||
FROM AllInvoicesWithAttributes I WITH(NOLOCK)
|
||
LEFT OUTER JOIN CustomerAttributesFilter CAF WITH(NOLOCK)
|
||
ON CAF.CurrAccTypeCode = I.CurrAccTypeCode
|
||
AND CAF.CurrAccCode = I.CurrAccCode
|
||
LEFT OUTER JOIN ProductAttributesFilter PAF WITH(NOLOCK)
|
||
ON PAF.ItemCode = I.ItemCode
|
||
WHERE I.InvoiceDate >= @p1
|
||
AND I.InvoiceDate < DATEADD(DAY, 1, @p2)
|
||
AND I.ItemTypeCode = 1
|
||
AND LEN(LTRIM(RTRIM(I.ItemCode))) = 13
|
||
AND (@p3 = '' OR UPPER(LTRIM(RTRIM(I.ItemCode))) LIKE @p3 + '%')
|
||
AND (
|
||
(I.CompanyCode = 1 AND I.ATAtt01 IN (1,2) AND I.ProcessCode IN ('WS','R'))
|
||
OR (I.CompanyCode = 4 AND I.ProcessCode = 'R')
|
||
)
|
||
AND EXISTS (
|
||
SELECT 1
|
||
FROM trDebitHeader DH WITH(NOLOCK)
|
||
INNER JOIN trDebitLine DL WITH(NOLOCK)
|
||
ON DL.DebitHeaderID = DH.DebitHeaderID
|
||
WHERE DH.ApplicationCode = 'Invoi'
|
||
AND DH.ApplicationID = I.InvoiceHeaderID
|
||
)
|
||
)
|
||
SELECT
|
||
SalesDate,
|
||
ProductCode,
|
||
ColorCode,
|
||
YakaKodu,
|
||
ItemDescription = MAX(ItemDescription),
|
||
Kategori = MAX(Kategori),
|
||
Seri = '',
|
||
YasGrubu = '',
|
||
AskiliYan = ISNULL(NULLIF(MAX(AskiliYan), '-'), ''),
|
||
UrunIlkGrubu = MAX(UrunIlkGrubu),
|
||
UrunAnaGrubu = MAX(UrunAnaGrubu),
|
||
UrunAltGrubu = MAX(UrunAltGrubu),
|
||
MarketKey = CONCAT(MAX(Kategori), '|', MAX(UrunIlkGrubu), '|', ISNULL(NULLIF(MAX(AskiliYan), '-'), ''), '|', MAX(UrunAnaGrubu), '|', MAX(UrunAltGrubu), '|', ChannelCode),
|
||
ChannelCode,
|
||
CustomerCountry = ISNULL(NULLIF(CustomerCountry, ''), '-'),
|
||
CustomerSegment = ISNULL(NULLIF(CustomerSegment, ''), '-'),
|
||
CustomerCode = ISNULL(NULLIF(CustomerCode, ''), '-'),
|
||
CustomerDescription = MAX(ISNULL(NULLIF(CustomerDescription, ''), '-')),
|
||
SalesQty = ISNULL(SUM(Qty1), 0),
|
||
SalesTL = ISNULL(SUM(TLAmount), 0),
|
||
SalesUSD = ISNULL(SUM(USDAmount), 0),
|
||
AvgPriceUSD = ISNULL(SUM(USDAmount) / NULLIF(SUM(Qty1), 0), 0),
|
||
InvoiceLineCount = COUNT(DISTINCT InvoiceLineID),
|
||
InvoiceCount = COUNT(DISTINCT InvoiceHeaderID),
|
||
CustomerCount = COUNT(DISTINCT CustomerCode),
|
||
LastRefNumber = MAX(InvoiceNumber)
|
||
FROM SalesLines
|
||
WHERE RN = 1
|
||
GROUP BY SalesDate, ProductCode, ColorCode, YakaKodu, ChannelCode, CustomerCountry, CustomerSegment, CustomerCode
|
||
`
|
||
}
|
||
|
||
func productPerformanceStockSQLUnused() string {
|
||
return `
|
||
;WITH ActiveWarehouses AS (
|
||
SELECT WarehouseCode
|
||
FROM (VALUES
|
||
('1-0-12'),('1.01.2014'),('1.02.2005'),('1.02.2004'),('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-29'),('1-0-28'),
|
||
('1-0-10'),('100'),('1.02.2006'),('1-0-42'),('1.01.2002'),
|
||
('1-0-52')
|
||
) W(WarehouseCode)
|
||
),
|
||
Raw AS (
|
||
SELECT
|
||
ProductCode = UPPER(LTRIM(RTRIM(S.ItemCode))),
|
||
ColorCode = UPPER(LTRIM(RTRIM(ISNULL(S.ColorCode, '')))),
|
||
YakaKodu = UPPER(LTRIM(RTRIM(ISNULL(S.ItemDim2Code, '')))),
|
||
MovementDate = CAST(S.DocumentDate AS date),
|
||
ProcessCode = CASE
|
||
WHEN LTRIM(RTRIM(ISNULL(S.ProcessCode, ''))) <> '' THEN LTRIM(RTRIM(S.ProcessCode))
|
||
ELSE LTRIM(RTRIM(ISNULL(S.InnerProcessCode, '')))
|
||
END,
|
||
InQty = SUM(S.In_Qty1),
|
||
OutQty = SUM(S.Out_Qty1),
|
||
NetQty = SUM(S.InventoryQty1)
|
||
FROM StockWithCost 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 (@p3 = '' OR UPPER(LTRIM(RTRIM(S.ItemCode))) LIKE @p3 + '%')
|
||
AND S.DocumentDate < DATEADD(DAY, 1, @p2)
|
||
GROUP BY
|
||
S.ItemCode,
|
||
S.ColorCode,
|
||
S.ItemDim2Code,
|
||
CAST(S.DocumentDate AS date),
|
||
CASE
|
||
WHEN LTRIM(RTRIM(ISNULL(S.ProcessCode, ''))) <> '' THEN LTRIM(RTRIM(S.ProcessCode))
|
||
ELSE LTRIM(RTRIM(ISNULL(S.InnerProcessCode, '')))
|
||
END
|
||
),
|
||
Opening AS (
|
||
SELECT
|
||
StockDate = @p1,
|
||
ProductCode,
|
||
ColorCode,
|
||
YakaKodu,
|
||
NetQty = SUM(NetQty),
|
||
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 Raw
|
||
WHERE MovementDate < @p1
|
||
GROUP BY ProductCode, ColorCode, YakaKodu
|
||
),
|
||
Daily AS (
|
||
SELECT
|
||
StockDate = MovementDate,
|
||
ProductCode,
|
||
ColorCode,
|
||
YakaKodu,
|
||
NetQty = SUM(NetQty),
|
||
InQty = SUM(InQty),
|
||
OutQty = SUM(OutQty),
|
||
KpiInQty = SUM(CASE WHEN ProcessCode IN ('OP','BP','CI') THEN InQty ELSE 0 END),
|
||
KpiOutQty = SUM(CASE WHEN ProcessCode IN ('R','WS','OC','CO') THEN OutQty ELSE 0 END),
|
||
SalesMovementQty = SUM(CASE WHEN ProcessCode IN ('R','WS') THEN OutQty ELSE 0 END),
|
||
ProductionInQty = SUM(CASE WHEN ProcessCode = 'OP' THEN InQty ELSE 0 END),
|
||
PurchaseInQty = SUM(CASE WHEN ProcessCode = 'BP' THEN InQty ELSE 0 END),
|
||
ConsumptionOutQty = SUM(CASE WHEN ProcessCode = 'OC' THEN OutQty ELSE 0 END),
|
||
CountDiffQty = SUM(CASE WHEN ProcessCode IN ('CO','CI') THEN NetQty ELSE 0 END)
|
||
FROM Raw
|
||
WHERE MovementDate BETWEEN @p1 AND @p2
|
||
GROUP BY MovementDate, ProductCode, ColorCode, YakaKodu
|
||
),
|
||
Series AS (
|
||
SELECT * FROM Opening
|
||
UNION ALL
|
||
SELECT * FROM Daily
|
||
),
|
||
Collapsed AS (
|
||
SELECT
|
||
StockDate,
|
||
ProductCode,
|
||
ColorCode,
|
||
YakaKodu,
|
||
NetQty = SUM(NetQty),
|
||
InQty = SUM(InQty),
|
||
OutQty = SUM(OutQty),
|
||
KpiInQty = SUM(KpiInQty),
|
||
KpiOutQty = SUM(KpiOutQty),
|
||
SalesMovementQty = SUM(SalesMovementQty),
|
||
ProductionInQty = SUM(ProductionInQty),
|
||
PurchaseInQty = SUM(PurchaseInQty),
|
||
ConsumptionOutQty = SUM(ConsumptionOutQty),
|
||
CountDiffQty = SUM(CountDiffQty)
|
||
FROM Series
|
||
GROUP BY StockDate, ProductCode, ColorCode, YakaKodu
|
||
),
|
||
Running AS (
|
||
SELECT
|
||
StockDate,
|
||
ProductCode,
|
||
ColorCode,
|
||
YakaKodu,
|
||
StockQty = SUM(NetQty) OVER (
|
||
PARTITION BY ProductCode, ColorCode, YakaKodu
|
||
ORDER BY StockDate
|
||
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||
),
|
||
InQty,
|
||
OutQty,
|
||
KpiInQty,
|
||
KpiOutQty,
|
||
SalesMovementQty,
|
||
ProductionInQty,
|
||
PurchaseInQty,
|
||
ConsumptionOutQty,
|
||
CountDiffQty
|
||
FROM Collapsed
|
||
)
|
||
SELECT
|
||
StockDate,
|
||
ProductCode,
|
||
ColorCode,
|
||
YakaKodu,
|
||
StockQty,
|
||
InQty,
|
||
OutQty,
|
||
KpiInQty,
|
||
KpiOutQty,
|
||
SalesMovementQty,
|
||
ProductionInQty,
|
||
PurchaseInQty,
|
||
ConsumptionOutQty,
|
||
CountDiffQty
|
||
FROM Running
|
||
WHERE StockDate BETWEEN @p1 AND @p2
|
||
ORDER BY StockDate, ProductCode, ColorCode, YakaKodu
|
||
`
|
||
}
|
||
|
||
func productPerformancePriceSQL() string {
|
||
return `
|
||
;WITH ProductCodes AS (
|
||
SELECT DISTINCT ItemCode
|
||
FROM cdItem WITH(NOLOCK)
|
||
WHERE ItemTypeCode = 1
|
||
AND LEN(LTRIM(RTRIM(ItemCode))) = 13
|
||
AND (@p1 = '' OR UPPER(LTRIM(RTRIM(ItemCode))) LIKE @p1 + '%')
|
||
UNION
|
||
SELECT DISTINCT ItemCode
|
||
FROM trPriceListLine WITH(NOLOCK)
|
||
WHERE ItemTypeCode = 1
|
||
AND LEN(LTRIM(RTRIM(ItemCode))) = 13
|
||
AND (@p1 = '' OR UPPER(LTRIM(RTRIM(ItemCode))) LIKE @p1 + '%')
|
||
UNION
|
||
SELECT DISTINCT ItemCode
|
||
FROM prItemBasePrice WITH(NOLOCK)
|
||
WHERE ItemTypeCode = 1
|
||
AND LEN(LTRIM(RTRIM(ItemCode))) = 13
|
||
AND (@p1 = '' OR UPPER(LTRIM(RTRIM(ItemCode))) LIKE @p1 + '%')
|
||
),
|
||
LatestPrice AS (
|
||
SELECT
|
||
p.ItemCode,
|
||
DocCurrencyCode = LTRIM(RTRIM(p.DocCurrencyCode)),
|
||
p.Price,
|
||
rn = ROW_NUMBER() OVER (
|
||
PARTITION BY p.ItemCode, LTRIM(RTRIM(p.DocCurrencyCode))
|
||
ORDER BY p.ValidDate DESC, p.ValidTime DESC, p.LastUpdatedDate DESC
|
||
)
|
||
FROM trPriceListLine p WITH(NOLOCK)
|
||
INNER JOIN ProductCodes pc ON pc.ItemCode = p.ItemCode
|
||
WHERE p.ItemTypeCode = 1
|
||
AND ISNULL(p.IsDisabled, 0) = 0
|
||
AND LTRIM(RTRIM(p.DocCurrencyCode)) IN ('USD', 'TRY')
|
||
AND (
|
||
(LTRIM(RTRIM(p.DocCurrencyCode)) = 'USD' AND LTRIM(RTRIM(p.PriceGroupCode)) = 'TM-USD')
|
||
OR (LTRIM(RTRIM(p.DocCurrencyCode)) = 'TRY' AND LTRIM(RTRIM(p.PriceGroupCode)) = 'TM-TRY')
|
||
)
|
||
AND p.Price > 0
|
||
),
|
||
BasePrice AS (
|
||
SELECT
|
||
ItemCode,
|
||
BasePriceUsd = MAX(CASE WHEN DocCurrencyCode = 'USD' THEN Price END),
|
||
BasePriceTry = MAX(CASE WHEN DocCurrencyCode = 'TRY' THEN Price END)
|
||
FROM LatestPrice
|
||
WHERE rn = 1
|
||
GROUP BY ItemCode
|
||
),
|
||
Cost AS (
|
||
SELECT
|
||
b.ItemCode,
|
||
CostPriceUsd = CAST(b.Price AS decimal(18,2)),
|
||
LastPricingDate = CAST(b.PriceDate AS date),
|
||
rn = ROW_NUMBER() OVER (
|
||
PARTITION BY b.ItemCode
|
||
ORDER BY b.PriceDate DESC, b.LastUpdatedDate DESC
|
||
)
|
||
FROM prItemBasePrice b WITH(NOLOCK)
|
||
INNER JOIN ProductCodes pc ON pc.ItemCode = b.ItemCode
|
||
WHERE b.ItemTypeCode = 1
|
||
AND b.BasePriceCode = 1
|
||
AND LTRIM(RTRIM(b.CurrencyCode)) = 'USD'
|
||
)
|
||
SELECT
|
||
UPPER(LTRIM(RTRIM(pc.ItemCode))) AS ItemCode,
|
||
ItemDescription = dbo.HG_Temizlik(ISNULL((
|
||
SELECT ItemDescription
|
||
FROM cdItemDesc WITH(NOLOCK)
|
||
WHERE cdItemDesc.ItemTypeCode = 1
|
||
AND cdItemDesc.ItemCode = pc.ItemCode
|
||
AND cdItemDesc.LangCode = 'TR'
|
||
), SPACE(0))),
|
||
Kategori = dbo.HG_Temizlik(ISNULL(paf.ProductAtt44, SPACE(0))),
|
||
AskiliYan = dbo.HG_Temizlik(ISNULL(paf.ProductAtt45, SPACE(0))),
|
||
UrunIlkGrubu = dbo.HG_Temizlik(ISNULL(paf.ProductAtt42, SPACE(0))),
|
||
UrunAnaGrubu = dbo.HG_Temizlik(ISNULL(paf.ProductAtt01, SPACE(0))),
|
||
UrunAltGrubu = dbo.HG_Temizlik(ISNULL(paf.ProductAtt02, SPACE(0))),
|
||
CostPriceUsd = ISNULL(c.CostPriceUsd, 0),
|
||
BasePriceUsd = ISNULL(bp.BasePriceUsd, 0),
|
||
BasePriceTry = ISNULL(bp.BasePriceTry, 0),
|
||
c.LastPricingDate
|
||
FROM ProductCodes pc
|
||
LEFT JOIN ProductAttributesFilter paf WITH(NOLOCK)
|
||
ON paf.ItemCode = pc.ItemCode
|
||
LEFT JOIN BasePrice bp ON bp.ItemCode = pc.ItemCode
|
||
LEFT JOIN Cost c ON c.ItemCode = pc.ItemCode AND c.rn = 1
|
||
`
|
||
}
|
||
|
||
func productPerformanceKPISQL() string {
|
||
return `
|
||
WITH LatestStock AS (
|
||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||
product_code, color_code, yaka_kodu, stock_qty
|
||
FROM mk_product_performance_stock_daily
|
||
WHERE stock_date <= $1
|
||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||
),
|
||
Stock90Start AS (
|
||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||
product_code, color_code, yaka_kodu, stock_qty
|
||
FROM mk_product_performance_stock_daily
|
||
WHERE stock_date <= $1::date - INTERVAL '89 days'
|
||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||
),
|
||
Stock180Start AS (
|
||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||
product_code, color_code, yaka_kodu, stock_qty
|
||
FROM mk_product_performance_stock_daily
|
||
WHERE stock_date <= $1::date - INTERVAL '179 days'
|
||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||
),
|
||
Stock365Start AS (
|
||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||
product_code, color_code, yaka_kodu, stock_qty
|
||
FROM mk_product_performance_stock_daily
|
||
WHERE stock_date <= $1::date - INTERVAL '359 days'
|
||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||
),
|
||
StockTotalStart AS (
|
||
SELECT DISTINCT ON (product_code, color_code, yaka_kodu)
|
||
product_code, color_code, yaka_kodu, stock_qty
|
||
FROM mk_product_performance_stock_daily
|
||
WHERE stock_date <= DATE '2022-01-01'
|
||
ORDER BY product_code, color_code, yaka_kodu, stock_date DESC
|
||
),
|
||
SalesAgg AS (
|
||
SELECT
|
||
product_code,
|
||
color_code,
|
||
yaka_kodu,
|
||
market_key,
|
||
MAX(item_description) AS item_description,
|
||
MAX(kategori) AS kategori,
|
||
MAX(seri) AS seri,
|
||
MAX(yas_grubu) AS yas_grubu,
|
||
COALESCE(MAX(NULLIF(askili_yan, '-')), '') AS askili_yan,
|
||
MAX(urun_ilk_grubu) AS urun_ilk_grubu,
|
||
MAX(urun_ana_grubu) AS urun_ana_grubu,
|
||
MAX(urun_alt_grubu) AS urun_alt_grubu,
|
||
SUM(sales_qty) FILTER (WHERE sales_date >= $1::date - INTERVAL '29 days') AS sales_qty_30d,
|
||
SUM(sales_qty) FILTER (WHERE sales_date >= $1::date - INTERVAL '89 days') AS sales_qty_90d,
|
||
SUM(sales_qty) FILTER (WHERE sales_date >= $1::date - INTERVAL '179 days') AS sales_qty_180d,
|
||
SUM(sales_qty) FILTER (WHERE sales_date >= $1::date - INTERVAL '359 days') AS sales_qty_365d,
|
||
SUM(sales_qty) FILTER (WHERE sales_date >= $1::date - INTERVAL '729 days') AS sales_qty_730d,
|
||
SUM(sales_qty) FILTER (WHERE sales_date >= DATE '2022-01-01') AS sales_qty_total,
|
||
SUM(sales_usd) FILTER (WHERE sales_date >= $1::date - INTERVAL '29 days') AS sales_usd_30d,
|
||
SUM(sales_usd) FILTER (WHERE sales_date >= $1::date - INTERVAL '89 days') AS sales_usd_90d,
|
||
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,
|
||
MAX(sales_date) AS last_sale_date,
|
||
MAX(last_ref_number) AS last_ref_number
|
||
FROM mk_product_performance_sales_daily
|
||
WHERE sales_date >= DATE '2022-01-01'
|
||
AND sales_date <= $1::date
|
||
AND upper(btrim(COALESCE(urun_ilk_grubu,''))) NOT IN ('MALZEMELI FASON', 'MALZEMESIZ FASON', 'DIGER')
|
||
GROUP BY product_code, color_code, yaka_kodu, market_key
|
||
),
|
||
Scope AS (
|
||
SELECT
|
||
product_code, color_code, yaka_kodu, market_key,
|
||
item_description, kategori, seri, yas_grubu, askili_yan, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu,
|
||
sales_qty_30d, sales_qty_90d, sales_qty_180d, sales_qty_365d, sales_qty_730d, sales_qty_total,
|
||
sales_usd_30d, sales_usd_90d, sales_usd_180d, sales_usd_365d, sales_usd_total,
|
||
customer_count_90d, last_sale_date, last_ref_number
|
||
FROM SalesAgg
|
||
UNION ALL
|
||
SELECT
|
||
ls.product_code,
|
||
ls.color_code,
|
||
ls.yaka_kodu,
|
||
'STOK' AS market_key,
|
||
'' AS item_description,
|
||
'' AS kategori,
|
||
'' AS seri,
|
||
'' AS yas_grubu,
|
||
'' AS askili_yan,
|
||
COALESCE(pd.urun_ilk_grubu, '') AS urun_ilk_grubu,
|
||
'' AS urun_ana_grubu,
|
||
'' AS urun_alt_grubu,
|
||
0 AS sales_qty_30d,
|
||
0 AS sales_qty_90d,
|
||
0 AS sales_qty_180d,
|
||
0 AS sales_qty_365d,
|
||
0 AS sales_qty_730d,
|
||
0 AS sales_qty_total,
|
||
0 AS sales_usd_30d,
|
||
0 AS sales_usd_90d,
|
||
0 AS sales_usd_180d,
|
||
0 AS sales_usd_365d,
|
||
0 AS sales_usd_total,
|
||
0 AS customer_count_90d,
|
||
NULL::date AS last_sale_date,
|
||
'' AS last_ref_number
|
||
FROM LatestStock ls
|
||
LEFT JOIN mk_product_performance_price_dim pd ON pd.product_code=ls.product_code
|
||
WHERE COALESCE(ls.stock_qty, 0) <> 0
|
||
AND upper(btrim(COALESCE(pd.urun_ilk_grubu,''))) NOT IN ('MALZEMELI FASON', 'MALZEMESIZ FASON', 'DIGER')
|
||
AND NOT EXISTS (
|
||
SELECT 1
|
||
FROM SalesAgg sa
|
||
WHERE sa.product_code = ls.product_code
|
||
AND sa.color_code = ls.color_code
|
||
AND sa.yaka_kodu = ls.yaka_kodu
|
||
)
|
||
),
|
||
PriceDim AS (
|
||
SELECT
|
||
product_code,
|
||
COALESCE(urun_ilk_grubu, '') AS urun_ilk_grubu,
|
||
COALESCE(urun_ana_grubu, '') AS urun_ana_grubu,
|
||
COALESCE(urun_alt_grubu, '') AS urun_alt_grubu,
|
||
CASE
|
||
WHEN cost_price_usd > 0 AND base_price_usd > 0 AND cost_price_usd < base_price_usd THEN base_price_usd
|
||
ELSE cost_price_usd
|
||
END AS cost_price_usd,
|
||
CASE
|
||
WHEN cost_price_usd > 0 AND base_price_usd > 0 AND cost_price_usd < base_price_usd THEN cost_price_usd
|
||
ELSE base_price_usd
|
||
END AS base_price_usd,
|
||
base_price_try
|
||
FROM mk_product_performance_price_dim
|
||
),
|
||
Base AS (
|
||
SELECT
|
||
s.*,
|
||
COALESCE(ls.stock_qty, 0) AS stock_qty,
|
||
COALESCE(pd.cost_price_usd, 0) AS cost_price_usd,
|
||
COALESCE(pd.base_price_usd, 0) AS base_price_usd,
|
||
COALESCE(pd.base_price_try, 0) AS base_price_try,
|
||
COALESCE(s.sales_qty_90d, 0) / 90.0 AS avg_daily_sales_90d,
|
||
COALESCE(s.sales_qty_180d, 0) / 180.0 AS avg_daily_sales_180d,
|
||
COALESCE(s.sales_qty_365d, 0) / 360.0 AS avg_daily_sales_365d,
|
||
COALESCE(s.sales_qty_total, 0) / GREATEST(1, ($1::date - DATE '2022-01-01') + 1) AS avg_daily_sales_total,
|
||
(COALESCE(s90.stock_qty, 0) + COALESCE(ls.stock_qty, 0)) / 2.0 AS avg_stock_90d,
|
||
(COALESCE(s180.stock_qty, 0) + COALESCE(ls.stock_qty, 0)) / 2.0 AS avg_stock_180d,
|
||
(COALESCE(s365.stock_qty, 0) + COALESCE(ls.stock_qty, 0)) / 2.0 AS avg_stock_365d,
|
||
(COALESCE(stotal.stock_qty, 0) + COALESCE(ls.stock_qty, 0)) / 2.0 AS avg_stock_total,
|
||
CASE WHEN COALESCE(s.sales_qty_90d, 0) = 0 THEN 0 ELSE COALESCE(s.sales_usd_90d, 0) / NULLIF(s.sales_qty_90d, 0) END AS avg_price_usd_90d,
|
||
CASE WHEN COALESCE(s.sales_qty_180d, 0) = 0 THEN 0 ELSE COALESCE(s.sales_usd_180d, 0) / NULLIF(s.sales_qty_180d, 0) END AS avg_price_usd_180d,
|
||
COALESCE(s.sales_usd_90d, 0) - (COALESCE(s.sales_qty_90d, 0) * COALESCE(pd.cost_price_usd, 0)) AS gross_profit_usd_90d,
|
||
COALESCE(s.sales_usd_180d, 0) - (COALESCE(s.sales_qty_180d, 0) * COALESCE(pd.cost_price_usd, 0)) AS gross_profit_usd_180d,
|
||
CASE WHEN COALESCE(s.sales_usd_90d, 0) = 0 THEN 0
|
||
ELSE (COALESCE(s.sales_usd_90d, 0) - (COALESCE(s.sales_qty_90d, 0) * COALESCE(pd.cost_price_usd, 0))) / NULLIF(s.sales_usd_90d, 0)
|
||
END AS gross_margin_90d,
|
||
CASE WHEN COALESCE(s.sales_usd_180d, 0) = 0 THEN 0
|
||
ELSE (COALESCE(s.sales_usd_180d, 0) - (COALESCE(s.sales_qty_180d, 0) * COALESCE(pd.cost_price_usd, 0))) / NULLIF(s.sales_usd_180d, 0)
|
||
END AS gross_margin_180d,
|
||
CASE WHEN COALESCE(s.sales_qty_90d, 0) = 0 THEN 0 ELSE (COALESCE(s.sales_usd_90d, 0) / NULLIF(s.sales_qty_90d, 0)) - COALESCE(pd.cost_price_usd, 0) END AS unit_profit_cost_90d,
|
||
CASE WHEN COALESCE(s.sales_qty_180d, 0) = 0 THEN 0 ELSE (COALESCE(s.sales_usd_180d, 0) / NULLIF(s.sales_qty_180d, 0)) - COALESCE(pd.cost_price_usd, 0) END AS unit_profit_cost_180d,
|
||
CASE WHEN COALESCE(s.sales_qty_90d, 0) = 0 THEN 0 ELSE (COALESCE(s.sales_usd_90d, 0) / NULLIF(s.sales_qty_90d, 0)) - COALESCE(pd.base_price_usd, 0) END AS unit_profit_base_90d,
|
||
CASE WHEN COALESCE(s.sales_qty_180d, 0) = 0 THEN 0 ELSE (COALESCE(s.sales_usd_180d, 0) / NULLIF(s.sales_qty_180d, 0)) - COALESCE(pd.base_price_usd, 0) END AS unit_profit_base_180d
|
||
FROM Scope s
|
||
LEFT JOIN LatestStock ls ON ls.product_code=s.product_code AND ls.color_code=s.color_code AND ls.yaka_kodu=s.yaka_kodu
|
||
LEFT JOIN Stock90Start s90 ON s90.product_code=s.product_code AND s90.color_code=s.color_code AND s90.yaka_kodu=s.yaka_kodu
|
||
LEFT JOIN Stock180Start s180 ON s180.product_code=s.product_code AND s180.color_code=s.color_code AND s180.yaka_kodu=s.yaka_kodu
|
||
LEFT JOIN Stock365Start s365 ON s365.product_code=s.product_code AND s365.color_code=s.color_code AND s365.yaka_kodu=s.yaka_kodu
|
||
LEFT JOIN StockTotalStart stotal ON stotal.product_code=s.product_code AND stotal.color_code=s.color_code AND stotal.yaka_kodu=s.yaka_kodu
|
||
LEFT JOIN PriceDim pd ON pd.product_code=s.product_code
|
||
WHERE upper(btrim(COALESCE(NULLIF(s.urun_ilk_grubu,''), pd.urun_ilk_grubu, ''))) NOT IN ('MALZEMELI FASON', 'MALZEMESIZ FASON', 'DIGER')
|
||
),
|
||
Spread AS (
|
||
SELECT
|
||
product_code,
|
||
color_code,
|
||
yaka_kodu,
|
||
COUNT(DISTINCT market_key) AS market_count_90d
|
||
FROM SalesAgg
|
||
WHERE COALESCE(sales_qty_90d, 0) > 0
|
||
GROUP BY product_code, color_code, yaka_kodu
|
||
),
|
||
Market AS (
|
||
SELECT
|
||
market_key,
|
||
AVG(NULLIF(sales_qty_90d, 0)) AS market_avg_sales_qty_90d,
|
||
AVG(NULLIF(avg_price_usd_90d, 0)) AS market_avg_price_usd_90d,
|
||
AVG(NULLIF(gross_margin_90d, 0)) AS market_avg_margin_90d
|
||
FROM Base
|
||
GROUP BY market_key
|
||
),
|
||
Scored AS (
|
||
SELECT
|
||
b.*,
|
||
COALESCE(sp.market_count_90d, 0) AS market_count_90d,
|
||
CASE WHEN b.avg_daily_sales_90d = 0 THEN 0 ELSE b.avg_stock_90d / NULLIF(b.avg_daily_sales_90d, 0) END AS stock_days_90d,
|
||
CASE WHEN b.avg_daily_sales_180d = 0 THEN 0 ELSE b.avg_stock_180d / NULLIF(b.avg_daily_sales_180d, 0) END AS stock_days_180d,
|
||
CASE WHEN b.avg_daily_sales_365d = 0 THEN 0 ELSE b.avg_stock_365d / NULLIF(b.avg_daily_sales_365d, 0) END AS stock_days_365d,
|
||
CASE WHEN b.avg_daily_sales_total = 0 THEN 0 ELSE b.avg_stock_total / NULLIF(b.avg_daily_sales_total, 0) END AS stock_days_total,
|
||
CASE WHEN b.avg_stock_90d = 0 THEN 0 ELSE b.sales_qty_90d / NULLIF(b.avg_stock_90d, 0) END AS stock_turnover_90d,
|
||
CASE WHEN b.avg_stock_180d = 0 THEN 0 ELSE b.sales_qty_180d / NULLIF(b.avg_stock_180d, 0) END AS stock_turnover_180d,
|
||
CASE WHEN b.avg_stock_365d = 0 THEN 0 ELSE b.sales_qty_365d / NULLIF(b.avg_stock_365d, 0) END AS stock_turnover_365d,
|
||
CASE WHEN b.avg_stock_total = 0 THEN 0 ELSE b.sales_qty_total / NULLIF(b.avg_stock_total, 0) END AS stock_turnover_total,
|
||
CASE WHEN COALESCE(m.market_avg_sales_qty_90d, 0) = 0 THEN 0 ELSE b.sales_qty_90d / NULLIF(m.market_avg_sales_qty_90d, 0) END AS sales_index_90d,
|
||
CASE WHEN COALESCE(m.market_avg_price_usd_90d, 0) = 0 THEN 0 ELSE b.avg_price_usd_90d / NULLIF(m.market_avg_price_usd_90d, 0) END AS price_index_90d,
|
||
CASE WHEN COALESCE(m.market_avg_margin_90d, 0) = 0 THEN 0 ELSE b.gross_margin_90d / NULLIF(m.market_avg_margin_90d, 0) END AS margin_index_90d
|
||
FROM Base b
|
||
LEFT JOIN Market m ON m.market_key=b.market_key
|
||
LEFT JOIN Spread sp ON sp.product_code=b.product_code AND sp.color_code=b.color_code AND sp.yaka_kodu=b.yaka_kodu
|
||
)
|
||
INSERT INTO mk_product_performance_kpi_daily (
|
||
kpi_date, product_code, color_code, yaka_kodu, item_description,
|
||
kategori, seri, yas_grubu, askili_yan, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu, market_key, stock_qty,
|
||
sales_qty_30d, sales_qty_90d, sales_qty_180d, sales_qty_365d, sales_qty_730d, sales_qty_total,
|
||
sales_usd_30d, sales_usd_90d, sales_usd_180d, sales_usd_365d, sales_usd_total, avg_daily_sales_90d, avg_daily_sales_180d, avg_daily_sales_365d, avg_daily_sales_total,
|
||
stock_days_90d, stock_days_180d, stock_days_365d, stock_days_total, stock_turnover_90d, stock_turnover_180d, stock_turnover_365d, stock_turnover_total,
|
||
avg_price_usd_90d, avg_price_usd_180d, cost_price_usd, base_price_usd, base_price_try,
|
||
gross_profit_usd_90d, gross_profit_usd_180d, gross_margin_90d, gross_margin_180d,
|
||
unit_profit_cost_90d, unit_profit_cost_180d, unit_profit_base_90d, unit_profit_base_180d, market_count_90d, customer_count_90d,
|
||
sales_index_90d, price_index_90d, margin_index_90d, performance_score,
|
||
performance_bucket, recommendation, last_sale_date, last_ref_number, updated_at
|
||
)
|
||
SELECT
|
||
$1::date,
|
||
product_code, color_code, yaka_kodu, item_description,
|
||
kategori, seri, yas_grubu, askili_yan, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu, market_key, stock_qty,
|
||
COALESCE(sales_qty_30d, 0), COALESCE(sales_qty_90d, 0), COALESCE(sales_qty_180d, 0), COALESCE(sales_qty_365d, 0), COALESCE(sales_qty_730d, 0), COALESCE(sales_qty_total, 0),
|
||
COALESCE(sales_usd_30d, 0), COALESCE(sales_usd_90d, 0), COALESCE(sales_usd_180d, 0), COALESCE(sales_usd_365d, 0), COALESCE(sales_usd_total, 0), COALESCE(avg_daily_sales_90d, 0), COALESCE(avg_daily_sales_180d, 0), COALESCE(avg_daily_sales_365d, 0), COALESCE(avg_daily_sales_total, 0),
|
||
COALESCE(stock_days_90d, 0), COALESCE(stock_days_180d, 0), COALESCE(stock_days_365d, 0), COALESCE(stock_days_total, 0), COALESCE(stock_turnover_90d, 0), COALESCE(stock_turnover_180d, 0), COALESCE(stock_turnover_365d, 0), COALESCE(stock_turnover_total, 0),
|
||
COALESCE(avg_price_usd_90d, 0), COALESCE(avg_price_usd_180d, 0), COALESCE(cost_price_usd, 0), COALESCE(base_price_usd, 0), COALESCE(base_price_try, 0),
|
||
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_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'
|
||
WHEN COALESCE(stock_days_90d,0) > 180 AND COALESCE(sales_index_90d,0) < 0.75 THEN 'STOK_RISKI'
|
||
WHEN COALESCE(price_index_90d,0) > 1.10 AND COALESCE(sales_index_90d,0) < 0.80 THEN 'FIYAT_BASKISI'
|
||
WHEN COALESCE(price_index_90d,0) < 0.90 AND COALESCE(sales_index_90d,0) > 1.00 THEN 'FIYAT_FIRSATI'
|
||
ELSE 'TAKIP'
|
||
END AS performance_bucket,
|
||
CASE
|
||
WHEN COALESCE(sales_index_90d,0) >= 1.25 AND COALESCE(gross_margin_90d,0) >= 0.25 THEN 'Piyasa üstü satış ve iyi marj: stok ve fiyat gücü takip edilmeli.'
|
||
WHEN COALESCE(stock_qty,0) <= 0 AND COALESCE(sales_qty_90d,0) > 0 THEN 'Talep var, stok yok: üretim/satın alma planına alınmalı.'
|
||
WHEN COALESCE(stock_days_90d,0) > 180 AND COALESCE(sales_index_90d,0) < 0.75 THEN 'Stok yüksek, satış piyasa altı: kampanya veya fiyat kontrolü gerekli.'
|
||
WHEN COALESCE(price_index_90d,0) > 1.10 AND COALESCE(sales_index_90d,0) < 0.80 THEN 'Fiyat piyasa üstünde ve satış zayıf: fiyat revizyonu değerlendirilmeli.'
|
||
WHEN COALESCE(price_index_90d,0) < 0.90 AND COALESCE(sales_index_90d,0) > 1.00 THEN 'Satış güçlü, fiyat piyasa altı: taban fiyat artışı değerlendirilebilir.'
|
||
ELSE 'Düzenli takip.'
|
||
END AS recommendation,
|
||
last_sale_date,
|
||
COALESCE(last_ref_number, ''),
|
||
now()
|
||
FROM Scored
|
||
`
|
||
}
|