From 701cc5e4395306a7e2d89e7a95a13c091670c948 Mon Sep 17 00:00:00 2001 From: M_Kececi Date: Wed, 24 Jun 2026 23:08:28 +0300 Subject: [PATCH] ui: add B2B olmayan stok (orphans) page --- svc/routes/product_series.go | 121 ++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/svc/routes/product_series.go b/svc/routes/product_series.go index 17e52ab..e81521f 100644 --- a/svc/routes/product_series.go +++ b/svc/routes/product_series.go @@ -353,14 +353,73 @@ WHERE product_code = ANY($1) existing, _ := loadProductSeriesAssignments(ctx, pg, codes) // Per-request cache for per-mmitem dimval3 inference to avoid repeated dfblob scans. + inferCache := map[string]int64{} + inferDim3ForMmitem := func(mmitemID int64, token string) int64 { + mmitemID = int64(mmitemID) + tok := strings.ToUpper(normalizeDimParam(token)) + if mmitemID <= 0 || tok == "" { + return 0 + } + key := fmt.Sprintf("%d|%s", mmitemID, tok) + if v, ok := inferCache[key]; ok { + return v + } + patterns := buildNameLikePatterns(tok) + if len(patterns) == 0 { + inferCache[key] = 0 + return 0 + } + var dimv string + err := pg.QueryRowContext(ctx, ` +SELECT x.dimv +FROM ( + SELECT COALESCE(dimval3::text, '') AS dimv, COUNT(*) AS cnt + FROM dfblob + WHERE src_table='mmitem' + AND typ='img' + AND src_id=$7 + AND COALESCE(dimval3::text, '') <> '' + AND ( + UPPER(COALESCE(file_name,'')) LIKE $1 OR + UPPER(COALESCE(file_name,'')) LIKE $2 OR + UPPER(COALESCE(file_name,'')) LIKE $3 OR + UPPER(COALESCE(file_name,'')) LIKE $4 OR + UPPER(COALESCE(file_name,'')) LIKE $5 OR + UPPER(COALESCE(file_name,'')) LIKE $6 + ) + GROUP BY COALESCE(dimval3::text, '') +) x +ORDER BY x.cnt DESC, x.dimv +LIMIT 1 +`, patterns[0], patterns[1], patterns[2], patterns[3], patterns[4], patterns[5], mmitemID).Scan(&dimv) + if err != nil { + inferCache[key] = 0 + return 0 + } + dimv = strings.TrimSpace(dimv) + if dimv == "" || dimv == "0" { + inferCache[key] = 0 + return 0 + } + id, err := strconv.ParseInt(dimv, 10, 64) + if err != nil || id <= 0 { + inferCache[key] = 0 + return 0 + } + inferCache[key] = id + return id + } + out := make([]productSeriesMappingRow, 0, len(grouped)) for _, row := range grouped { row.MmitemID = mmitemByCode[row.ProductCode] row.Dim1ID = dim1ByToken[row.ColorCode] if row.Dim3Code != "" { - // Strict: only accept explicit token map rows for dimval3. + // Prefer token map; fallback to per-item inference (do not persist). if v := dim3ByToken[row.Dim3Code]; v > 0 { row.Dim3ID = v + } else if inferred := inferDim3ForMmitem(row.MmitemID, row.Dim3Code); inferred > 0 { + row.Dim3ID = inferred } } // Only show variants that are also known/valid on the PG side (product_code + dim1 + dim3_key). @@ -582,6 +641,64 @@ WHERE product_code = ANY($1) dim3ByToken, _ := loadDimTokenIDsStrict(ctx, pg, "dimval3", setToSortedSlice(dim3Set)) combos, _ := loadProductDimCombos(ctx, pg, codes) + // Per-request cache for per-mmitem dimval3 inference (dfblob scan). + inferCache := map[string]int64{} + inferDim3ForMmitem := func(mmitemID int64, token string) int64 { + mmitemID = int64(mmitemID) + tok := strings.ToUpper(normalizeDimParam(token)) + if mmitemID <= 0 || tok == "" { + return 0 + } + key := fmt.Sprintf("%d|%s", mmitemID, tok) + if v, ok := inferCache[key]; ok { + return v + } + patterns := buildNameLikePatterns(tok) + if len(patterns) == 0 { + inferCache[key] = 0 + return 0 + } + var dimv string + err := pg.QueryRowContext(ctx, ` +SELECT x.dimv +FROM ( + SELECT COALESCE(dimval3::text, '') AS dimv, COUNT(*) AS cnt + FROM dfblob + WHERE src_table='mmitem' + AND typ='img' + AND src_id=$7 + AND COALESCE(dimval3::text, '') <> '' + AND ( + UPPER(COALESCE(file_name,'')) LIKE $1 OR + UPPER(COALESCE(file_name,'')) LIKE $2 OR + UPPER(COALESCE(file_name,'')) LIKE $3 OR + UPPER(COALESCE(file_name,'')) LIKE $4 OR + UPPER(COALESCE(file_name,'')) LIKE $5 OR + UPPER(COALESCE(file_name,'')) LIKE $6 + ) + GROUP BY COALESCE(dimval3::text, '') +) x +ORDER BY x.cnt DESC, x.dimv +LIMIT 1 +`, patterns[0], patterns[1], patterns[2], patterns[3], patterns[4], patterns[5], mmitemID).Scan(&dimv) + if err != nil { + inferCache[key] = 0 + return 0 + } + dimv = strings.TrimSpace(dimv) + if dimv == "" || dimv == "0" { + inferCache[key] = 0 + return 0 + } + id, err := strconv.ParseInt(dimv, 10, 64) + if err != nil || id <= 0 { + inferCache[key] = 0 + return 0 + } + inferCache[key] = id + return id + } + out := make([]productSeriesMappingRow, 0, len(grouped)) for _, row := range grouped { if row.TotalQty <= 0 { @@ -592,6 +709,8 @@ WHERE product_code = ANY($1) if row.Dim3Code != "" { if v := dim3ByToken[row.Dim3Code]; v > 0 { row.Dim3ID = v + } else if inferred := inferDim3ForMmitem(row.MmitemID, row.Dim3Code); inferred > 0 { + row.Dim3ID = inferred } }