Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-06-19 12:59:06 +03:00
parent 3732004a29
commit a2f70160bc

View File

@@ -774,6 +774,19 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
hasMMItemDim := make(map[int64]bool, len(itemIDs)) hasMMItemDim := make(map[int64]bool, len(itemIDs))
dim1IDs := make([]int64, 0, 8192) dim1IDs := make([]int64, 0, 8192)
dim3IDs := make([]int64, 0, 8192) dim3IDs := make([]int64, 0, 8192)
itemDim1Candidates := make(map[int64][]int64, len(itemIDs))
itemDim3Candidates := make(map[int64][]int64, len(itemIDs))
addCandidate := func(dst map[int64][]int64, itemID int64, id int64) {
if itemID <= 0 || id <= 0 {
return
}
for _, existing := range dst[itemID] {
if existing == id {
return
}
}
dst[itemID] = append(dst[itemID], id)
}
if len(itemIDs) > 0 { if len(itemIDs) > 0 {
rows, err := pg.QueryContext(ctx, ` rows, err := pg.QueryContext(ctx, `
SELECT mmitem_id, mmdim_id, val1, val2, val3 SELECT mmitem_id, mmdim_id, val1, val2, val3
@@ -804,9 +817,11 @@ WHERE mmitem_id = ANY($1::bigint[])
d1 := v1.Int64 d1 := v1.Int64
_ = mmdimID _ = mmdimID
_ = v2 _ = v2
addCandidate(itemDim1Candidates, itemID, d1)
d3k := int64(0) d3k := int64(0)
if v3.Valid && v3.Int64 > 0 { if v3.Valid && v3.Int64 > 0 {
d3k = v3.Int64 d3k = v3.Int64
addCandidate(itemDim3Candidates, itemID, d3k)
} }
code := strings.TrimSpace(itemToCode[itemID]) code := strings.TrimSpace(itemToCode[itemID])
@@ -927,6 +942,84 @@ LIMIT 1
return "" return ""
} }
sortDimIDs := func(ids []int64) []int64 {
out := append([]int64(nil), ids...)
sort.Slice(out, func(i, j int) bool { return out[i] < out[j] })
return out
}
sortTokens := func(tokens []string) []string {
out := append([]string(nil), tokens...)
sort.Slice(out, func(i, j int) bool {
li := strings.TrimLeft(out[i], "0")
lj := strings.TrimLeft(out[j], "0")
if li == "" {
li = "0"
}
if lj == "" {
lj = "0"
}
ni, ei := strconv.ParseInt(li, 10, 64)
nj, ej := strconv.ParseInt(lj, 10, 64)
if ei == nil && ej == nil && ni != nj {
return ni < nj
}
return out[i] < out[j]
})
return out
}
addToken := func(dst map[int64][]string, itemID int64, token string) {
token = strings.ToUpper(normalizeDimParam(token))
if itemID <= 0 || token == "" {
return
}
for _, existing := range dst[itemID] {
if existing == token {
return
}
}
dst[itemID] = append(dst[itemID], token)
}
buildInferredMap := func(column string, tokenByItem map[int64][]string, idsByItem map[int64][]int64) map[string]int64 {
out := make(map[string]int64, 128)
for itemID, tokens := range tokenByItem {
sortedTokens := sortTokens(tokens)
sortedIDs := sortDimIDs(idsByItem[itemID])
if len(sortedTokens) == 0 || len(sortedTokens) != len(sortedIDs) {
continue
}
for i, token := range sortedTokens {
id := sortedIDs[i]
if token == "" || id <= 0 {
continue
}
key := column + "|" + token
if _, exists := out[key]; !exists {
out[key] = id
}
}
}
return out
}
persistDimToken := func(column string, token string, id int64) {
token = strings.ToUpper(normalizeDimParam(token))
if column == "" || token == "" || id <= 0 {
return
}
_, _ = pg.ExecContext(ctx, `
INSERT INTO mk_dim_token_map (dim_column, token, dim_id, updated_at)
VALUES ($1,$2,$3,now())
ON CONFLICT (dim_column, token)
DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
`, column, token, id)
}
type msVariantRow struct {
ItemCode string
ColorCode string
Dim1Code string
Dim3Code string
Qty sql.NullFloat64
}
// MSSQL: stock list for selected products; map to (mmitem_id, dim1, dim3_key) via token->id mapping. // MSSQL: stock list for selected products; map to (mmitem_id, dim1, dim3_key) via token->id mapping.
joined := strings.Join(codes, ",") joined := strings.Join(codes, ",")
msRows, err := mssql.QueryContext(ctx, queries.GetWholesaleCampaignVariantStockByProducts, joined) msRows, err := mssql.QueryContext(ctx, queries.GetWholesaleCampaignVariantStockByProducts, joined)
@@ -934,11 +1027,14 @@ LIMIT 1
http.Error(w, "variant stock query error: "+err.Error(), http.StatusInternalServerError) http.Error(w, "variant stock query error: "+err.Error(), http.StatusInternalServerError)
return return
} }
defer msRows.Close() msVariants := make([]msVariantRow, 0, 1024)
colorTokensByItem := make(map[int64][]string, len(itemIDs))
dim3TokensByItem := make(map[int64][]string, len(itemIDs))
for msRows.Next() { for msRows.Next() {
var itemCode, colorCode, dim1Code, dim3Code string var itemCode, colorCode, dim1Code, dim3Code string
var qty sql.NullFloat64 var qty sql.NullFloat64
if err := msRows.Scan(&itemCode, &colorCode, &dim1Code, &dim3Code, &qty); err != nil { if err := msRows.Scan(&itemCode, &colorCode, &dim1Code, &dim3Code, &qty); err != nil {
msRows.Close()
http.Error(w, "variant stock scan error", http.StatusInternalServerError) http.Error(w, "variant stock scan error", http.StatusInternalServerError)
return return
} }
@@ -950,18 +1046,62 @@ LIMIT 1
if itemID <= 0 { if itemID <= 0 {
continue continue
} }
msVariants = append(msVariants, msVariantRow{
ItemCode: itemCode,
ColorCode: colorCode,
Dim1Code: dim1Code,
Dim3Code: dim3Code,
Qty: qty,
})
addToken(colorTokensByItem, itemID, colorCode)
addToken(dim3TokensByItem, itemID, dim3Code)
}
if err := msRows.Err(); err != nil {
msRows.Close()
http.Error(w, "variant stock rows error", http.StatusInternalServerError)
return
}
msRows.Close()
inferredDim1 := buildInferredMap("dimval1", colorTokensByItem, itemDim1Candidates)
inferredDim3 := buildInferredMap("dimval3", dim3TokensByItem, itemDim3Candidates)
resolveProductDimID := func(column string, token string, inferred map[string]int64) (int64, bool) {
if id, ok := resolveDimID(column, token); ok {
return id, true
}
token = strings.ToUpper(normalizeDimParam(token))
if token == "" {
return 0, false
}
if id := inferred[column+"|"+token]; id > 0 {
persistDimToken(column, token, id)
return id, true
}
return 0, false
}
for _, ms := range msVariants {
itemCode := ms.ItemCode
colorCode := ms.ColorCode
dim1Code := ms.Dim1Code
dim3Code := ms.Dim3Code
qty := ms.Qty
itemID := codeToItem[itemCode]
if itemID <= 0 {
continue
}
// Map Nebim tokens to PG integer ids. Color and yaka must use separate token namespaces, // Map Nebim tokens to PG integer ids. Color and yaka must use separate token namespaces,
// because the same visible token (for example "001") can exist in both dimensions. // because the same visible token (for example "001") can exist in both dimensions.
d1 := int64(0) d1 := int64(0)
if id, ok := resolveDimID("dimval1", colorCode); ok { if id, ok := resolveProductDimID("dimval1", colorCode, inferredDim1); ok {
d1 = id d1 = id
} }
if d1 <= 0 { if d1 <= 0 {
continue continue
} }
d3k := int64(0) d3k := int64(0)
if id, ok := resolveDimID("dimval3", dim3Code); ok { if id, ok := resolveProductDimID("dimval3", dim3Code, inferredDim3); ok {
d3k = id d3k = id
} }
key := fmt.Sprintf("%d|%d|%d", itemID, d1, d3k) key := fmt.Sprintf("%d|%d|%d", itemID, d1, d3k)
@@ -974,7 +1114,7 @@ LIMIT 1
v2 = sizeID v2 = sizeID
} }
v3 := int64(0) v3 := int64(0)
if id, ok := resolveDimID("dimval3", dim3Code); ok { if id, ok := resolveProductDimID("dimval3", dim3Code, inferredDim3); ok {
v3 = id v3 = id
} }
mmdimID := int64(2) mmdimID := int64(2)