feat: 完善 SYB 蝦皮主数据与软删除 (#203 #204 #205)

This commit is contained in:
chengma
2026-08-13 10:39:21 +08:00
parent 3af9bf245a
commit ad1ccc2c60
23 changed files with 864 additions and 90 deletions
+20 -7
View File
@@ -191,6 +191,16 @@ func UpsertCatalogShopeeProduct(q Execer, in CatalogShopeeProductInput) (out Cat
out.FieldsManualSkipped++
return false
}
// 商品目录是权威来源,可以替换顺运宝为了预览而填入的低优先级值。
// 这不是任意跨来源覆盖:只有明确标记为 syb 的值享受升级规则。
if source.Valid && source.String == "syb" {
if *current != incoming {
*current = incoming
out.FieldsFilled++
return true
}
return false
}
if in.UpdatePolicy == "fill_missing" {
if *current == "" {
*current = incoming
@@ -324,22 +334,25 @@ func UpsertCatalogShopeeSKU(q Execer, in CatalogShopeeSKUInput) (CatalogSKUOutco
color, size, advice, skuCode := current.Color.String, current.Size.String, current.Advice.String, current.SKUCode.String
sources, times := catalogFieldProvenance(current)
changed := external != current.ShopeeSKUID.String
if color == "" && strings.TrimSpace(in.Color) != "" {
canFill := func(field, current, incoming string) bool {
return strings.TrimSpace(incoming) != "" && (current == "" || (sources[field] == "syb" && in.Source != "syb"))
}
if canFill("color", color, in.Color) {
color = in.Color
sources["color"], times["color"] = in.Source, in.ObservedAt
changed = true
}
if size == "" && strings.TrimSpace(in.Size) != "" {
if canFill("size", size, in.Size) {
size = in.Size
sources["size"], times["size"] = in.Source, in.ObservedAt
changed = true
}
if advice == "" && strings.TrimSpace(in.Advice) != "" {
if canFill("advice", advice, in.Advice) {
advice = in.Advice
sources["advice"], times["advice"] = in.Source, in.ObservedAt
changed = true
}
if skuCode == "" && strings.TrimSpace(in.SKUCode) != "" {
if canFill("sku_code", skuCode, in.SKUCode) {
skuCode = in.SKUCode
sources["sku_code"], times["sku_code"] = in.Source, in.ObservedAt
changed = true
@@ -349,7 +362,7 @@ func UpsertCatalogShopeeSKU(q Execer, in CatalogShopeeSKUInput) (CatalogSKUOutco
}
sourcesJSON, _ := json.Marshal(sources)
timesJSON, _ := json.Marshal(times)
_, err = q.Exec(`UPDATE shopee_skus SET shopee_sku_id=NULLIF(?,''),color=NULLIF(?,''),size=NULLIF(?,''),advice=NULLIF(?,''),sku_code=NULLIF(?,''),parse_ok=CASE WHEN parse_ok=1 THEN 1 ELSE ? END,field_sources=?,field_observed_at=?,updated_at=? WHERE sku_id=?`, external, color, size, advice, skuCode, parse, string(sourcesJSON), string(timesJSON), in.Now, current.RecordID)
_, err = q.Exec(`UPDATE shopee_skus SET shopee_sku_id=NULLIF(?,''),color=NULLIF(?,''),size=NULLIF(?,''),advice=NULLIF(?,''),sku_code=NULLIF(?,''),parse_ok=CASE WHEN parse_ok=1 THEN 1 ELSE ? END,field_sources=?,field_observed_at=?,source_observed_at=CASE WHEN source='syb' AND ?<>'syb' THEN ? ELSE source_observed_at END,source=CASE WHEN source='syb' AND ?<>'syb' THEN ? ELSE source END,updated_at=? WHERE sku_id=?`, external, color, size, advice, skuCode, parse, string(sourcesJSON), string(timesJSON), in.Source, in.ObservedAt, in.Source, in.Source, in.Now, current.RecordID)
if err != nil {
return "", err
}
@@ -448,7 +461,7 @@ func UpsertCatalogPddProduct(q Execer, goodsID, url, title, shopName, skusJSON,
// ApplyCatalogAssociation 只允许空关联建立或相同关联重放。
func ApplyCatalogAssociation(q Execer, shopeeGoodsID, pddGoodsID, now string) (created, unchanged bool, err error) {
var current sql.NullString
if err = q.QueryRow(`SELECT pdd_goods_id FROM shopee_products WHERE goods_id=?`, shopeeGoodsID).Scan(&current); err != nil {
if err = q.QueryRow(`SELECT pdd_goods_id FROM shopee_products WHERE goods_id=? AND deleted_at IS NULL`, shopeeGoodsID).Scan(&current); err != nil {
return
}
var url string
@@ -461,7 +474,7 @@ func ApplyCatalogAssociation(q Execer, shopeeGoodsID, pddGoodsID, now string) (c
}
return false, false, fmt.Errorf("蝦皮商品 %s 已关联 PDD 商品 %s", shopeeGoodsID, current.String)
}
_, err = q.Exec(`UPDATE shopee_products SET pdd_goods_id=?,pdd_goods_url=?,updated_at=? WHERE goods_id=?`, pddGoodsID, url, now, shopeeGoodsID)
_, err = q.Exec(`UPDATE shopee_products SET pdd_goods_id=?,pdd_goods_url=?,updated_at=? WHERE goods_id=? AND deleted_at IS NULL`, pddGoodsID, url, now, shopeeGoodsID)
return err == nil, false, err
}