fix: 修复微信/富友支付回调配置加载错误
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m5s

- WechatPayCallback 移除对永远为 nil 的单例 wechatPayment 的依赖,
  改为动态按 payment_config_id 加载创建订单时所用的精确配置
- PaymentV2Service 新增 VerifyCallback()(v2 XML 验签)和 PeekOrderNo()(不验签预解析)
- FuiouPayCallback 由 GetActiveConfig 改为 GetConfigForCallback,
  通过 ParseNotify 预解析订单号后精确加载配置,防止切换配置后旧订单验签失败
- wechat_config.Service 注入 assetRechargeStore/agentRechargeStore,
  新增 GetConfigForCallback():按订单号前缀查 payment_config_id,
  GetByIDUnscoped 加载配置(含已停用/软删除记录),找不到则回退激活配置
- 修复微信 v2 回调响应格式:从 JSON 改为 XML,避免微信持续重试
This commit is contained in:
2026-03-31 19:17:45 +08:00
parent 69ee754c19
commit 045aa4fa3a
5 changed files with 283 additions and 49 deletions

View File

@@ -31,21 +31,33 @@ type AuditServiceInterface interface {
// Service 微信参数配置业务服务
type Service struct {
store *postgres.WechatConfigStore
orderStore *postgres.OrderStore
auditService AuditServiceInterface
redis *redis.Client
logger *zap.Logger
store *postgres.WechatConfigStore
orderStore *postgres.OrderStore
assetRechargeStore *postgres.AssetRechargeStore
agentRechargeStore *postgres.AgentRechargeStore
auditService AuditServiceInterface
redis *redis.Client
logger *zap.Logger
}
// New 创建微信参数配置服务实例
func New(store *postgres.WechatConfigStore, orderStore *postgres.OrderStore, auditService AuditServiceInterface, rdb *redis.Client, logger *zap.Logger) *Service {
func New(
store *postgres.WechatConfigStore,
orderStore *postgres.OrderStore,
assetRechargeStore *postgres.AssetRechargeStore,
agentRechargeStore *postgres.AgentRechargeStore,
auditService AuditServiceInterface,
rdb *redis.Client,
logger *zap.Logger,
) *Service {
return &Service{
store: store,
orderStore: orderStore,
auditService: auditService,
redis: rdb,
logger: logger,
store: store,
orderStore: orderStore,
assetRechargeStore: assetRechargeStore,
agentRechargeStore: agentRechargeStore,
auditService: auditService,
redis: rdb,
logger: logger,
}
}
@@ -471,3 +483,58 @@ func (s *Service) mergeSensitiveField(target *string, newVal *string) {
*target = *newVal
}
}
// GetConfigForCallback 按订单号查找创建该订单时所用的支付配置(含已软删除/停用的记录)
// 回调验签必须使用创建订单时的密钥,否则签名不匹配。
// 若找不到 payment_config_id旧订单或数据缺失回退到当前激活配置。
func (s *Service) GetConfigForCallback(ctx context.Context, orderNo string) (*model.WechatConfig, error) {
configID, err := s.resolvePaymentConfigID(ctx, orderNo)
if err != nil {
s.logger.Warn("回调:查询订单 payment_config_id 失败,回退激活配置",
zap.String("order_no", orderNo),
zap.Error(err),
)
}
if configID != nil {
cfg, err := s.store.GetByIDUnscoped(ctx, *configID)
if err == nil {
return cfg, nil
}
s.logger.Warn("回调:按 config_id 加载配置失败,回退激活配置",
zap.Uint("config_id", *configID),
zap.Error(err),
)
}
return s.GetActiveConfig(ctx)
}
// resolvePaymentConfigID 按订单号前缀从对应表中取 payment_config_id
func (s *Service) resolvePaymentConfigID(ctx context.Context, orderNo string) (*uint, error) {
switch {
case len(orderNo) >= 3 && orderNo[:3] == "ORD":
order, err := s.orderStore.GetByOrderNo(ctx, orderNo)
if err != nil {
return nil, err
}
return order.PaymentConfigID, nil
case len(orderNo) >= 4 && orderNo[:4] == constants.AssetRechargeOrderPrefix:
record, err := s.assetRechargeStore.GetByRechargeNo(ctx, orderNo)
if err != nil {
return nil, err
}
return record.PaymentConfigID, nil
case len(orderNo) >= 4 && orderNo[:4] == constants.AgentRechargeOrderPrefix:
record, err := s.agentRechargeStore.GetByRechargeNo(ctx, orderNo)
if err != nil {
return nil, err
}
return record.PaymentConfigID, nil
default:
return nil, fmt.Errorf("未知订单号前缀: %s", orderNo)
}
}