2026-06-06 11:52:06 +08:00
|
|
|
package pay
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
|
|
"qnc-server/app/main/api/internal/service"
|
|
|
|
|
"qnc-server/app/main/api/internal/svc"
|
2026-06-07 14:47:50 +08:00
|
|
|
|
2026-06-06 11:52:06 +08:00
|
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type XpayPushLogic struct {
|
|
|
|
|
logx.Logger
|
|
|
|
|
svcCtx *svc.ServiceContext
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewXpayPushLogic(svcCtx *svc.ServiceContext) *XpayPushLogic {
|
|
|
|
|
return &XpayPushLogic{svcCtx: svcCtx}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HandleGET mp 后台配置消息推送时的验签
|
|
|
|
|
func (l *XpayPushLogic) HandleGET(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
q := r.URL.Query()
|
|
|
|
|
signature := q.Get("signature")
|
|
|
|
|
timestamp := q.Get("timestamp")
|
|
|
|
|
nonce := q.Get("nonce")
|
|
|
|
|
echostr := q.Get("echostr")
|
|
|
|
|
|
|
|
|
|
if l.svcCtx.XpayService.VerifyPushSignature(signature, timestamp, nonce) {
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
_, _ = w.Write([]byte(echostr))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
w.WriteHeader(http.StatusForbidden)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HandlePOST 接收 xpay_goods_deliver_notify
|
|
|
|
|
func (l *XpayPushLogic) HandlePOST(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
l.writePushResp(w, 1, "read body failed")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var notify service.XpayDeliverNotify
|
|
|
|
|
if err := json.Unmarshal(body, ¬ify); err != nil {
|
|
|
|
|
l.writePushResp(w, 1, "parse failed")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if notify.Event != "" && notify.Event != "xpay_goods_deliver_notify" {
|
|
|
|
|
l.writePushResp(w, 0, "ignored")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orderNo := notify.OutTradeNo
|
|
|
|
|
if orderNo == "" {
|
|
|
|
|
l.writePushResp(w, 1, "missing OutTradeNo")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx := r.Context()
|
2026-06-07 14:47:50 +08:00
|
|
|
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))
|
|
|
|
|
|
2026-06-06 11:52:06 +08:00
|
|
|
already, _ := l.svcCtx.XpayService.AlreadyNotified(ctx, orderNo)
|
|
|
|
|
if already {
|
|
|
|
|
l.writePushResp(w, 0, "already notified")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
order, findErr := l.svcCtx.OrderModel.FindOneByOrderNo(ctx, orderNo)
|
|
|
|
|
if findErr != nil {
|
|
|
|
|
logx.WithContext(ctx).Errorf("[xpay push] 订单不存在 order_no=%s err=%v", orderNo, findErr)
|
|
|
|
|
l.writePushResp(w, 1, "order not found")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wxOrderID := notify.WeChatPayInfo.TransactionId
|
|
|
|
|
credited, fulfillErr := fulfillQueryOrderPaid(ctx, l.svcCtx, order, wxOrderID, notify.GoodsInfo.ActualPrice)
|
|
|
|
|
if fulfillErr != nil {
|
|
|
|
|
logx.WithContext(ctx).Errorf("[xpay push] 到账失败 order_no=%s err=%v", orderNo, fulfillErr)
|
|
|
|
|
l.writePushResp(w, 1, fulfillErr.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ = l.svcCtx.XpayService.MarkNotified(ctx, orderNo)
|
|
|
|
|
logx.WithContext(ctx).Infof("[xpay push] event=xpay_goods_deliver_notify order_no=%s credited=%v", orderNo, credited)
|
|
|
|
|
l.writePushResp(w, 0, "success")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *XpayPushLogic) writePushResp(w http.ResponseWriter, errCode int, errMsg string) {
|
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
_ = json.NewEncoder(w).Encode(map[string]interface{}{
|
|
|
|
|
"ErrCode": errCode,
|
|
|
|
|
"ErrMsg": errMsg,
|
|
|
|
|
})
|
|
|
|
|
}
|