Files
cmautobuy/admin/cmd/backfill-xlsx-pdd-prices/main.go
T

127 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// backfill-xlsx-pdd-prices 用三个固定蝦皮 Excel 的价格最大值回填关联 PDD 正式价格。
// 默认只预览;只有显式传入 --apply 才写数据库。
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"time"
"cmautobuy/admin/config"
"cmautobuy/admin/repository"
"cmautobuy/admin/service"
)
type backupFile struct {
Shop string `json:"shop"`
GeneratedAt string `json:"generated_at"`
Formula string `json:"formula"`
Files []string `json:"files"`
Items []backupItem `json:"items"`
}
type backupItem struct {
PDDGoodsID string `json:"pdd_goods_id"`
SourceMaxTWD string `json:"source_max_twd"`
PriceCent int64 `json:"price_cent"`
OriginalSKUsJSON string `json:"original_skus_json"`
OriginalCollectStatus string `json:"original_collect_status"`
OriginalCollectMsg *string `json:"original_collect_msg"`
OriginalArtifactRef *string `json:"original_artifact_ref"`
OriginalCollectedAt *string `json:"original_collected_at"`
OriginalUpdatedAt string `json:"original_updated_at"`
}
func main() {
dir := flag.String("dir", "../raw_data", "三个固定 Excel 所在目录")
apply := flag.Bool("apply", false, "实际写入;不传时只做 dry-run")
flag.Parse()
if flag.NArg() != 0 {
log.Fatal("不接受额外文件参数;只会读取 --dir 下三个固定文件名")
}
sources, err := service.LoadXLSXPriceSources(*dir)
if err != nil {
log.Fatalf("读取三个固定 Excel 失败: %v", err)
}
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()
targets, err := repository.ListShopPDDPriceBackfillTargets(db, service.XLSXPriceBackfillShop)
if err != nil {
log.Fatal(err)
}
plan := service.BuildXLSXPriceBackfillPlan(sources, targets, time.Now())
if !*apply {
printReport(plan, 0, "dry-run")
return
}
if len(plan.Candidates) == 0 {
printReport(plan, 0, "applied-noop")
return
}
backupPath, err := writeBackup(plan)
if err != nil {
log.Fatalf("创建本机回退备份失败,未写数据库: %v", err)
}
updated, err := service.ApplyXLSXPriceBackfill(db, plan, time.Now())
if err != nil {
log.Fatalf("PDD 正式价格回填失败: %v;本机备份位于 %s", err, backupPath)
}
printReport(plan, updated, "applied")
fmt.Printf("本机回退备份:%s\n", backupPath)
}
func printReport(plan service.XLSXPriceBackfillPlan, updated int, mode string) {
summary, _ := json.Marshal(plan.Summary)
skuCount := 0
for _, candidate := range plan.Candidates {
skuCount += candidate.SKUCount
}
fmt.Printf("模式:%s\n店铺:%s\nExcel 行:%d\n蝦皮商品:%d\nPDD 商品:%d\n共用 PDD 且最大价不同:%d\n候选 PDD:%d\n候选 SKU:%d\n本次更新 PDD:%d\n分类:%s\n",
mode, plan.Shop, plan.Sources.RowCount, plan.Sources.ShopeeProductCount,
plan.Sources.PDDProductCount, plan.Sources.SharedPDDWithDifferentMaxCount,
len(plan.Candidates), skuCount, updated, summary)
}
func writeBackup(plan service.XLSXPriceBackfillPlan) (string, error) {
file, err := os.CreateTemp("", "cmautobuy_xlsx_price_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),
Formula: "max_twd / 10 * 100 = cny_cent", Files: append([]string(nil), service.XLSXPriceBackfillFiles...),
}
for _, candidate := range plan.Candidates {
original := candidate.Original
backup.Items = append(backup.Items, backupItem{
PDDGoodsID: candidate.PDDGoodsID, SourceMaxTWD: candidate.SourceMaxTWD,
PriceCent: candidate.PriceCent, OriginalSKUsJSON: original.SKUsJSON,
OriginalCollectStatus: original.CollectStatus, OriginalCollectMsg: original.CollectMsg,
OriginalArtifactRef: original.ArtifactRef, OriginalCollectedAt: original.CollectedAt,
OriginalUpdatedAt: original.UpdatedAt,
})
}
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
if err := encoder.Encode(backup); err != nil {
return "", err
}
return path, nil
}