Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-06-18 15:59:24 +03:00
parent 21b1242a5a
commit d1f1e5a4f4
3 changed files with 375 additions and 89 deletions

View File

@@ -642,6 +642,7 @@ func GetWholesaleCampaignVariantRowsHandler(pg *sql.DB, mssql *sql.DB) http.Hand
// Resolve mmitem ids in bulk.
codeToItem := make(map[string]int64, len(codes))
itemToCode := make(map[int64]string, len(codes))
{
rows, err := pg.QueryContext(ctx, `
SELECT code, id
@@ -663,6 +664,7 @@ WHERE code = ANY($1::text[])
c = strings.TrimSpace(c)
if c != "" && id > 0 {
codeToItem[c] = id
itemToCode[id] = c
}
}
rows.Close()
@@ -727,15 +729,6 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
return id, true
}
// MSSQL: variant+stock list for selected products.
joined := strings.Join(codes, ",")
msRows, err := mssql.QueryContext(ctx, queries.GetWholesaleCampaignVariantStockByProducts, joined)
if err != nil {
http.Error(w, "variant stock query error: "+err.Error(), http.StatusInternalServerError)
return
}
defer msRows.Close()
type tmpRow struct {
ProductCode string
VariantCode string
@@ -744,8 +737,138 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
Dim1 int64
Dim3Key int64
}
// Deduplicate by (mmitem_id, dim1, dim3_key) and aggregate stock qty.
// Build base variant keys from PG's authoritative table (mmitem_dim).
itemIDs := make([]int64, 0, len(codeToItem))
for _, id := range codeToItem {
itemIDs = append(itemIDs, id)
}
tmpMap := make(map[string]tmpRow, 4096)
hasMMItemDim := make(map[int64]bool, len(itemIDs))
dimIDs := make([]int64, 0, 8192)
if len(itemIDs) > 0 {
rows, err := pg.QueryContext(ctx, `
SELECT mmitem_id, mmdim_id, val1, val2, val3
FROM mmitem_dim
WHERE mmitem_id = ANY($1::bigint[])
AND COALESCE(is_active, TRUE) = TRUE
`, pq.Array(itemIDs))
if err != nil {
http.Error(w, "mmitem_dim lookup error: "+err.Error(), http.StatusInternalServerError)
return
}
for rows.Next() {
var itemID int64
var mmdimID sql.NullInt64
var v1 sql.NullInt64
var v2 sql.NullInt64
var v3 sql.NullInt64
if err := rows.Scan(&itemID, &mmdimID, &v1, &v2, &v3); err != nil {
rows.Close()
http.Error(w, "mmitem_dim scan error", http.StatusInternalServerError)
return
}
hasMMItemDim[itemID] = true
if !v1.Valid || v1.Int64 <= 0 {
continue
}
d1 := v1.Int64
d3k := int64(0)
// Variant key in this app is (val1, val2). val3 may exist but is not the second axis for matching.
_ = mmdimID
_ = v3
if v2.Valid && v2.Int64 > 0 {
d3k = v2.Int64
}
code := strings.TrimSpace(itemToCode[itemID])
if code == "" {
continue
}
key := fmt.Sprintf("%d|%d|%d", itemID, d1, d3k)
if _, ok := tmpMap[key]; ok {
continue
}
tmpMap[key] = tmpRow{
ProductCode: code,
VariantCode: "",
StockQty: 0,
ItemID: itemID,
Dim1: d1,
Dim3Key: d3k,
}
dimIDs = append(dimIDs, d1)
if d3k > 0 {
dimIDs = append(dimIDs, d3k)
}
}
rows.Close()
}
// Resolve dim ids -> tokens for a readable VariantCode.
idToToken := map[int64]string{}
if len(dimIDs) > 0 {
// uniq
uniq := make([]int64, 0, len(dimIDs))
seen := make(map[int64]struct{}, len(dimIDs))
for _, id := range dimIDs {
if id <= 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
uniq = append(uniq, id)
}
if len(uniq) > 0 {
rows, err := pg.QueryContext(ctx, `
SELECT DISTINCT ON (dim_id) dim_id, token
FROM mk_dim_token_map
WHERE dim_column = 'dimval1'
AND dim_id = ANY($1::bigint[])
ORDER BY dim_id, updated_at DESC;
`, pq.Array(uniq))
if err == nil {
for rows.Next() {
var id int64
var tok string
_ = rows.Scan(&id, &tok)
tok = strings.TrimSpace(tok)
if tok != "" {
idToToken[id] = tok
}
}
rows.Close()
}
}
}
for k, v := range tmpMap {
t1 := strings.TrimSpace(idToToken[v.Dim1])
if t1 == "" {
t1 = fmt.Sprintf("%d", v.Dim1)
}
if v.Dim3Key > 0 {
t3 := strings.TrimSpace(idToToken[v.Dim3Key])
if t3 == "" {
t3 = fmt.Sprintf("%d", v.Dim3Key)
}
v.VariantCode = t1 + "-" + t3
} else {
v.VariantCode = t1
}
tmpMap[k] = v
}
// MSSQL: stock list for selected products; map to (mmitem_id, dim1, dim3_key) via token->id mapping.
joined := strings.Join(codes, ",")
msRows, err := mssql.QueryContext(ctx, queries.GetWholesaleCampaignVariantStockByProducts, joined)
if err != nil {
http.Error(w, "variant stock query error: "+err.Error(), http.StatusInternalServerError)
return
}
defer msRows.Close()
for msRows.Next() {
var itemCode, colorCode, dim1Code, dim3Code string
var qty sql.NullFloat64
@@ -762,66 +885,84 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
continue
}
// Variant token: prefer ColorCode; ItemDim1Code may represent a different attribute.
t1 := strings.TrimSpace(colorCode)
if t1 == "" || t1 == "0" {
t1 = strings.TrimSpace(dim1Code)
}
t3 := strings.TrimSpace(dim3Code)
varCode := strings.TrimSpace(t1)
if varCode != "" && t3 != "" && t3 != "0" {
varCode = varCode + "-" + strings.TrimSpace(t3)
}
if varCode == "" {
continue
}
// Map Nebim tokens to PG integer ids (dimval1 namespace).
// This app uses key: dim1=<color>, dim3=<size> to match mmitem_dim (val1,val2).
d1 := int64(0)
// IMPORTANT: In this Nebim setup, both ItemDim1Code and ItemDim3Code are mapped in PG as dimval1 ids.
// We therefore resolve both axes via dimval1 and store the second axis in dim3 (still a bigint).
if id, ok := resolveDimID("dimval1", dim1Code); ok {
d1 = id
} else if id, ok := resolveDimID("dimval1", dim3Code); ok {
d1 = id
} else if id, ok := resolveDimID("dimval1", colorCode); ok {
if id, ok := resolveDimID("dimval1", colorCode); ok {
d1 = id
}
if d1 <= 0 {
continue
}
d3k := int64(0)
if id, ok := resolveDimID("dimval1", dim3Code); ok {
d3k = id
} else if id, ok := resolveDimID("dimval1", colorCode); ok {
if id, ok := resolveDimID("dimval1", dim1Code); ok {
d3k = id
}
key := fmt.Sprintf("%d|%d|%d", itemID, d1, d3k)
prev, ok := tmpMap[key]
if !ok {
// If PG does not have mmitem_dim rows for this item yet, seed it from MSSQL and include it.
if !hasMMItemDim[itemID] {
var v2 any = nil
if d3k > 0 {
v2 = d3k
}
v3 := int64(0)
if id, ok := resolveDimID("dimval1", dim3Code); ok {
v3 = id
}
mmdimID := int64(2)
var v3any any = nil
if v3 > 0 {
mmdimID = 3
v3any = v3
}
_, _ = pg.ExecContext(ctx, `
INSERT INTO mmitem_dim (mmitem_id, mmdim_id, val1, val2, val3, is_active, qty)
SELECT $1, $2, $3, $4, $5, TRUE, 0
WHERE NOT EXISTS (
SELECT 1
FROM mmitem_dim
WHERE mmitem_id = $1
AND mmdim_id = $2
AND val1 = $3
AND COALESCE(val2, 0) = COALESCE($4::bigint, 0)
AND COALESCE(val3, 0) = COALESCE($5::bigint, 0)
LIMIT 1
);
`, itemID, mmdimID, d1, v2, v3any)
hasMMItemDim[itemID] = true
code := strings.TrimSpace(itemToCode[itemID])
if code != "" {
tmpMap[key] = tmpRow{
ProductCode: code,
VariantCode: "",
StockQty: 0,
ItemID: itemID,
Dim1: d1,
Dim3Key: d3k,
}
// Keep dim token cache for VariantCode formatting.
dimIDs = append(dimIDs, d1)
if d3k > 0 {
dimIDs = append(dimIDs, d3k)
}
prev = tmpMap[key]
ok = true
}
}
if !ok {
continue
}
}
q := 0.0
if qty.Valid {
q = qty.Float64
}
key := fmt.Sprintf("%d|%d|%d", itemID, d1, d3k)
if prev, ok := tmpMap[key]; ok {
prev.StockQty += q
// Keep the first non-empty variant code.
if prev.VariantCode == "" {
prev.VariantCode = varCode
}
tmpMap[key] = prev
} else {
tmpMap[key] = tmpRow{
ProductCode: itemCode,
VariantCode: varCode,
StockQty: q,
ItemID: itemID,
Dim1: d1,
Dim3Key: d3k,
}
}
}
if err := msRows.Err(); err != nil {
http.Error(w, "variant stock read error: "+err.Error(), http.StatusInternalServerError)
return
prev.StockQty += q
tmpMap[key] = prev
_ = colorCode // display-only
}
tmp := make([]tmpRow, 0, len(tmpMap))