87 lines
3.1 KiB
Go
87 lines
3.1 KiB
Go
package repository
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// PDDPriceBackfillTarget 是一次性 Excel 价格回填需要的 PDD 原值。
|
|
// 原值同时用于 dry-run、乐观锁和本机回退备份。
|
|
type PDDPriceBackfillTarget struct {
|
|
GoodsID string
|
|
SKUsJSON string
|
|
CollectStatus string
|
|
CollectMsg *string
|
|
ArtifactRef *string
|
|
CollectedAt *string
|
|
UpdatedAt string
|
|
}
|
|
|
|
// ListShopPDDPriceBackfillTargets 读取指定蝦皮店铺当前关联的活动 PDD 商品。
|
|
// 同一个 PDD 被多个蝦皮商品关联时只返回一份原值。
|
|
func ListShopPDDPriceBackfillTargets(q Execer, shopName string) ([]PDDPriceBackfillTarget, error) {
|
|
rows, err := q.Query(`
|
|
SELECT DISTINCT pp.goods_id, COALESCE(pp.skus_json, ''), pp.collect_status,
|
|
pp.collect_msg, pp.artifact_ref, pp.collected_at, pp.updated_at
|
|
FROM shopee_products sp
|
|
JOIN pdd_products pp ON pp.goods_id = sp.pdd_goods_id
|
|
WHERE sp.deleted_at IS NULL AND pp.deleted_at IS NULL
|
|
AND sp.shopee_shop_name = ?
|
|
ORDER BY pp.goods_id`, strings.TrimSpace(shopName))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("读取店铺 PDD 价格回填目标失败: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var targets []PDDPriceBackfillTarget
|
|
for rows.Next() {
|
|
var target PDDPriceBackfillTarget
|
|
var collectMsg, artifactRef, collectedAt sql.NullString
|
|
if err := rows.Scan(&target.GoodsID, &target.SKUsJSON, &target.CollectStatus,
|
|
&collectMsg, &artifactRef, &collectedAt, &target.UpdatedAt); err != nil {
|
|
return nil, fmt.Errorf("解析 PDD 价格回填目标失败: %w", err)
|
|
}
|
|
target.CollectMsg = nullableStringPointer(collectMsg)
|
|
target.ArtifactRef = nullableStringPointer(artifactRef)
|
|
target.CollectedAt = nullableStringPointer(collectedAt)
|
|
targets = append(targets, target)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("遍历 PDD 价格回填目标失败: %w", err)
|
|
}
|
|
return targets, nil
|
|
}
|
|
|
|
func nullableStringPointer(value sql.NullString) *string {
|
|
if !value.Valid {
|
|
return nil
|
|
}
|
|
result := value.String
|
|
return &result
|
|
}
|
|
|
|
// ReplacePDDPricesAndMarkCollected 使用完整原值作乐观锁,写入价格并标记已采集。
|
|
// 返回 false 表示 dry-run 后目标发生变化,调用方必须回滚整批,不能部分提交。
|
|
func ReplacePDDPricesAndMarkCollected(q Execer, target PDDPriceBackfillTarget,
|
|
newSKUsJSON, collectedAt, updatedAt string) (bool, error) {
|
|
result, err := q.Exec(`
|
|
UPDATE pdd_products
|
|
SET skus_json = ?, collect_status = 'collected',
|
|
collect_msg = NULL, artifact_ref = NULL,
|
|
collected_at = ?, updated_at = ?
|
|
WHERE goods_id = ? AND deleted_at IS NULL
|
|
AND COALESCE(skus_json, '') = ?
|
|
AND collect_status = ? AND updated_at = ?`,
|
|
newSKUsJSON, collectedAt, updatedAt, target.GoodsID,
|
|
target.SKUsJSON, target.CollectStatus, target.UpdatedAt)
|
|
if err != nil {
|
|
return false, fmt.Errorf("更新 PDD 商品 %s 的正式价格失败: %w", target.GoodsID, err)
|
|
}
|
|
rows, err := result.RowsAffected()
|
|
if err != nil {
|
|
return false, fmt.Errorf("读取 PDD 商品 %s 的价格回填结果失败: %w", target.GoodsID, err)
|
|
}
|
|
return rows == 1, nil
|
|
}
|