Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -392,6 +392,45 @@ WHERE is_active = TRUE
|
||||
Price float64 `json:"price"`
|
||||
}
|
||||
|
||||
// sdprc has a unique constraint on the business key (tier/currency/dims).
|
||||
// If input rows contain duplicates for the same key (can happen due to tier/group mapping),
|
||||
// we must dedupe before bulk inserting to avoid 500s like "duplicate key violates uq_sdprc_2".
|
||||
dedupeSdprcWriteRows := func(productCode string, in []sdprcWriteRow) []sdprcWriteRow {
|
||||
if len(in) <= 1 {
|
||||
return in
|
||||
}
|
||||
type key struct {
|
||||
Cur string
|
||||
Grp int
|
||||
D1 int64
|
||||
D3 int64 // 0 => NULL
|
||||
}
|
||||
idx := make(map[key]int, len(in))
|
||||
out := make([]sdprcWriteRow, 0, len(in))
|
||||
for _, r := range in {
|
||||
cur := strings.ToUpper(strings.TrimSpace(r.Currency))
|
||||
d3k := int64(0)
|
||||
if r.Dim3 != nil && *r.Dim3 > 0 {
|
||||
d3k = *r.Dim3
|
||||
}
|
||||
k := key{Cur: cur, Grp: r.SdprcGrpID, D1: r.Dim1, D3: d3k}
|
||||
if i, ok := idx[k]; ok {
|
||||
out[i] = r // keep last
|
||||
continue
|
||||
}
|
||||
idx[k] = len(out)
|
||||
out = append(out, r)
|
||||
}
|
||||
if len(out) != len(in) {
|
||||
logger.Warn("save:pg:sdprc:dedupe",
|
||||
"product_code", strings.TrimSpace(productCode),
|
||||
"in_rows", len(in),
|
||||
"out_rows", len(out),
|
||||
)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
loadDimCombosFromCache := func(productCode string) ([]dimCombo, error) {
|
||||
productCode = strings.TrimSpace(productCode)
|
||||
if productCode == "" {
|
||||
@@ -552,11 +591,17 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
|
||||
if err := rows.Scan(&colorCode, &dim1Code, &dim3Code); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Resolve to PG dim ids (e-commerce expects integer ids, e.g. dim1=82).
|
||||
// Resolve to PG dim ids (e-commerce expects integer ids, e.g. dim1=82, dim3=2182).
|
||||
// Nebim varies by installation; we try a few fallbacks. In most setups:
|
||||
// - dim1 is size (ItemDim1Code)
|
||||
// - dim3 is color (ColorCode)
|
||||
d1 := int64(0)
|
||||
if id, ok := resolveDimvalFromToken(pgTx, "dimval1", dim1Code); ok {
|
||||
d1 = id
|
||||
resolvedDim1++
|
||||
} else if id, ok := resolveDimvalFromToken(pgTx, "dimval1", dim3Code); ok {
|
||||
d1 = id
|
||||
resolvedDim1++
|
||||
} else if id, ok := resolveDimvalFromToken(pgTx, "dimval1", colorCode); ok {
|
||||
d1 = id
|
||||
resolvedDim1++
|
||||
@@ -565,7 +610,12 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
|
||||
continue
|
||||
}
|
||||
var d3 sql.NullInt64
|
||||
if id, ok := resolveDimvalFromToken(pgTx, "dimval3", dim3Code); ok {
|
||||
// IMPORTANT: In this Nebim setup, both ItemDim1Code and ItemDim3Code are mapped in PG as dimval1 ids.
|
||||
// We therefore resolve dim3 via dimval1 as well (not dimval3).
|
||||
if id, ok := resolveDimvalFromToken(pgTx, "dimval1", dim3Code); ok {
|
||||
d3 = sql.NullInt64{Int64: id, Valid: true}
|
||||
resolvedDim3++
|
||||
} else if id, ok := resolveDimvalFromToken(pgTx, "dimval1", colorCode); ok {
|
||||
d3 = sql.NullInt64{Int64: id, Valid: true}
|
||||
resolvedDim3++
|
||||
}
|
||||
@@ -1073,6 +1123,7 @@ VALUES (
|
||||
}
|
||||
}
|
||||
if len(writeRows) > 0 {
|
||||
writeRows = dedupeSdprcWriteRows(code, writeRows)
|
||||
startPG := time.Now()
|
||||
inserted, err := bulkAppendOnlyInsertSdprc(mmItemID, code, writeRows)
|
||||
if err != nil {
|
||||
|
||||
@@ -24,6 +24,8 @@ type wholesaleCampaignMailRow struct {
|
||||
BrandGroupSec string
|
||||
Dim1 int64
|
||||
Dim3 int64
|
||||
Dim1Token string
|
||||
Dim3Token string
|
||||
CampaignCode string
|
||||
CampaignTitle string
|
||||
DiscountRate float64
|
||||
@@ -73,10 +75,10 @@ func buildWholesaleCampaignChangeMailHTML(firstGroupCode string, rows []wholesal
|
||||
r.BrandGroupSec,
|
||||
r.Marka,
|
||||
r.ProductCode,
|
||||
fmt.Sprintf("%d", r.Dim1),
|
||||
strings.TrimSpace(r.Dim1Token),
|
||||
func() string {
|
||||
if r.Dim3 > 0 {
|
||||
return fmt.Sprintf("%d", r.Dim3)
|
||||
if strings.TrimSpace(r.Dim3Token) != "" {
|
||||
return strings.TrimSpace(r.Dim3Token)
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
@@ -197,7 +199,52 @@ ORDER BY mm.code, l.dim1, COALESCE(l.dim3, 0), sc.discount_rate DESC;
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Resolve dim ids -> human tokens so mails show Nebim-style variant codes (not numeric ids).
|
||||
resolveDimTokens := func(ctx context.Context, dimIDs []int64) map[int64]string {
|
||||
out := make(map[int64]string, len(dimIDs))
|
||||
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 {
|
||||
return out
|
||||
}
|
||||
tRows, 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 {
|
||||
return out
|
||||
}
|
||||
defer tRows.Close()
|
||||
for tRows.Next() {
|
||||
var id int64
|
||||
var tok string
|
||||
if err := tRows.Scan(&id, &tok); err == nil {
|
||||
tok = strings.TrimSpace(tok)
|
||||
if tok != "" {
|
||||
out[id] = tok
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
mailRows := make([]wholesaleCampaignMailRow, 0, 1024)
|
||||
dimIDs := make([]int64, 0, 2048)
|
||||
for rows.Next() {
|
||||
var r dbRow
|
||||
if err := rows.Scan(&r.ProductCode, &r.Dim1, &r.Dim3, &r.CampaignCode, &r.CampaignTitle, &r.DiscountRate); err != nil {
|
||||
@@ -214,6 +261,12 @@ ORDER BY mm.code, l.dim1, COALESCE(l.dim3, 0), sc.discount_rate DESC;
|
||||
if r.Dim3.Valid {
|
||||
d3 = r.Dim3.Int64
|
||||
}
|
||||
if r.Dim1 > 0 {
|
||||
dimIDs = append(dimIDs, r.Dim1)
|
||||
}
|
||||
if d3 > 0 {
|
||||
dimIDs = append(dimIDs, d3)
|
||||
}
|
||||
mailRows = append(mailRows, wholesaleCampaignMailRow{
|
||||
ProductCode: code,
|
||||
UrunIlkGrubu: group,
|
||||
@@ -236,6 +289,20 @@ ORDER BY mm.code, l.dim1, COALESCE(l.dim3, 0), sc.discount_rate DESC;
|
||||
return
|
||||
}
|
||||
|
||||
tokens := resolveDimTokens(ctx, dimIDs)
|
||||
for i := range mailRows {
|
||||
mailRows[i].Dim1Token = tokens[mailRows[i].Dim1]
|
||||
if mailRows[i].Dim1Token == "" && mailRows[i].Dim1 > 0 {
|
||||
mailRows[i].Dim1Token = fmt.Sprintf("%d", mailRows[i].Dim1)
|
||||
}
|
||||
if mailRows[i].Dim3 > 0 {
|
||||
mailRows[i].Dim3Token = tokens[mailRows[i].Dim3]
|
||||
if mailRows[i].Dim3Token == "" {
|
||||
mailRows[i].Dim3Token = fmt.Sprintf("%d", mailRows[i].Dim3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byGroup := map[string][]wholesaleCampaignMailRow{}
|
||||
for _, r := range mailRows {
|
||||
g := strings.TrimSpace(r.UrunIlkGrubu)
|
||||
|
||||
@@ -777,17 +777,22 @@ DO UPDATE SET dim_id = EXCLUDED.dim_id, updated_at = EXCLUDED.updated_at
|
||||
}
|
||||
|
||||
d1 := int64(0)
|
||||
// Resolve dim1: prefer ColorCode first (matches e-comm expectation: dim1=Color).
|
||||
if id, ok := resolveDimID("dimval1", colorCode); ok {
|
||||
// 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", dim1Code); ok {
|
||||
} else if id, ok := resolveDimID("dimval1", dim3Code); ok {
|
||||
d1 = id
|
||||
} else if id, ok := resolveDimID("dimval1", colorCode); ok {
|
||||
d1 = id
|
||||
}
|
||||
if d1 <= 0 {
|
||||
continue
|
||||
}
|
||||
d3k := int64(0)
|
||||
if id, ok := resolveDimID("dimval3", t3); ok {
|
||||
if id, ok := resolveDimID("dimval1", dim3Code); ok {
|
||||
d3k = id
|
||||
} else if id, ok := resolveDimID("dimval1", colorCode); ok {
|
||||
d3k = id
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user