Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user