feat: 明确顺运宝复用 PDD 关联 (#183)
This commit is contained in:
@@ -247,6 +247,23 @@ func TestShopeeDetail_区分顺运宝观测与正式SKU(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSybPage_明确展示蝦皮商品Pdd关联来源(t *testing.T) {
|
||||
list, err := os.ReadFile("templates/syb/list.html")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
detail, err := os.ReadFile("templates/syb/detail_modal.html")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
content := string(list) + string(detail)
|
||||
for _, want := range []string{".PddAssociationText", "仅在需要更换采购商品时修改下面的关联"} {
|
||||
if !strings.Contains(content, want) {
|
||||
t.Errorf("顺运宝页面缺少关联复用提示 %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCatalogHistory_展示更新策略和分级统计(t *testing.T) {
|
||||
list, err := os.ReadFile("templates/catalog/list.html")
|
||||
if err != nil {
|
||||
|
||||
@@ -44,6 +44,44 @@ func TestAssociateSybPdd_兼容商品ID并复用已有采集结果(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertSybOrder_同步后自动复用蝦皮商品Pdd关联(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
if err := repository.UpsertShopeeProduct(db, "SP-REUSE", "目录商品", "正常", "MAIN-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := AssociateShopeePdd(db, "SP-REUSE", pddURLA, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
seedWorkflowOrder(t, db, "SYB-REUSE", "SP-REUSE", "黑色,M")
|
||||
detail, err := GetSybProcessingDetail(db, "SYB-REUSE")
|
||||
if err != nil || detail == nil {
|
||||
t.Fatalf("读取同步明细失败: detail=%+v err=%v", detail, err)
|
||||
}
|
||||
if detail.Stage != SybStagePddPending || detail.PddGoodsID != "737116531267" || detail.PddAssociationText == "" {
|
||||
t.Fatalf("新明细应直接复用已有 PDD 关联并进入待采集阶段: %+v", detail)
|
||||
}
|
||||
list, err := ListSybOrdersView(db, "", "", SybStagePddPending, 1)
|
||||
if err != nil || list.Total != 1 || list.Rows[0].PddAssociationText == "" {
|
||||
t.Fatalf("列表应显示关联来源: list=%+v err=%v", list, err)
|
||||
}
|
||||
|
||||
// 重复同步仍复用同一商品关系,不覆盖主数据上的 PDD 关联。
|
||||
seedWorkflowOrder(t, db, "SYB-REUSE", "SP-REUSE", "黑色,M")
|
||||
product, err := repository.GetShopeeProductByGoodsID(db, "SP-REUSE")
|
||||
if err != nil || product == nil || product.PddGoodsID != "737116531267" {
|
||||
t.Fatalf("重复同步覆盖了蝦皮商品的 PDD 关联: product=%+v err=%v", product, err)
|
||||
}
|
||||
|
||||
if err := repository.SoftDeletePddProduct(db, "737116531267"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
detail, err = GetSybProcessingDetail(db, "SYB-REUSE")
|
||||
if err != nil || detail.Stage != SybStagePddMissing || detail.PddAssociationText != "" {
|
||||
t.Fatalf("PDD 软删除后必须回到关联失效状态且不显示复用提示: detail=%+v err=%v", detail, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssociateSybPdd_新商品ID生成标准链接且完整链接保持兼容(t *testing.T) {
|
||||
t.Run("纯商品ID", func(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
|
||||
+37
-24
@@ -925,29 +925,30 @@ func EnsureSybSession(db *sql.DB, client *syb.Client, username string, now time.
|
||||
// SybOrderView 是列表页一行要显示的全部内容,已经格式化成字符串,
|
||||
// 模板里不做判断和格式化,和其余四个模块的做法一致。
|
||||
type SybOrderView struct {
|
||||
SybID string
|
||||
OrderNo string
|
||||
ShopName string
|
||||
Title string
|
||||
ProductSpec string
|
||||
ShopeeGoodsID string
|
||||
Quantity int
|
||||
PriceText string // "NT$239.00",和人民币价格一眼分得清
|
||||
ImageURL string
|
||||
Stage string
|
||||
StageText string
|
||||
StageHelp string
|
||||
ActionText string
|
||||
NeedsAttention bool
|
||||
CanCollect bool
|
||||
CanPurchase bool
|
||||
SelectionHint string
|
||||
DefaultUnitPrice string
|
||||
DefaultTotalPrice string
|
||||
MappedPddChoice string
|
||||
MappingOptionKey string
|
||||
ContextVersion string
|
||||
UpdatedAt string
|
||||
SybID string
|
||||
OrderNo string
|
||||
ShopName string
|
||||
Title string
|
||||
ProductSpec string
|
||||
ShopeeGoodsID string
|
||||
Quantity int
|
||||
PriceText string // "NT$239.00",和人民币价格一眼分得清
|
||||
ImageURL string
|
||||
Stage string
|
||||
StageText string
|
||||
StageHelp string
|
||||
PddAssociationText string
|
||||
ActionText string
|
||||
NeedsAttention bool
|
||||
CanCollect bool
|
||||
CanPurchase bool
|
||||
SelectionHint string
|
||||
DefaultUnitPrice string
|
||||
DefaultTotalPrice string
|
||||
MappedPddChoice string
|
||||
MappingOptionKey string
|
||||
ContextVersion string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -1154,6 +1155,7 @@ func sybOrderViewFor(context repository.SybOrderContext) SybOrderView {
|
||||
Quantity: o.Quantity, ImageURL: o.ImageURL,
|
||||
UpdatedAt: formatLocalTime(o.UpdatedAt)}
|
||||
v.Stage, v.StageText, v.StageHelp, v.ActionText = sybStageFor(context)
|
||||
v.PddAssociationText = sybPddAssociationText(context)
|
||||
v.CanCollect = v.Stage == SybStagePddPending || v.Stage == SybStagePddFailed ||
|
||||
v.Stage == SybStagePddCollectingStale
|
||||
v.CanPurchase = v.Stage == SybStagePurchaseReady
|
||||
@@ -1209,6 +1211,7 @@ type SybProcessingDetail struct {
|
||||
ShopeeExists bool
|
||||
PddGoodsID string
|
||||
PddURL string
|
||||
PddAssociationText string
|
||||
CollectStatus string
|
||||
CollectMsg string
|
||||
CanCollect bool
|
||||
@@ -1231,7 +1234,8 @@ func GetSybProcessingDetail(db *sql.DB, sybID string) (*SybProcessingDetail, err
|
||||
ShopeeGoodsID: o.ShopeeGoodsID,
|
||||
Quantity: o.Quantity, ShopeeExists: context.ShopeeExists,
|
||||
PddGoodsID: context.PddGoodsID, PddURL: context.PddGoodsURL,
|
||||
CollectStatus: context.PddCollectStatus, CollectMsg: context.PddCollectMsg,
|
||||
PddAssociationText: sybPddAssociationText(*context),
|
||||
CollectStatus: context.PddCollectStatus, CollectMsg: context.PddCollectMsg,
|
||||
}
|
||||
d.Stage, d.StageText, d.StageHelp, _ = sybStageFor(*context)
|
||||
d.CanCollect = context.PddGoodsID != "" &&
|
||||
@@ -1258,6 +1262,15 @@ func GetSybProcessingDetail(db *sql.DB, sybID string) (*SybProcessingDetail, err
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// sybPddAssociationText 只在当前蝦皮商品关联能找到有效、未删除的 PDD 商品时显示。
|
||||
// PDD 关联的唯一事实来源是 shopee_products;顺运宝明细不复制这份关系。
|
||||
func sybPddAssociationText(context repository.SybOrderContext) string {
|
||||
if context.PddGoodsID == "" || context.PddCollectStatus == "" {
|
||||
return ""
|
||||
}
|
||||
return "使用蝦皮商品的 PDD 关联:" + context.PddGoodsID + ",无需重复输入链接"
|
||||
}
|
||||
|
||||
// SaveSybLoginSession 登录成功后把会话缓存进数据库。
|
||||
//
|
||||
// `[必须]` 缓存写失败不能让已经登录的会话失效——本函数把错误原样
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<p class="missing" role="alert">顺运宝没有提供规格原文,系统无法安全判断要采购的颜色和尺码。请先核对上游货运单数据。</p>
|
||||
{{else}}
|
||||
<h3>关联采购商品</h3>
|
||||
{{if .PddAssociationText}}<p class="hint" role="status">{{.PddAssociationText}};仅在需要更换采购商品时修改下面的关联。</p>{{end}}
|
||||
<form method="post" action="/syb/associate-pdd" class="form-stack">
|
||||
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
||||
<input type="hidden" name="syb_id" value="{{.SybID}}">
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
</button>
|
||||
{{else}}—{{end}}
|
||||
</td>
|
||||
<td><span class="status-pill">{{.StageText}}</span><br><small>{{.StageHelp}}</small></td>
|
||||
<td><span class="status-pill">{{.StageText}}</span><br><small>{{.StageHelp}}</small>{{if .PddAssociationText}}<br><small class="hint">{{.PddAssociationText}}</small>{{end}}</td>
|
||||
<td>
|
||||
{{if eq .Stage "purchase_ready"}}
|
||||
<button type="button" data-modal-open="purchase-modal" data-purchase-open
|
||||
|
||||
Reference in New Issue
Block a user