Files
junhong_cmp_fiber/internal/service/refund/payment_merchant.go
break 98c145fe70
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Failing after 3m55s
实现支付商户池与微信授权配置
新增收款商户、商户池轮询、微信授权配置独立管理;三类新支付
(C端套餐购买、C端资产钱包充值、代理在线预存款充值)无条件
经商户池选择并冻结路由,无旧综合配置回退。merchant_id 为空
历史支付继续按 payment_config_id 双读。凭证版本化加载与
ID+版本缓存保证轮换一致性。删除商户池新支付创建开关及全部
引用。
2026-09-09 18:13:04 +08:00

100 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package refund
import (
"context"
"strings"
"gorm.io/gorm"
merchantpayment "github.com/break/junhong_cmp_fiber/internal/application/merchantpayment"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
// SetPaymentMerchantRuntime 注入冻结商户的当前凭证版本加载器。
func (s *Service) SetPaymentMerchantRuntime(runtime *merchantpayment.RuntimeLoader) {
s.paymentMerchantRuntime = runtime
}
// preparePaymentRefundCredentials 只为既有套餐订单退款流程装载和校验支付凭证;本 Change
// 不发起任何渠道退款请求。钱包支付和线下支付没有收款商户凭证,直接放行。
// merchant_id 为空仅是留存期内的历史线上支付,独立 Change 清理后才可删除按
// payment_config_id 读取的兼容路径,绝不能按当前商户池推断商户。
func (s *Service) preparePaymentRefundCredentials(ctx context.Context, tx *gorm.DB, orderID uint) error {
var payment model.Payment
err := tx.WithContext(ctx).
Where("order_id = ? AND order_type = ? AND status = ?", orderID, model.PaymentOrderTypePackage, model.PaymentRecordStatusPaid).
Order("id DESC").
First(&payment).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil
}
return errors.Wrap(errors.CodeDatabaseError, err, "查询退款关联支付单失败")
}
// 钱包支付和线下支付没有收款商户凭证,不被本检查阻断。
if payment.PaymentMethod == model.PaymentByWallet || payment.PaymentMethod == model.PaymentByOffline {
return nil
}
if payment.MerchantID != nil {
if s.paymentMerchantRuntime == nil {
return errors.New(errors.CodeServiceUnavailable, "支付商户加载能力未配置")
}
merchant, loadErr := s.paymentMerchantRuntime.LoadMerchant(ctx, *payment.MerchantID)
if loadErr != nil {
return loadErr
}
return validateFrozenMerchantRefundCredentials(merchant)
}
if payment.PaymentConfigID == nil {
return errors.New(errors.CodeNoPaymentConfig, "历史支付单缺少支付配置")
}
var legacy model.WechatConfig
if err := tx.WithContext(ctx).Unscoped().First(&legacy, *payment.PaymentConfigID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeNoPaymentConfig, "历史支付配置不可用")
}
return errors.Wrap(errors.CodeDatabaseError, err, "读取历史支付配置失败")
}
return nil
}
// validateFrozenMerchantRefundCredentials 只判断既有渠道流程所需凭证是否完整。
// 当前系统没有任何渠道原路退款 Adapter因此返回前不调用微信、支付宝或富友。
func validateFrozenMerchantRefundCredentials(merchant *model.PaymentMerchant) error {
config, err := merchantpayment.MerchantConfig(merchant, nil)
if err != nil {
return err
}
switch config.ProviderType {
case model.ProviderTypeWechat:
if blank(config.WxMchID, config.WxAPIV3Key, config.WxCertContent, config.WxKeyContent, config.WxSerialNo, config.WxNotifyURL) {
return errors.New(errors.CodeNoPaymentConfig, "冻结微信商户退款凭证不完整")
}
case model.ProviderTypeWechatV2:
if blank(config.WxMchID, config.WxAPIV2Key, config.WxNotifyURL) {
return errors.New(errors.CodeNoPaymentConfig, "冻结微信商户退款凭证不完整")
}
case model.ProviderTypeFuiou:
if blank(config.FyInsCd, config.FyMchntCd, config.FyTermID, config.FyPrivateKey, config.FyPublicKey, config.FyAPIURL, config.FyNotifyURL) {
return errors.New(errors.CodeNoPaymentConfig, "冻结富友商户退款凭证不完整")
}
case "alipay":
if blank(config.AliAppID, config.AliPrivateKey, config.AliPublicKey, config.AliNotifyURL, config.AliReturnURL) {
return errors.New(errors.CodeNoPaymentConfig, "冻结支付宝商户退款凭证不完整")
}
default:
return errors.New(errors.CodeNoPaymentConfig, "冻结商户不支持现有退款流程")
}
return nil
}
func blank(values ...string) bool {
for _, value := range values {
if strings.TrimSpace(value) == "" {
return true
}
}
return false
}