fix(delivery): 乐玩不可用时回退 DLC,避免提交 UID 绑定失败

legacy 双渠道配置升为 priority;显式 lewan 且具备 DLC 时允许回退,缓解 LEWAN_* 未注入导致的 bind 失败。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-09-15 11:51:32 +08:00
co-authored by Cursor
parent 7df1330b65
commit 6c41834274
2 changed files with 41 additions and 8 deletions
+18 -7
View File
@@ -35,7 +35,9 @@ func ParseProductRoutingConfig(fulfillmentConfig string, sku string) ProductRout
_ = json.Unmarshal([]byte(fulfillmentConfig), &cfg)
}
// 兼容老配置或单 provider 字段
// 兼容老配置:只抽取字段,不提前固化 routing_mode,
// 避免仅有 lewan_product_id 时在补齐内置 DLC 前被锁成 lewan-only。
legacyProvider := ""
if cfg.RoutingMode == "" {
var legacy struct {
Provider string `json:"provider"`
@@ -45,11 +47,11 @@ func ParseProductRoutingConfig(fulfillmentConfig string, sku string) ProductRout
if strings.TrimSpace(fulfillmentConfig) != "" {
_ = json.Unmarshal([]byte(fulfillmentConfig), &legacy)
}
if legacy.Provider == ProviderLewan || legacy.LewanProductID != "" {
cfg.RoutingMode = RoutingModeLewan
legacyProvider = strings.TrimSpace(legacy.Provider)
if cfg.LewanProductID == "" && legacy.LewanProductID != "" {
cfg.LewanProductID = legacy.LewanProductID
} else if legacy.Provider == ProviderDLC {
cfg.RoutingMode = RoutingModeDLC
}
if cfg.DLCGoodID == "" && legacy.DLCGoodID != "" {
cfg.DLCGoodID = legacy.DLCGoodID
}
}
@@ -60,13 +62,15 @@ func ParseProductRoutingConfig(fulfillmentConfig string, sku string) ProductRout
cfg.DLCGoodID = builtinDLC
}
// 若未配置 RoutingMode
// 若未配置 RoutingMode:双渠道优先 priority,单渠道按已有 ID / legacy provider 决定
if cfg.RoutingMode == "" {
if cfg.LewanProductID != "" && cfg.DLCGoodID != "" {
cfg.RoutingMode = RoutingModePriority
cfg.Priority = []string{ProviderLewan, ProviderDLC}
} else if cfg.LewanProductID != "" {
} else if cfg.LewanProductID != "" || legacyProvider == ProviderLewan {
cfg.RoutingMode = RoutingModeLewan
} else if legacyProvider == ProviderDLC {
cfg.RoutingMode = RoutingModeDLC
} else {
cfg.RoutingMode = RoutingModeDLC
}
@@ -184,6 +188,13 @@ func (r *FulfillmentRouter) ResolveProviders(order *model.FulfillmentOrder) ([]F
if p, ok := r.providers[ProviderLewan]; ok {
list = append(list, p)
}
// 显式 lewan 但商品同时具备 DLC 配置时,乐玩不可用(密钥未配/上游失败)允许回退 DLC,
// 避免「套装-浪漫天命」等双渠道商品在 LEWAN_* 未注入时提交 UID 直接失败。
if cfg.DLCGoodID != "" {
if p, ok := r.providers[ProviderDLC]; ok {
list = append(list, p)
}
}
case RoutingModeDLC:
if p, ok := r.providers[ProviderDLC]; ok {
list = append(list, p)
+23 -1
View File
@@ -39,12 +39,22 @@ func TestParseProductRoutingConfig(t *testing.T) {
t.Fatalf("mismatched IDs: dlc=%s lewan=%s", cfg3.DLCGoodID, cfg3.LewanProductID)
}
// Case 4: 兼容历史 legacy 单 provider 字段
// Case 4: 兼容历史 legacy 单 provider 字段(无内置 DLC 时仍为 lewan-only)
cfg4JSON := `{"provider":"lewan","lewan_product_id":"uuid-999"}`
cfg4 := ParseProductRoutingConfig(cfg4JSON, "any_sku")
if cfg4.RoutingMode != RoutingModeLewan || cfg4.LewanProductID != "uuid-999" {
t.Fatalf("legacy lewan format failed: %+v", cfg4)
}
// Case 5: legacy 仅有 lewan_product_id,但 SKU 有内置 DLC → 应升为 priority
cfg5JSON := `{"lewan_product_id":"b1fff090-e389-4c6c-9c51-32751582239d"}`
cfg5 := ParseProductRoutingConfig(cfg5JSON, "suit_romantic_destiny")
if cfg5.RoutingMode != RoutingModePriority {
t.Fatalf("expected priority for dual-capable legacy config, got %s", cfg5.RoutingMode)
}
if cfg5.DLCGoodID != "682ef39ca8f40c4234c59f38" {
t.Fatalf("expected builtin DLC good id, got %s", cfg5.DLCGoodID)
}
}
func TestFulfillmentRouterResolution(t *testing.T) {
@@ -73,6 +83,18 @@ func TestFulfillmentRouterResolution(t *testing.T) {
t.Fatalf("expected Lewan provider, got %d providers", len(providers))
}
// Case 2b: 显式 lewan 但 SKU 有内置 DLC → 应附带 DLC 回退
orderLewanWithDLC := &model.FulfillmentOrder{
ProductSKU: "suit_romantic_destiny",
MerchantProduct: &model.MerchantProduct{
FulfillmentConfig: `{"routing_mode":"lewan","lewan_product_id":"b1fff090-e389-4c6c-9c51-32751582239d","dlc_good_id":""}`,
},
}
providers, _ = router.ResolveProviders(orderLewanWithDLC)
if len(providers) != 2 || providers[0].Name() != ProviderLewan || providers[1].Name() != ProviderDLC {
t.Fatalf("expected [lewan, dlc] fallback, got %v", providerNames(providers))
}
// Case 3: 优先级路由 [lewan, dlc]
orderPriority := &model.FulfillmentOrder{
ProductSKU: "shared_item",