diff --git a/svc/queries/product_performance.go b/svc/queries/product_performance.go index b27d9a8..54bc491 100644 --- a/svc/queries/product_performance.go +++ b/svc/queries/product_performance.go @@ -347,6 +347,10 @@ CREATE TABLE IF NOT EXISTS mk_product_performance_sales_daily ( `ALTER TABLE mk_product_performance_sales_daily ADD COLUMN IF NOT EXISTS urun_ana_grubu TEXT NOT NULL DEFAULT ''`, `ALTER TABLE mk_product_performance_sales_daily ADD COLUMN IF NOT EXISTS urun_alt_grubu TEXT NOT NULL DEFAULT ''`, ` +UPDATE mk_product_performance_sales_daily +SET urun_ilk_grubu = '', updated_at = now() +WHERE upper(translate(btrim(urun_ilk_grubu), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON')`, + ` DO $$ BEGIN IF EXISTS ( @@ -457,6 +461,10 @@ CREATE TABLE IF NOT EXISTS mk_product_performance_kpi_daily ( `ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS urun_ilk_grubu TEXT NOT NULL DEFAULT ''`, `ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS urun_ana_grubu TEXT NOT NULL DEFAULT ''`, `ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS urun_alt_grubu TEXT NOT NULL DEFAULT ''`, + ` +UPDATE mk_product_performance_kpi_daily +SET urun_ilk_grubu = '', updated_at = now() +WHERE upper(translate(btrim(urun_ilk_grubu), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON')`, `ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS sales_qty_180d NUMERIC(18,4) NOT NULL DEFAULT 0`, `ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS sales_usd_180d NUMERIC(18,4) NOT NULL DEFAULT 0`, `ALTER TABLE mk_product_performance_kpi_daily ADD COLUMN IF NOT EXISTS avg_daily_sales_180d NUMERIC(18,6) NOT NULL DEFAULT 0`, @@ -667,6 +675,7 @@ func refreshProductPerformanceSales(ctx context.Context, tx *sql.Tx, startDate, ); err != nil { return count, err } + r.UrunIlkGrubu = cleanProductPerformanceFirstGroup(r.UrunIlkGrubu) if _, err := tx.ExecContext(ctx, ` INSERT INTO mk_product_performance_sales_daily ( sales_date, product_code, color_code, yaka_kodu, item_description, @@ -1001,6 +1010,7 @@ LIMIT $`+fmt.Sprint(len(args)-1)+` OFFSET $`+fmt.Sprint(len(args)), args...) ); err != nil { return nil, 0, err } + r.UrunIlkGrubu = cleanProductPerformanceFirstGroup(r.UrunIlkGrubu) out = append(out, r) } return out, total, rows.Err() @@ -1340,6 +1350,7 @@ LIMIT $1 ); err != nil { return nil, err } + r.UrunIlkGrubu = cleanProductPerformanceFirstGroup(r.UrunIlkGrubu) out = append(out, r) } return out, rows.Err() @@ -2172,6 +2183,7 @@ LIMIT $1 ); err != nil { return nil, err } + r.UrunIlkGrubu = cleanProductPerformanceFirstGroup(r.UrunIlkGrubu) out = append(out, r) } return out, rows.Err() @@ -2324,7 +2336,7 @@ func ListProductPerformanceSalesBreakdown(ctx context.Context, pg *sql.DB, break "item_description": "MAX(s.item_description)", "kategori": "COALESCE(MAX(s.kategori),'')", "askili_yan": "MAX(s.askili_yan)", - "urun_ilk_grubu": "COALESCE(MAX(s.urun_ilk_grubu),'')", + "urun_ilk_grubu": "COALESCE(MAX(CASE WHEN upper(translate(btrim(COALESCE(s.urun_ilk_grubu,'')), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON') THEN '' ELSE s.urun_ilk_grubu END),'')", "urun_ana_grubu": "COALESCE(MAX(s.urun_ana_grubu),'')", "urun_alt_grubu": "MAX(s.urun_alt_grubu)", "market_key": "s.market_key", @@ -2351,7 +2363,7 @@ func ListProductPerformanceSalesBreakdown(ctx context.Context, pg *sql.DB, break selected["market_key"] = true selected["customer_code"] = true selected["customer_name"] = true - groupCols = []string{"s.color_code", "s.yaka_kodu", "s.urun_ilk_grubu", "s.askili_yan", "s.kategori", "s.urun_ana_grubu", "s.urun_alt_grubu", "s.product_code", "s.customer_country", "s.market_key", "s.customer_segment", "s.customer_code"} + groupCols = []string{"CASE WHEN upper(translate(btrim(COALESCE(s.urun_ilk_grubu,'')), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON') THEN '' ELSE s.urun_ilk_grubu END", "s.color_code", "s.yaka_kodu", "s.askili_yan", "s.kategori", "s.urun_ana_grubu", "s.urun_alt_grubu", "s.product_code", "s.customer_country", "s.market_key", "s.customer_segment", "s.customer_code"} case "product_country_segment_market_customer": selected["product_code"] = true selected["item_description"] = true @@ -2414,7 +2426,7 @@ func ListProductPerformanceSalesBreakdown(ctx context.Context, pg *sql.DB, break selected["market_key"] = true selected["customer_code"] = true selected["customer_name"] = true - groupCols = []string{"s.color_code", "s.yaka_kodu", "s.urun_ilk_grubu", "s.askili_yan", "s.kategori", "s.urun_ana_grubu", "s.urun_alt_grubu", "s.product_code", "s.customer_country", "s.market_key", "s.customer_segment", "s.customer_code"} + groupCols = []string{"CASE WHEN upper(translate(btrim(COALESCE(s.urun_ilk_grubu,'')), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON') THEN '' ELSE s.urun_ilk_grubu END", "s.color_code", "s.yaka_kodu", "s.askili_yan", "s.kategori", "s.urun_ana_grubu", "s.urun_alt_grubu", "s.product_code", "s.customer_country", "s.market_key", "s.customer_segment", "s.customer_code"} } selectExpr := func(name string) string { @@ -2432,7 +2444,10 @@ WITH LatestKPI AS ( yaka_kodu, COALESCE(kategori,'') AS kategori, askili_yan, - COALESCE(urun_ilk_grubu,'') AS urun_ilk_grubu, + CASE + WHEN upper(translate(btrim(COALESCE(urun_ilk_grubu,'')), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON') THEN '' + ELSE COALESCE(urun_ilk_grubu,'') + END AS urun_ilk_grubu, COALESCE(urun_ana_grubu,'') AS urun_ana_grubu, urun_alt_grubu FROM mk_product_performance_kpi_daily @@ -3027,7 +3042,10 @@ WITH Source AS ( seri, yas_grubu, askili_yan, - COALESCE(urun_ilk_grubu,'') AS urun_ilk_grubu, + CASE + WHEN upper(translate(btrim(COALESCE(urun_ilk_grubu,'')), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON') THEN '' + ELSE COALESCE(urun_ilk_grubu,'') + END AS urun_ilk_grubu, COALESCE(urun_ana_grubu,'') AS urun_ana_grubu, urun_alt_grubu, market_key, @@ -3066,7 +3084,9 @@ WITH Source AS ( func productPerformanceSQLGroupExpr(field string) (string, bool) { switch field { - case "kategori", "askili_yan", "urun_ilk_grubu", "urun_ana_grubu", "urun_alt_grubu", "product_code", "item_description", "color_code", "yaka_kodu": + case "urun_ilk_grubu": + return "CASE WHEN upper(translate(btrim(COALESCE(urun_ilk_grubu,'')), 'İŞĞÜÖÇ', 'ISGUOC')) IN ('YETISKIN', 'YETISKIN/GARSON', 'GARSON') THEN '' ELSE COALESCE(urun_ilk_grubu,'') END", true + case "kategori", "askili_yan", "urun_ana_grubu", "urun_alt_grubu", "product_code", "item_description", "color_code", "yaka_kodu": return field, true case "market_key": return "btrim(regexp_replace(COALESCE(market_key,''), '^.*\\|', ''))", true @@ -4008,6 +4028,7 @@ ORDER BY product_code, color_code, yaka_kodu, performance_score DESC if err := rows.Scan(&productCode, &colorCode, &yakaKodu, &p.itemDescription, &p.kategori, &p.askiliYan, &p.urunIlkGrubu, &p.urunAnaGrubu, &p.urunAltGrubu); err != nil { return nil, err } + p.urunIlkGrubu = cleanProductPerformanceFirstGroup(p.urunIlkGrubu) out[productPerformanceVariantKey(productCode, colorCode, yakaKodu)] = p } return out, rows.Err() diff --git a/ui/src/pages/ProductPerformanceProfitability.vue b/ui/src/pages/ProductPerformanceProfitability.vue index e77213d..23a3f48 100644 --- a/ui/src/pages/ProductPerformanceProfitability.vue +++ b/ui/src/pages/ProductPerformanceProfitability.vue @@ -3844,10 +3844,12 @@ async function loadBackendGroupedRows () { } function normalizeGroupedDisplayRow (tabKey, row) { + const nextRow = { ...row } + normalizeGroupedProductHierarchyValues(nextRow) if (tabKey === 'order_product_customers' || tabKey === 'order_market_details') { - return withOrderPeriodScores({ ...row }) + return withOrderPeriodScores(nextRow) } - const next = withPeriodScores({ ...row }) + const next = withPeriodScores(nextRow) if (tabKey !== 'products' && tabKey !== 'idle') { next.customer_score_90d = Number(next.customer_score_90d || customerSalesPeriodScore(periodMetricSource(next, '90d'))) next.customer_score_180d = Number(next.customer_score_180d || customerSalesPeriodScore(periodMetricSource(next, '180d'))) @@ -3857,6 +3859,17 @@ function normalizeGroupedDisplayRow (tabKey, row) { return next } +function normalizeGroupedProductHierarchyValues (row) { + row.urun_ilk_grubu = cleanProductFirstGroupValue(row.urun_ilk_grubu) + if (row.__group && row.group_field === 'urun_ilk_grubu') { + const cleanValue = cleanProductFirstGroupValue(row.group_value || row.label || row.urun_ilk_grubu) + row.group_value = cleanValue + row.label = cleanValue + row.urun_ilk_grubu = cleanValue + } + return row +} + function responseRowCount (data) { if (Array.isArray(data)) return data.length if (Array.isArray(data?.rows)) return data.rows.length