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 }