fix: 修复收入统计 404,并隔离支付测试/生产配置

Dashboard 收入接口路径对齐;登录页去掉「授权管理平台」;Waffo 测试/生产密钥与 Product 映射分环境保存。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Logan.LiandCursor committed 2026-08-12 22:37:22 +08:00
1 parent 76bba729f1
commit 9b79eabd34
9 files changed
+391 -80

No files matched your search

@@ -86,29 +86,73 @@ func (s *SettingService) GetWaffo() (*dto.WaffoSettingsResponse, error) {
}
meta := payment.ParseWaffoPublicMeta(gw.PublicKey)
env := payment.NormalizeWaffoEnvironment(cfg.Environment)
meta.ApplyEnvProfile(env)
mappings := buildProductMappings(cfg, meta.ProductMappings)
productIDs := cloneProductIDs(cfg.ProductIDs)
bag := payment.ParseWaffoSecretBag(gw.SecretKey, env)
profiles := map[string]dto.WaffoEnvUI{
"test": buildEnvUI(meta, bag, "test"),
"live": buildEnvUI(meta, bag, "live"),
}
return &dto.WaffoSettingsResponse{
Enabled: enabled,
MerchantID: cfg.MerchantID,
StoreID: cfg.StoreID,
StoreSlug: cfg.StoreSlug,
Environment: cfg.Environment,
SandboxMode: cfg.Environment == "test",
Environment: env,
SandboxMode: env == "test",
Currency: cfg.Currency,
ProductID: cfg.ProductID,
ProductIDYearly: cfg.ProductIDYearly,
ProductIDPerpetual: cfg.ProductIDPerpetual,
ProductID: firstNonEmpty(meta.ProductID, cfg.ProductID),
ProductIDYearly: firstNonEmpty(meta.ProductIDYearly, cfg.ProductIDYearly),
ProductIDPerpetual: firstNonEmpty(meta.ProductIDPerpetual, cfg.ProductIDPerpetual),
ProductIDs: productIDs,
ProductMappings: mappings,
SuccessURL: cfg.SuccessURL,
WebhookURL: payment.DefaultWebhookURL,
PrivateKeyConfigured: strings.TrimSpace(cfg.PrivateKey) != "",
SourceHint: hint,
PrivateKeyConfigured: bag.SecretForEnv(env) != "",
PrivateKeyByEnv: map[string]bool{
"test": bag.SecretForEnv("test") != "",
"live": bag.SecretForEnv("live") != "",
},
Profiles: profiles,
SourceHint: hint,
}, nil
}
// buildEnvUI 组装单环境预览 // Logan.Li
func buildEnvUI(meta payment.WaffoPublicMeta, bag payment.WaffoSecretBag, env string) dto.WaffoEnvUI {
cp := meta
cp.ApplyEnvProfile(env)
cfgLike := payment.WaffoConfig{
ProductID: cp.ProductID,
ProductIDYearly: cp.ProductIDYearly,
ProductIDPerpetual: cp.ProductIDPerpetual,
ProductIDs: cloneProductIDs(cp.ProductIDs),
}
if len(cp.ProductMappings) > 0 {
if cfgLike.ProductIDs == nil {
cfgLike.ProductIDs = map[string]string{}
}
for _, m := range cp.ProductMappings {
k := strings.TrimSpace(strings.ToLower(m.PlanKey))
v := strings.TrimSpace(m.ProductID)
if k != "" && v != "" {
cfgLike.ProductIDs[k] = v
}
}
}
return dto.WaffoEnvUI{
ProductMappings: buildProductMappings(cfgLike, cp.ProductMappings),
ProductID: cp.ProductID,
ProductIDYearly: cp.ProductIDYearly,
ProductIDPerpetual: cp.ProductIDPerpetual,
PrivateKeyConfigured: bag.SecretForEnv(env) != "",
}
}
// UpdateWaffo 保存 Waffo 配置到 payment_gateway_configs(后台优先于 .env) // Logan.Li
func (s *SettingService) UpdateWaffo(req dto.WaffoSettingsUpdate) (*dto.WaffoSettingsResponse, error) {
var gw model.PaymentGatewayConfig
@@ -123,25 +167,35 @@ func (s *SettingService) UpdateWaffo(req dto.WaffoSettingsUpdate) (*dto.WaffoSet
}
}
productIDs, mappings := mergeProductIDInputs(req)
meta := payment.WaffoPublicMeta{
MerchantID: strings.TrimSpace(req.MerchantID),
StoreID: strings.TrimSpace(req.StoreID),
StoreSlug: strings.TrimSpace(req.StoreSlug),
ProductID: strings.TrimSpace(req.ProductID),
ProductIDYearly: strings.TrimSpace(req.ProductIDYearly),
ProductIDPerpetual: strings.TrimSpace(req.ProductIDPerpetual),
ProductIDs: productIDs,
ProductMappings: toPaymentMappings(mappings),
SuccessURL: strings.TrimSpace(req.SuccessURL),
Currency: strings.TrimSpace(req.Currency),
oldMeta := payment.ParseWaffoPublicMeta(gw.PublicKey)
oldEnv := payment.NormalizeWaffoEnvironment(oldMeta.Environment)
if oldEnv == "test" && !gw.SandboxMode {
oldEnv = "live"
}
productIDs, mappings := mergeProductIDInputs(req)
newEnv := payment.NormalizeWaffoEnvironment(req.Environment)
meta := oldMeta
if meta.EnvProfiles == nil {
meta.EnvProfiles = map[string]payment.WaffoEnvProfile{}
}
meta.MerchantID = strings.TrimSpace(req.MerchantID)
meta.StoreID = strings.TrimSpace(req.StoreID)
meta.StoreSlug = strings.TrimSpace(req.StoreSlug)
meta.SuccessURL = strings.TrimSpace(req.SuccessURL)
meta.Currency = strings.TrimSpace(req.Currency)
if meta.Currency == "" {
meta.Currency = "CNY"
}
meta.CurrencyYearly = meta.Currency
meta.CurrencyPerpetual = meta.Currency
meta.Environment = newEnv
meta.ProductID = strings.TrimSpace(req.ProductID)
meta.ProductIDYearly = strings.TrimSpace(req.ProductIDYearly)
meta.ProductIDPerpetual = strings.TrimSpace(req.ProductIDPerpetual)
meta.ProductIDs = productIDs
meta.ProductMappings = toPaymentMappings(mappings)
// 兼容字段与可扩展映射对齐 // Logan.Li
if meta.ProductIDYearly == "" {
@@ -154,13 +208,12 @@ func (s *SettingService) UpdateWaffo(req dto.WaffoSettingsUpdate) (*dto.WaffoSet
meta.ProductID = firstNonEmpty(meta.ProductIDPerpetual, meta.ProductIDYearly, productIDs["default"])
}
env := strings.ToLower(strings.TrimSpace(req.Environment))
switch env {
case "live", "prod", "production":
meta.Environment = "live"
// 当前环境映射写入 Profile,保留另一环境配置 // Logan.Li
meta.CaptureEnvProfile(newEnv)
if newEnv == "live" {
gw.SandboxMode = false
default:
meta.Environment = "test"
} else {
gw.SandboxMode = true
}
@@ -177,14 +230,20 @@ func (s *SettingService) UpdateWaffo(req dto.WaffoSettingsUpdate) (*dto.WaffoSet
gw.Enabled = true
}
bag := payment.ParseWaffoSecretBag(gw.SecretKey, oldEnv)
if req.ClearPrivateKey {
gw.SecretKey = ""
bag.ClearSecretForEnv(newEnv)
} else if pk := strings.TrimSpace(req.PrivateKey); pk != "" {
if _, err := payment.ParseMerchantPrivateKey(pk); err != nil {
return nil, errors.New("私钥无法解析: " + err.Error())
}
gw.SecretKey = pk
bag.SetSecretForEnv(newEnv, pk)
}
encodedSecret, err := payment.EncodeWaffoSecretBag(bag)
if err != nil {
return nil, errors.New("保存私钥失败")
}
gw.SecretKey = encodedSecret
if err := s.db.Save(&gw).Error; err != nil {
return nil, errors.New("保存 Waffo 配置失败")