feat: 复用颜色映射生成完整采购规格 (#295)

This commit is contained in:
chengma
2026-08-24 00:12:36 +08:00
parent 3f17bedf6a
commit 486a374869
10 changed files with 545 additions and 6 deletions
+31 -3
View File
@@ -77,7 +77,14 @@ func UpsertSpecMapping(q Execer, m model.SpecMapping) error {
// UpsertAutomaticSpecMapping 只在没有人工映射且上下文版本变化时写入自动结果。
// 同一上下文的并发 AI 请求由先写入者获胜;人工保存无论先后都不会被自动结果覆盖。
func UpsertAutomaticSpecMapping(q Execer, m model.SpecMapping) error {
_, err := q.Exec(`
_, err := UpsertAutomaticSpecMappingChanged(q, m)
return err
}
// UpsertAutomaticSpecMappingChanged 与 UpsertAutomaticSpecMapping 使用同一条并发安全 SQL,
// 并返回本次是否真正插入或更新。调用方据此避免为幂等重放重复追加决策审计。
func UpsertAutomaticSpecMappingChanged(q Execer, m model.SpecMapping) (bool, error) {
result, err := q.Exec(`
INSERT INTO spec_mappings
(shopee_goods_id,spec_key,pdd_goods_id,pdd_option_key,pdd_options,spec_raw,
mapped_at,mapped_by,source,source_provider_id,source_model,confidence_bps,
@@ -101,9 +108,30 @@ func UpsertAutomaticSpecMapping(q Execer, m model.SpecMapping) error {
nullableText(m.SourceModel), nullableInt(m.ConfidenceBPS, m.ConfidenceSet), nullableText(m.SourceReason),
nullableText(m.SourceVersion), nullableText(m.ContextVersion))
if err != nil {
return fmt.Errorf("保存自动规格映射失败: %w", err)
return false, fmt.Errorf("保存自动规格映射失败: %w", err)
}
return nil
rows, err := result.RowsAffected()
if err != nil {
return false, fmt.Errorf("读取自动规格映射保存结果失败: %w", err)
}
return rows > 0, nil
}
// DeleteAutomaticSpecMappingByVersion 只删除指定规则自己生成的映射。
// 人工和 AI 结果以及其他规则版本永远不受影响。
func DeleteAutomaticSpecMappingByVersion(q Execer, shopeeGoodsID, specKey, pddGoodsID, sourceVersion string) (bool, error) {
result, err := q.Exec(`DELETE FROM spec_mappings
WHERE shopee_goods_id=? AND spec_key=? AND pdd_goods_id=?
AND source='rule' AND source_version=?`,
shopeeGoodsID, specKey, pddGoodsID, sourceVersion)
if err != nil {
return false, fmt.Errorf("清除失效的颜色辅助规格映射失败: %w", err)
}
rows, err := result.RowsAffected()
if err != nil {
return false, fmt.Errorf("读取颜色辅助规格映射清除结果失败: %w", err)
}
return rows > 0, nil
}
func InsertAISpecMatchDecision(q Execer, d model.AISpecMatchDecision) error {
+19
View File
@@ -332,6 +332,25 @@ func ListShopeePddLinksByGoodsIDs(q Execer, goodsIDs []string) (map[string]strin
return links, nil
}
// ListShopeeGoodsIDsByPddGoodsID 返回当前仍关联指定 PDD 商品的蝦皮商品。
func ListShopeeGoodsIDsByPddGoodsID(q Execer, pddGoodsID string) ([]string, error) {
rows, err := q.Query(`SELECT goods_id FROM shopee_products
WHERE pdd_goods_id=? AND deleted_at IS NULL ORDER BY goods_id`, pddGoodsID)
if err != nil {
return nil, fmt.Errorf("查询 PDD 商品 %s 的蝦皮关联失败: %w", pddGoodsID, err)
}
defer rows.Close()
var result []string
for rows.Next() {
var goodsID string
if err := rows.Scan(&goodsID); err != nil {
return nil, fmt.Errorf("读取 PDD 商品的蝦皮关联失败: %w", err)
}
result = append(result, goodsID)
}
return result, rows.Err()
}
// UpdateShopeePddLink 更新蝦皮商品当前关联的 PDD 商品。
// 调用方必须先在同一事务里保证 PDD 商品存在,避免留下悬空关联。
func UpdateShopeePddLink(q Execer, shopeeGoodsID, pddGoodsID, pddURL string) error {
+20
View File
@@ -726,6 +726,26 @@ func GetSybOrderContext(q Execer, sybID string) (*SybOrderContext, error) {
return &row, nil
}
// ListSybIDsByShopeeGoodsID 限定读取一个蝦皮商品已有的有效规格明细,供写入事件幂等派生。
func ListSybIDsByShopeeGoodsID(q Execer, goodsID string) ([]string, error) {
rows, err := q.Query(`SELECT syb_id FROM syb_orders
WHERE shopee_goods_id=? AND spec_key IS NOT NULL AND spec_key<>''
ORDER BY syb_id`, goodsID)
if err != nil {
return nil, fmt.Errorf("查询蝦皮商品 %s 的顺运宝明细失败: %w", goodsID, err)
}
defer rows.Close()
var result []string
for rows.Next() {
var sybID string
if err := rows.Scan(&sybID); err != nil {
return nil, fmt.Errorf("读取颜色辅助顺运宝明细失败: %w", err)
}
result = append(result, sybID)
}
return result, rows.Err()
}
// ListSybOrders 按筛选条件分页查货运单明细列表,按更新时间倒序。
func ListSybOrders(q Execer, filter SybOrderFilter, limit, offset int) ([]model.SybOrder, error) {
where, args := sybOrderFilterClause(filter)