Files
cmautobuy/admin/repository/price_backfill.go
T

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
}