feat: 回填店铺关联PDD空规格 (#194)
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
// backfill-shop-pdd-specs 把指定蝦皮店铺的正式规格补成关联 PDD 的空规格骨架。
|
||||
// 默认只预览;只有显式传入 --apply 才写数据库。
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cmautobuy/admin/config"
|
||||
"cmautobuy/admin/repository"
|
||||
"cmautobuy/admin/service"
|
||||
)
|
||||
|
||||
type backupFile struct {
|
||||
Shop string `json:"shop"`
|
||||
GeneratedAt string `json:"generated_at"`
|
||||
Items []backupItem `json:"items"`
|
||||
}
|
||||
|
||||
type backupItem struct {
|
||||
PDDGoodsID string `json:"pdd_goods_id"`
|
||||
SKUsJSON string `json:"skus_json"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
shop := flag.String("shop", "", "要处理的蝦皮店铺名(精确匹配,必填)")
|
||||
apply := flag.Bool("apply", false, "实际写入;不传时只做 dry-run")
|
||||
flag.Parse()
|
||||
if strings.TrimSpace(*shop) == "" {
|
||||
log.Fatal("必须通过 --shop 指定店铺名")
|
||||
}
|
||||
|
||||
cfg, err := config.LoadDatabase()
|
||||
if err != nil {
|
||||
log.Fatalf("读取 MySQL 配置失败: %v", err)
|
||||
}
|
||||
db, err := repository.OpenMySQL(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("连接 MySQL 失败: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
sources, err := repository.ListShopSpecSources(db, *shop)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
now := time.Now()
|
||||
plan := service.BuildSpecBackfillPlan(*shop, sources, now)
|
||||
if !*apply {
|
||||
printReport(plan, 0, "dry-run")
|
||||
return
|
||||
}
|
||||
backupPath, err := writeBackup(plan)
|
||||
if err != nil {
|
||||
log.Fatalf("创建本机回退备份失败,未写数据库: %v", err)
|
||||
}
|
||||
updated, err := service.ApplySpecBackfill(db, plan, now)
|
||||
if err != nil {
|
||||
log.Fatalf("规格回填失败: %v;本机备份位于 %s", err, backupPath)
|
||||
}
|
||||
printReport(plan, updated, "applied")
|
||||
fmt.Printf("本机回退备份:%s\n", backupPath)
|
||||
}
|
||||
|
||||
func printReport(plan service.SpecBackfillPlan, updated int, mode string) {
|
||||
summary, _ := json.Marshal(plan.Summary)
|
||||
fmt.Printf("模式:%s\n店铺:%s\n蝦皮商品:%d\n候选 PDD:%d\n已回填 PDD:%d\n本次更新 PDD:%d\n分类:%s\n",
|
||||
mode, plan.Shop, plan.SourceProductCount, plan.CandidatePDDCount,
|
||||
plan.BackfilledPDDCount, updated, summary)
|
||||
}
|
||||
|
||||
func writeBackup(plan service.SpecBackfillPlan) (string, error) {
|
||||
file, err := os.CreateTemp("", "cmautobuy_spec_backfill_backup_*.json")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
path := file.Name()
|
||||
defer file.Close()
|
||||
if err := file.Chmod(0o600); err != nil {
|
||||
return "", err
|
||||
}
|
||||
backup := backupFile{Shop: plan.Shop, GeneratedAt: time.Now().UTC().Format(time.RFC3339)}
|
||||
for _, candidate := range plan.Candidates {
|
||||
backup.Items = append(backup.Items, backupItem{PDDGoodsID: candidate.PDDGoodsID, SKUsJSON: candidate.OriginalSKUsJSON})
|
||||
}
|
||||
encoder := json.NewEncoder(file)
|
||||
encoder.SetIndent("", " ")
|
||||
if err := encoder.Encode(backup); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
Reference in New Issue
Block a user