新增收款商户、商户池轮询、微信授权配置独立管理;三类新支付 (C端套餐购买、C端资产钱包充值、代理在线预存款充值)无条件 经商户池选择并冻结路由,无旧综合配置回退。merchant_id 为空 历史支付继续按 payment_config_id 双读。凭证版本化加载与 ID+版本缓存保证轮换一致性。删除商户池新支付创建开关及全部 引用。
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
merchantpayment "github.com/break/junhong_cmp_fiber/internal/application/merchantpayment"
|
||||
systemconfigapp "github.com/break/junhong_cmp_fiber/internal/application/systemconfig"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/wechat"
|
||||
)
|
||||
|
||||
// Redis 缓存键
|
||||
@@ -544,6 +546,28 @@ func (s *Service) GetActiveConfig(ctx context.Context) (*model.WechatConfig, err
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetAuthorizationConfig 读取唯一启用且按凭证版本缓存的 C 端微信授权配置。
|
||||
// 仅用于兼容现有微信 SDK 的配置结构,绝不回退到 tb_wechat_config。
|
||||
func (s *Service) GetAuthorizationConfig(ctx context.Context) (*model.WechatConfig, error) {
|
||||
if s == nil || s.store == nil {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "微信授权加载能力未配置")
|
||||
}
|
||||
authorization, err := merchantpayment.NewRuntimeLoader(s.store.DB(), s.redis).LoadAuthorization(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.WechatConfig{
|
||||
IsActive: true,
|
||||
OaAppID: authorization.OaAppID,
|
||||
OaAppSecret: authorization.OaAppSecret,
|
||||
OaToken: authorization.OaToken,
|
||||
OaAesKey: authorization.OaAesKey,
|
||||
OaOAuthRedirectURL: authorization.OaOAuthRedirectURL,
|
||||
MiniappAppID: authorization.MiniappAppID,
|
||||
MiniappAppSecret: authorization.MiniappAppSecret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetActiveConfigForAPI 获取当前生效的支付配置(API 响应,已脱敏)
|
||||
func (s *Service) GetActiveConfigForAPI(ctx context.Context) (*dto.WechatConfigResponse, error) {
|
||||
config, err := s.GetActiveConfig(ctx)
|
||||
@@ -594,30 +618,74 @@ func (s *Service) mergeSensitiveField(target *string, newVal *string) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetConfigForCallback 按订单号查找创建该订单时所用的支付配置(含已软删除/停用的记录)
|
||||
// 回调验签必须使用创建订单时的密钥,否则签名不匹配。
|
||||
// 若找不到 payment_config_id(旧订单或数据缺失),回退到当前激活配置。
|
||||
// GetByIDUnscoped loads a historical comprehensive payment configuration, including soft-deleted rows.
|
||||
func (s *Service) GetByIDUnscoped(ctx context.Context, id uint) (*model.WechatConfig, error) {
|
||||
if s == nil || s.store == nil {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "旧支付配置加载能力未配置")
|
||||
}
|
||||
return s.store.GetByIDUnscoped(ctx, id)
|
||||
}
|
||||
|
||||
// GetConfigForCallback 按支付单冻结的商户或旧支付配置加载回调凭证。
|
||||
// merchant_id 为空仅表示数据留存期内的历史支付:本 Change 只允许按其
|
||||
// payment_config_id 读取,独立 Change 完成留存清理后才可删除这条旧路径。
|
||||
// 禁止按当前启用池、当前综合配置推断或回填历史支付的实际商户。
|
||||
func (s *Service) GetConfigForCallback(ctx context.Context, orderNo string) (*model.WechatConfig, error) {
|
||||
if s.paymentStore != nil {
|
||||
payment, err := s.paymentStore.GetByPaymentNo(ctx, orderNo)
|
||||
if err == nil && payment.MerchantID != nil {
|
||||
loader := merchantpayment.NewRuntimeLoader(s.store.DB(), s.redis)
|
||||
merchant, loadErr := loader.LoadMerchant(ctx, *payment.MerchantID)
|
||||
if loadErr != nil {
|
||||
return nil, loadErr
|
||||
}
|
||||
// 仅微信直连(v3/v2)商户需要全局授权配置中的 AppID;富友商户不依赖该配置。
|
||||
// 授权字段只注入内存中的渠道配置,绝不写入支付快照、日志或审计。
|
||||
if merchant.ProviderType == model.ProviderTypeWechat || merchant.ProviderType == model.ProviderTypeWechatV2 {
|
||||
authorization, authErr := loader.LoadAuthorization(ctx)
|
||||
if authErr != nil {
|
||||
return nil, authErr
|
||||
}
|
||||
return merchantpayment.MerchantConfig(merchant, authorization)
|
||||
}
|
||||
return merchantpayment.MerchantConfig(merchant, nil)
|
||||
}
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询支付单路由失败")
|
||||
}
|
||||
if err == nil && payment.PaymentConfigID == nil {
|
||||
return nil, errors.New(errors.CodeNoPaymentConfig, "历史支付单缺少支付配置")
|
||||
}
|
||||
}
|
||||
|
||||
configID, err := s.resolvePaymentConfigID(ctx, orderNo)
|
||||
if err != nil {
|
||||
s.logger.Warn("回调:查询订单 payment_config_id 失败,回退激活配置",
|
||||
zap.String("order_no", orderNo),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, 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),
|
||||
)
|
||||
if configID == nil {
|
||||
return nil, errors.New(errors.CodeNoPaymentConfig, "历史支付单缺少支付配置")
|
||||
}
|
||||
cfg, loadErr := s.store.GetByIDUnscoped(ctx, *configID)
|
||||
if loadErr != nil {
|
||||
return nil, errors.Wrap(errors.CodeNoPaymentConfig, loadErr, "历史支付配置不可用")
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
return s.GetActiveConfig(ctx)
|
||||
// GetPaymentServiceForCallback 使用已选定的支付配置构造回调验签实例。
|
||||
// 回调验签只能使用支付单冻结商户的当前凭证,不能复用进程启动时的旧支付实例。
|
||||
func (s *Service) GetPaymentServiceForCallback(config *model.WechatConfig) (wechat.PaymentServiceInterface, error) {
|
||||
if s == nil || s.redis == nil {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "微信支付回调加载能力未配置")
|
||||
}
|
||||
if config == nil || config.ProviderType != model.ProviderTypeWechat {
|
||||
return nil, errors.New(errors.CodeWechatConfigUnavailable, "微信支付回调配置不可用")
|
||||
}
|
||||
app, err := wechat.NewPaymentAppFromConfig(config, config.OaAppID, wechat.NewRedisCache(s.redis), s.logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeWechatPayFailed, err, "构建微信支付回调验签实例失败")
|
||||
}
|
||||
return wechat.NewPaymentService(app, s.logger), nil
|
||||
}
|
||||
|
||||
// resolvePaymentConfigID 按订单号前缀从对应表中取 payment_config_id
|
||||
|
||||
Reference in New Issue
Block a user