feat: 支持批量导入 PDD 商品链接 (#104)

This commit is contained in:
chengma
2026-08-10 16:14:24 +08:00
parent 7bd75510b2
commit 188725ff64
15 changed files with 911 additions and 32 deletions
+27 -9
View File
@@ -47,6 +47,16 @@ func scanPddProduct(s rowScanner, extra ...any) (*model.PddProduct, error) {
return &p, nil
}
// EnsurePddProductOutcome 说明 EnsurePddProductWithOutcome 实际做了什么。
// 批量导入用它给采购员显示准确统计;普通单条创建只关心最终商品。
type EnsurePddProductOutcome string
const (
PddProductCreated EnsurePddProductOutcome = "created"
PddProductExisting EnsurePddProductOutcome = "existing"
PddProductRevived EnsurePddProductOutcome = "revived"
)
// EnsurePddProduct 保证 goods_id 对应的 PDD 商品存在,返回它。
//
// 操作员在货运单或蝦皮商品上填 PDD 链接、点保存时调它。三种情况:
@@ -58,16 +68,23 @@ func scanPddProduct(s rowScanner, extra ...any) (*model.PddProduct, error) {
// 复活是必要的:goods_id 上有 UNIQUE 约束,软删除的行还占着那个值,
// 不复活就会插入冲突,操作员会看到一个莫名其妙的错误。
func EnsurePddProduct(q Execer, goodsID, url string) (*model.PddProduct, error) {
p, _, err := EnsurePddProductWithOutcome(q, goodsID, url)
return p, err
}
// EnsurePddProductWithOutcome 与 EnsurePddProduct 使用完全相同的建档规则,
// 额外返回新建、复用或复活分类,供批量导入统计使用。
func EnsurePddProductWithOutcome(q Execer, goodsID, url string) (*model.PddProduct, EnsurePddProductOutcome, error) {
if goodsID == "" {
return nil, fmt.Errorf("goods_id 不能为空")
return nil, "", fmt.Errorf("goods_id 不能为空")
}
if url == "" {
return nil, fmt.Errorf("url 不能为空")
return nil, "", fmt.Errorf("url 不能为空")
}
existing, err := GetPddProductByGoodsID(q, goodsID)
if err != nil {
return nil, err
return nil, "", err
}
now := model.NowISO()
@@ -78,14 +95,14 @@ func EnsurePddProduct(q Execer, goodsID, url string) (*model.PddProduct, error)
VALUES (?, ?, 'pending', ?, ?)`,
goodsID, url, now, now)
if err != nil {
return nil, fmt.Errorf("新建 PDD 商品 %s 失败: %w", goodsID, err)
return nil, "", fmt.Errorf("新建 PDD 商品 %s 失败: %w", goodsID, err)
}
id, _ := res.LastInsertId()
return &model.PddProduct{
ID: id, GoodsID: goodsID, URL: url,
CollectStatus: model.CollectPending,
CreatedAt: now, UpdatedAt: now,
}, nil
}, PddProductCreated, nil
}
if existing.IsDeleted() {
@@ -103,9 +120,10 @@ func EnsurePddProduct(q Execer, goodsID, url string) (*model.PddProduct, error)
WHERE goods_id = ?`,
url, now, goodsID)
if err != nil {
return nil, fmt.Errorf("复活 PDD 商品 %s 失败: %w", goodsID, err)
return nil, "", fmt.Errorf("复活 PDD 商品 %s 失败: %w", goodsID, err)
}
return GetPddProductByGoodsID(q, goodsID)
p, err := GetPddProductByGoodsID(q, goodsID)
return p, PddProductRevived, err
}
// 已存在且有效:链接可能写法不同(带不带参数),更新一下原文,
@@ -114,11 +132,11 @@ func EnsurePddProduct(q Execer, goodsID, url string) (*model.PddProduct, error)
if _, err := q.Exec(
`UPDATE pdd_products SET url = ?, updated_at = ? WHERE goods_id = ?`,
url, now, goodsID); err != nil {
return nil, fmt.Errorf("更新 PDD 商品 %s 链接失败: %w", goodsID, err)
return nil, "", fmt.Errorf("更新 PDD 商品 %s 链接失败: %w", goodsID, err)
}
existing.URL = url
}
return existing, nil
return existing, PddProductExisting, nil
}
// GetPddProductByGoodsID 按 goods_id 查,**包括已软删除的**。