fix: 修复顺运宝采集任务孤儿状态 (#165)

This commit is contained in:
chengma
2026-08-11 17:00:33 +08:00
parent c8b1fd686a
commit 9e328984e9
17 changed files with 508 additions and 67 deletions
+86 -2
View File
@@ -379,8 +379,14 @@ func taskFilterClause(filter TaskFilter) (string, []any) {
if kw := strings.TrimSpace(filter.Keyword); kw != "" {
pattern := "%" + escapeLike(kw) + "%"
clauses = append(clauses,
"(t.task_id LIKE ? ESCAPE '!' OR t.order_no LIKE ? ESCAPE '!' OR t.pdd_goods_id LIKE ? ESCAPE '!')")
args = append(args, pattern, pattern, pattern)
`(t.task_id LIKE ? ESCAPE '!' OR t.order_no LIKE ? ESCAPE '!' OR t.pdd_goods_id LIKE ? ESCAPE '!'
OR EXISTS (
SELECT 1 FROM task_syb_sources tss
JOIN syb_orders so ON so.syb_id=tss.syb_id
WHERE tss.task_id=t.task_id
AND (tss.syb_id LIKE ? ESCAPE '!' OR so.order_no LIKE ? ESCAPE '!')
))`)
args = append(args, pattern, pattern, pattern, pattern, pattern)
}
if filter.VisibleUserID != "" {
clauses = append(clauses, "t.created_by_user_id = ?")
@@ -529,6 +535,59 @@ func DeleteTasksInScope(q Execer, taskIDs []string, visibleUserID string) (int64
return res.RowsAffected()
}
// ListCollectTaskGoodsIDsInScope 在删除前找出受影响的 PDD 商品。
// 调用方必须和删除使用同一事务、同一可见范围,避免越权数据影响状态回收。
func ListCollectTaskGoodsIDsInScope(q Execer, taskIDs []string, visibleUserID string) ([]string, error) {
if len(taskIDs) == 0 {
return nil, nil
}
placeholders := strings.TrimSuffix(strings.Repeat("?,", len(taskIDs)), ",")
args := make([]any, 0, len(taskIDs)+1)
for _, id := range taskIDs {
args = append(args, id)
}
where := `task_id IN (` + placeholders + `) AND task_type='collect' AND pdd_goods_id IS NOT NULL`
if visibleUserID != "" {
where += ` AND created_by_user_id = ?`
args = append(args, visibleUserID)
}
rows, err := q.Query(`SELECT DISTINCT pdd_goods_id FROM tasks WHERE `+where, args...)
if err != nil {
return nil, fmt.Errorf("查询待删除采集任务的 PDD 商品失败: %w", err)
}
defer rows.Close()
var goodsIDs []string
for rows.Next() {
var goodsID string
if err := rows.Scan(&goodsID); err != nil {
return nil, fmt.Errorf("读取待删除采集任务的 PDD 商品失败: %w", err)
}
goodsIDs = append(goodsIDs, goodsID)
}
return goodsIDs, rows.Err()
}
// ResetCollectingIfNoActiveTask 把没有有效采集任务的孤儿状态回收到待采集。
// 条件判断和更新在一条 SQL 内完成,避免并发建任务时误覆盖 collecting。
func ResetCollectingIfNoActiveTask(q Execer, goodsID string) (bool, error) {
result, err := q.Exec(`UPDATE pdd_products AS pp
SET collect_status='pending', collect_msg=NULL, updated_at=?
WHERE pp.goods_id=? AND pp.collect_status='collecting'
AND NOT EXISTS (
SELECT 1 FROM tasks t
WHERE t.task_type='collect' AND t.pdd_goods_id=pp.goods_id
AND t.status IN ('pending','assigned','claimed')
)`, model.NowISO(), goodsID)
if err != nil {
return false, fmt.Errorf("回收商品 %s 的孤立采集中状态失败: %w", goodsID, err)
}
n, err := result.RowsAffected()
if err != nil {
return false, fmt.Errorf("确认商品 %s 的采集状态回收结果失败: %w", goodsID, err)
}
return n == 1, nil
}
// InsertCollectTask 建一条不指定客户端的采集任务。
// 保留这个入口给蝦皮、顺运宝等现有流程使用,避免它们被 PDD 页的新选项影响。
func InsertCollectTask(q Execer, taskID, goodsID, goodsURL string) error {
@@ -567,6 +626,31 @@ func InsertCollectTaskForClientAndUser(q Execer, taskID, goodsID, goodsURL, assi
return nil
}
// InsertCollectTaskSybSources 保存一条采集任务对应的全部顺运宝明细来源。
// 同一个 PDD 商品可能由多条明细共同发起,来源不能压成 tasks 上的单列。
func InsertCollectTaskSybSources(q Execer, taskID string, sybIDs []string) error {
taskID = strings.TrimSpace(taskID)
if taskID == "" {
return fmt.Errorf("采集任务编号不能为空")
}
seen := make(map[string]struct{}, len(sybIDs))
for _, raw := range sybIDs {
sybID := strings.TrimSpace(raw)
if sybID == "" {
return fmt.Errorf("顺运宝明细编号不能为空")
}
if _, ok := seen[sybID]; ok {
continue
}
seen[sybID] = struct{}{}
if _, err := q.Exec(`INSERT INTO task_syb_sources(task_id,syb_id,created_at)
VALUES(?,?,?) ON DUPLICATE KEY UPDATE created_at=created_at`, taskID, sybID, model.NowISO()); err != nil {
return fmt.Errorf("保存采集任务 %s 的顺运宝来源 %s 失败: %w", taskID, sybID, err)
}
}
return nil
}
// HasActivePurchaseTask 判断顺运宝明细是否已有尚未结束的采购任务。
func HasActivePurchaseTask(q Execer, sybID string) (bool, error) {
var count int