f
This commit is contained in:
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -25,6 +26,14 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// wxpayAPIHTTPStatus 安全读取微信支付 API 的 HTTP 状态码;本地签名/随机串失败时 result 可能为 nil。
|
||||||
|
func wxpayAPIHTTPStatus(result *core.APIResult) int {
|
||||||
|
if result == nil || result.Response == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return result.Response.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TradeStateSuccess = "SUCCESS" // 支付成功
|
TradeStateSuccess = "SUCCESS" // 支付成功
|
||||||
TradeStateRefund = "REFUND" // 转入退款
|
TradeStateRefund = "REFUND" // 转入退款
|
||||||
@@ -175,7 +184,7 @@ func (w *WechatPayService) CreateWechatAppOrder(ctx context.Context, amount floa
|
|||||||
resp, result, err := svc.Prepay(ctx, payRequest)
|
resp, result, err := svc.Prepay(ctx, payRequest)
|
||||||
logx.Infof("微信app支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
logx.Infof("微信app支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回预支付交易会话标识
|
// 返回预支付交易会话标识
|
||||||
@@ -200,14 +209,23 @@ func jsapiRequestPaymentToMap(resp *jsapi.PrepayWithRequestPaymentResponse) (map
|
|||||||
if resp.Package != nil {
|
if resp.Package != nil {
|
||||||
m["package"] = *resp.Package
|
m["package"] = *resp.Package
|
||||||
}
|
}
|
||||||
if resp.SignType != nil {
|
if resp.SignType != nil && *resp.SignType != "" {
|
||||||
m["signType"] = *resp.SignType
|
m["signType"] = *resp.SignType
|
||||||
|
} else {
|
||||||
|
m["signType"] = "RSA"
|
||||||
}
|
}
|
||||||
if resp.PaySign != nil {
|
if resp.PaySign != nil {
|
||||||
m["paySign"] = *resp.PaySign
|
m["paySign"] = *resp.PaySign
|
||||||
}
|
}
|
||||||
if len(m) != 6 {
|
var missing []string
|
||||||
return nil, fmt.Errorf("微信 JSAPI 调起参数不完整")
|
for _, key := range []string{"appId", "timeStamp", "nonceStr", "package", "paySign"} {
|
||||||
|
if m[key] == "" {
|
||||||
|
missing = append(missing, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missing) > 0 {
|
||||||
|
logx.Errorf("[WechatPay] JSAPI 调起参数缺项: missing=%v resp=%s", missing, resp.String())
|
||||||
|
return nil, fmt.Errorf("微信 JSAPI 调起参数不完整: 缺少或为空 %v", missing)
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
@@ -237,7 +255,7 @@ func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amo
|
|||||||
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
|
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
|
||||||
logx.Infof("微信小程序支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
logx.Infof("微信小程序支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
return jsapiRequestPaymentToMap(resp)
|
return jsapiRequestPaymentToMap(resp)
|
||||||
}
|
}
|
||||||
@@ -270,7 +288,7 @@ func (w *WechatPayService) CreateWechatH5Order(ctx context.Context, amount float
|
|||||||
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
return jsapiRequestPaymentToMap(resp)
|
return jsapiRequestPaymentToMap(resp)
|
||||||
}
|
}
|
||||||
@@ -316,31 +334,28 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
|
|||||||
if getUidErr != nil {
|
if getUidErr != nil {
|
||||||
return "", getUidErr
|
return "", getUidErr
|
||||||
}
|
}
|
||||||
// 微信内 H5:优先 wxh5_openid(与公众号/网页 AppID 一致);若无则尝试 wxmini_openid(走小程序 AppID 下单)
|
// 微信内置浏览器 JSAPI 必须使用与商户公众号一致的 openid(snsapi_base / snsapi_userinfo 授权后写入 wxh5_openid)。
|
||||||
|
// 不可使用小程序 openid 兜底:AppID 与 openid 主体不一致会导致下单失败或调起异常。
|
||||||
h5Auth, h5Err := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID)
|
h5Auth, h5Err := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID)
|
||||||
if h5Err == nil {
|
if h5Err != nil {
|
||||||
logx.Infof("微信h5支付订单:userAuthModel(wxh5): %+v", h5Auth)
|
if errors.Is(h5Err, model.ErrNotFound) {
|
||||||
prepayData, err = w.CreateWechatH5Order(ctx, amount, description, outTradeNo, h5Auth.AuthKey)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
} else if h5Err == model.ErrNotFound {
|
|
||||||
miniAuth, miniErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMiniOpenID)
|
|
||||||
if miniErr != nil {
|
|
||||||
return "", miniErr
|
|
||||||
}
|
|
||||||
logx.WithContext(ctx).Infof(
|
logx.WithContext(ctx).Infof(
|
||||||
"[WechatPay] wxh5 无 wxh5_openid,使用 wxmini_openid 下单 out_trade_no=%s user_id=%d",
|
"[WechatPay] wxh5 缺少 user_auth(wxh5_openid) user_id=%d out_trade_no=%s,需先走公众号网页授权(建议 scope=snsapi_base)",
|
||||||
outTradeNo, userID,
|
userID, outTradeNo,
|
||||||
)
|
)
|
||||||
logx.Infof("微信h5支付订单:userAuthModel(wxmini fallback): %+v", miniAuth)
|
return "", fmt.Errorf("微信内支付需先完成公众号网页授权以获取 openid(建议使用 snsapi_base 静默授权)")
|
||||||
prepayData, err = w.CreateWechatMiniProgramOrder(ctx, amount, description, outTradeNo, miniAuth.AuthKey)
|
}
|
||||||
|
return "", h5Err
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(h5Auth.AuthKey) == "" {
|
||||||
|
logx.WithContext(ctx).Errorf("[WechatPay] wxh5_openid 记录存在但 auth_key 为空 user_id=%d", userID)
|
||||||
|
return "", fmt.Errorf("微信内支付 openid 未就绪,请重新完成公众号网页授权")
|
||||||
|
}
|
||||||
|
logx.Infof("微信h5支付订单:userAuthModel(wxh5): %+v", h5Auth)
|
||||||
|
prepayData, err = w.CreateWechatH5Order(ctx, amount, description, outTradeNo, strings.TrimSpace(h5Auth.AuthKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return "", h5Err
|
|
||||||
}
|
|
||||||
case model.PlatformApp:
|
case model.PlatformApp:
|
||||||
// 如果是 APP 平台,调用 APP 支付订单创建
|
// 如果是 APP 平台,调用 APP 支付订单创建
|
||||||
prepayData, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo)
|
prepayData, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo)
|
||||||
@@ -355,7 +370,10 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
|
|||||||
|
|
||||||
if prepayData == nil {
|
if prepayData == nil {
|
||||||
logx.WithContext(ctx).Errorf("[WechatPay] CreateWechatOrder 返回 prepayData 为 nil platform=%q", platform)
|
logx.WithContext(ctx).Errorf("[WechatPay] CreateWechatOrder 返回 prepayData 为 nil platform=%q", platform)
|
||||||
} else if m, isMap := prepayData.(map[string]string); isMap {
|
return nil, fmt.Errorf("微信支付返回数据为空 platform=%s", platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, isMap := prepayData.(map[string]string); isMap {
|
||||||
keys := make([]string, 0, len(m))
|
keys := make([]string, 0, len(m))
|
||||||
for k := range m {
|
for k := range m {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
@@ -400,7 +418,7 @@ func (w *WechatPayService) QueryOrderStatus(ctx context.Context, transactionID s
|
|||||||
Mchid: core.String(w.config.Wxpay.MchID),
|
Mchid: core.String(w.config.Wxpay.MchID),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user