f
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,6 +24,7 @@ data/*
|
||||
/app/main/api/_*
|
||||
__debug_bin.exe
|
||||
**/.../
|
||||
*.exe
|
||||
|
||||
|
||||
# 文档目录
|
||||
|
||||
@@ -45,6 +45,10 @@ service main {
|
||||
|
||||
@handler PaymentCheck
|
||||
post /pay/check (PaymentCheckReq) returns (PaymentCheckResp)
|
||||
|
||||
// 小程序虚拟支付:上报微信/Apple 客户端提示与步骤(写入服务端日志并可选查微信单)
|
||||
@handler XpayClientEvent
|
||||
post /pay/xpay/client-event (XpayClientEventReq) returns (XpayClientEventResp)
|
||||
}
|
||||
|
||||
type (
|
||||
@@ -69,6 +73,23 @@ type (
|
||||
WxOrderStatus int `json:"wx_order_status,optional"` // 微信侧订单 status
|
||||
WxOrderDetail string `json:"wx_order_detail,optional"` // query_order 原始 order 摘要(排查用)
|
||||
}
|
||||
XpayClientEventReq {
|
||||
OrderNo string `json:"order_no,optional"`
|
||||
Stage string `json:"stage" validate:"required"` // prepay_ok, invoke, success, fail, check
|
||||
EventType string `json:"event_type" validate:"required,oneof=info tip fail success"`
|
||||
Message string `json:"message,optional"` // 微信/Apple 展示给用户的话术(非 HTTP 报错)
|
||||
ErrMsg string `json:"err_msg,optional"`
|
||||
ErrCode int `json:"err_code,optional"`
|
||||
Errno int `json:"errno,optional"`
|
||||
SignData string `json:"sign_data,optional"`
|
||||
Device string `json:"device,optional"`
|
||||
Extra string `json:"extra,optional"`
|
||||
}
|
||||
XpayClientEventResp {
|
||||
WxOrderStatus int `json:"wx_order_status,optional"`
|
||||
WxOrderDetail string `json:"wx_order_detail,optional"`
|
||||
WxSyncError string `json:"wx_sync_error,optional"`
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
30
app/main/api/internal/handler/pay/xpayclienteventhandler.go
Normal file
30
app/main/api/internal/handler/pay/xpayclienteventhandler.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package pay
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"qnc-server/app/main/api/internal/logic/pay"
|
||||
"qnc-server/app/main/api/internal/svc"
|
||||
"qnc-server/app/main/api/internal/types"
|
||||
"qnc-server/common/result"
|
||||
"qnc-server/pkg/lzkit/validator"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func XpayClientEventHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.XpayClientEventReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate(req); err != nil {
|
||||
result.ParamValidateErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
l := pay.NewXpayClientEventLogic(r.Context(), svcCtx)
|
||||
resp, err := l.XpayClientEvent(&req)
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
||||
@@ -976,6 +976,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/pay/payment",
|
||||
Handler: pay.PaymentHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/pay/xpay/client-event",
|
||||
Handler: pay.XpayClientEventHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
|
||||
|
||||
65
app/main/api/internal/logic/pay/xpayclienteventlogic.go
Normal file
65
app/main/api/internal/logic/pay/xpayclienteventlogic.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"qnc-server/app/main/api/internal/svc"
|
||||
"qnc-server/app/main/api/internal/types"
|
||||
"qnc-server/common/ctxdata"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type XpayClientEventLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewXpayClientEventLogic(ctx context.Context, svcCtx *svc.ServiceContext) *XpayClientEventLogic {
|
||||
return &XpayClientEventLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// XpayClientEvent 记录小程序虚拟支付各步骤及微信/Apple 客户端提示(非 HTTP 异常)
|
||||
func (l *XpayClientEventLogic) XpayClientEvent(req *types.XpayClientEventReq) (*types.XpayClientEventResp, error) {
|
||||
userID, _ := ctxdata.GetUidFromCtx(l.ctx)
|
||||
|
||||
l.Infof("[xpay:client-event] user=%s order_no=%s stage=%s event=%s message=%q err_msg=%q err_code=%d errno=%d sign_data=%s device=%s extra=%s",
|
||||
userID, req.OrderNo, req.Stage, req.EventType, req.Message, req.ErrMsg, req.ErrCode, req.Errno,
|
||||
req.SignData, req.Device, req.Extra)
|
||||
|
||||
resp := &types.XpayClientEventResp{}
|
||||
|
||||
if req.OrderNo == "" || l.svcCtx.XpayService == nil || !l.svcCtx.XpayService.Enabled() {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 客户端 fail/tip 时主动 query_order,把微信服务端侧状态一并记入日志
|
||||
if req.EventType == "fail" || req.EventType == "tip" {
|
||||
openid, err := l.svcCtx.XpayService.GetWxMiniOpenID(l.ctx, l.svcCtx.UserAuthModel, userID)
|
||||
if err != nil {
|
||||
resp.WxSyncError = "获取 openid 失败: " + err.Error()
|
||||
l.Errorf("[xpay:client-event] query_order skip order_no=%s reason=%v", req.OrderNo, err)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
status, qErr := l.svcCtx.XpayService.QueryOrder(l.ctx, openid, req.OrderNo, "")
|
||||
if qErr != nil {
|
||||
resp.WxSyncError = qErr.Error()
|
||||
l.Errorf("[xpay:client-event] query_order FAIL order_no=%s client_msg=%q wx_err=%v",
|
||||
req.OrderNo, req.Message, qErr)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
resp.WxOrderStatus = status.Status
|
||||
resp.WxOrderDetail = status.RawOrder
|
||||
l.Infof("[xpay:client-event] query_order SNAPSHOT order_no=%s client_msg=%q wx_status=%d wx_order_id=%s paid_fee=%d err_msg=%s raw=%s",
|
||||
req.OrderNo, req.Message, status.Status, status.WxOrderID, status.PaidFee, status.ErrMsg, status.RawOrder)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"qnc-server/app/main/api/internal/service"
|
||||
"qnc-server/app/main/api/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
@@ -61,6 +62,9 @@ func (l *XpayPushLogic) HandlePOST(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
logx.WithContext(ctx).Infof("[xpay:push] recv event=%s order_no=%s openid=%s env=%d body=%s",
|
||||
notify.Event, orderNo, notify.OpenId, notify.Env, string(body))
|
||||
|
||||
already, _ := l.svcCtx.XpayService.AlreadyNotified(ctx, orderNo)
|
||||
if already {
|
||||
l.writePushResp(w, 0, "already notified")
|
||||
|
||||
@@ -1935,6 +1935,25 @@ type PaymentCheckResp struct {
|
||||
WxOrderDetail string `json:"wx_order_detail,optional"` // query_order 原始 order 摘要(排查用)
|
||||
}
|
||||
|
||||
type XpayClientEventReq struct {
|
||||
OrderNo string `json:"order_no,optional"`
|
||||
Stage string `json:"stage" validate:"required"` // prepay_ok, invoke, success, fail, check
|
||||
EventType string `json:"event_type" validate:"required,oneof=info tip fail success"`
|
||||
Message string `json:"message,optional"` // 微信/Apple 展示给用户的话术
|
||||
ErrMsg string `json:"err_msg,optional"`
|
||||
ErrCode int `json:"err_code,optional"`
|
||||
Errno int `json:"errno,optional"`
|
||||
SignData string `json:"sign_data,optional"`
|
||||
Device string `json:"device,optional"`
|
||||
Extra string `json:"extra,optional"`
|
||||
}
|
||||
|
||||
type XpayClientEventResp struct {
|
||||
WxOrderStatus int `json:"wx_order_status,optional"`
|
||||
WxOrderDetail string `json:"wx_order_detail,optional"`
|
||||
WxSyncError string `json:"wx_sync_error,optional"`
|
||||
}
|
||||
|
||||
type PaymentReq struct {
|
||||
Id string `json:"id"`
|
||||
PayMethod string `json:"pay_method"` // 支付方式: wechat, alipay, appleiap, test(仅开发环境), test_empty(仅开发环境-空报告模式)
|
||||
|
||||
Reference in New Issue
Block a user