fix: 修复富友预下单报文格式错(1014) — XML根元素、小程序tradeType、termIP三处问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m27s

This commit is contained in:
2026-03-30 11:57:46 +08:00
parent f339fb1987
commit 0c82ae2b73
4 changed files with 36 additions and 21 deletions

View File

@@ -46,14 +46,15 @@ func (w *wechatPaymentProvider) CreateJSAPIPayment(ctx context.Context, orderNo,
// fuiouPaymentProvider 富友支付适配器。 // fuiouPaymentProvider 富友支付适配器。
type fuiouPaymentProvider struct { type fuiouPaymentProvider struct {
client *fuiou.Client client *fuiou.Client
appID string appID string
tradeType string
} }
// CreateJSAPIPayment 创建富友 JSAPI 预下单。 // CreateJSAPIPayment 创建富友 JSAPI 预下单。
func (f *fuiouPaymentProvider) CreateJSAPIPayment(ctx context.Context, orderNo, description, openID string, amount int) (*PaymentResult, error) { func (f *fuiouPaymentProvider) CreateJSAPIPayment(ctx context.Context, orderNo, description, openID string, amount int) (*PaymentResult, error) {
amountStr := strconv.Itoa(amount) amountStr := strconv.Itoa(amount)
resp, err := f.client.WxPreCreate(orderNo, amountStr, description, "", "JSAPI", f.appID, openID) resp, err := f.client.WxPreCreate(orderNo, amountStr, description, "127.0.0.1", f.tradeType, f.appID, openID)
if err != nil { if err != nil {
return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "富友预下单失败") return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "富友预下单失败")
} }
@@ -69,9 +70,14 @@ func (f *fuiouPaymentProvider) CreateJSAPIPayment(ctx context.Context, orderNo,
} }
// newPaymentProvider 根据支付配置创建支付提供者。 // newPaymentProvider 根据支付配置创建支付提供者。
func (s *Service) newPaymentProvider(config *model.WechatConfig, appID string) (PaymentProvider, error) { // appType: "official_account" 或 "miniapp"
func (s *Service) newPaymentProvider(config *model.WechatConfig, appID, appType string) (PaymentProvider, error) {
switch config.ProviderType { switch config.ProviderType {
case model.ProviderTypeFuiou: case model.ProviderTypeFuiou:
tradeType := "JSAPI"
if appType == "miniapp" {
tradeType = "LETPAY"
}
client, err := fuiou.NewClient( client, err := fuiou.NewClient(
config.FyInsCd, config.FyInsCd,
config.FyMchntCd, config.FyMchntCd,
@@ -85,7 +91,7 @@ func (s *Service) newPaymentProvider(config *model.WechatConfig, appID string) (
if err != nil { if err != nil {
return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "创建富友客户端失败") return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "创建富友客户端失败")
} }
return &fuiouPaymentProvider{client: client, appID: appID}, nil return &fuiouPaymentProvider{client: client, appID: appID, tradeType: tradeType}, nil
default: default:
cache := wechat.NewRedisCache(s.redis) cache := wechat.NewRedisCache(s.redis)
paymentApp, err := wechat.NewPaymentAppFromConfig(config, appID, cache, s.logger) paymentApp, err := wechat.NewPaymentAppFromConfig(config, appID, cache, s.logger)

View File

@@ -174,7 +174,7 @@ func (s *Service) CreateOrder(ctx context.Context, customerID uint, req *dto.Cli
} }
}() }()
paymentProvider, err := s.newPaymentProvider(activeConfig, appID) paymentProvider, err := s.newPaymentProvider(activeConfig, appID, req.AppType)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -202,6 +202,12 @@ func structToMap(data interface{}) map[string]string {
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
field := t.Field(i) field := t.Field(i)
// 排除 XMLName 字段xml.Name 类型,仅用于指定根元素名称)
if field.Name == "XMLName" {
continue
}
value := v.Field(i).String() value := v.Field(i).String()
tag := field.Tag.Get("xml") tag := field.Tag.Get("xml")

View File

@@ -2,23 +2,26 @@
// 实现富友 wxPreCreate 接口的签名、通信和回调处理 // 实现富友 wxPreCreate 接口的签名、通信和回调处理
package fuiou package fuiou
import "encoding/xml"
// WxPreCreateRequest wxPreCreate 下单请求 // WxPreCreateRequest wxPreCreate 下单请求
type WxPreCreateRequest struct { type WxPreCreateRequest struct {
Version string `xml:"version"` // 版本号: 1.0 XMLName xml.Name `xml:"xml"`
InsCd string `xml:"ins_cd"` // 机构号 Version string `xml:"version"` // 版本号: 1.0
MchntCd string `xml:"mchnt_cd"` // 商户 InsCd string `xml:"ins_cd"` // 机构
TermId string `xml:"term_id"` // 终端 MchntCd string `xml:"mchnt_cd"` // 商户
RandomStr string `xml:"random_str"` // 随机字符串 TermId string `xml:"term_id"` // 终端号
Sign string `xml:"sign"` // 签名 RandomStr string `xml:"random_str"` // 随机字符串
MchntOrderNo string `xml:"mchnt_order_no"` // 商户订单号 Sign string `xml:"sign"` // 签名
TradeType string `xml:"trade_type"` // 交易类型: JSAPI=公众号 LETPAY=小程序 MchntOrderNo string `xml:"mchnt_order_no"` // 商户订单号
OrderAmt string `xml:"order_amt"` // 订单金额(分) TradeType string `xml:"trade_type"` // 交易类型: JSAPI=公众号 LETPAY=小程序
GoodsDesc string `xml:"goods_des"` // 商品描述 OrderAmt string `xml:"order_amt"` // 订单金额(分)
TermIp string `xml:"term_ip"` // 终端IP GoodsDesc string `xml:"goods_des"` // 商品描述
NotifyUrl string `xml:"notify_url"` // 回调地址 TermIp string `xml:"term_ip"` // 终端IP
SubAppid string `xml:"sub_appid"` // 子应用ID公众号/小程序AppID NotifyUrl string `xml:"notify_url"` // 回调地址
SubOpenid string `xml:"sub_openid"` // 用户OpenID SubAppid string `xml:"sub_appid"` // 子应用ID公众号/小程序AppID
LimitPay string `xml:"limit_pay"` // 限制支付方式(可选) SubOpenid string `xml:"sub_openid"` // 用户OpenID
LimitPay string `xml:"limit_pay"` // 限制支付方式(可选)
} }
// WxPreCreateResponse wxPreCreate 下单响应 // WxPreCreateResponse wxPreCreate 下单响应