Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Failing after 3m55s
新增收款商户、商户池轮询、微信授权配置独立管理;三类新支付 (C端套餐购买、C端资产钱包充值、代理在线预存款充值)无条件 经商户池选择并冻结路由,无旧综合配置回退。merchant_id 为空 历史支付继续按 payment_config_id 双读。凭证版本化加载与 ID+版本缓存保证轮换一致性。删除商户池新支付创建开关及全部 引用。
100 lines
4.0 KiB
Go
100 lines
4.0 KiB
Go
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
|
||
}
|