完善支付流程,实现异步事件
This commit is contained in:
@@ -233,7 +233,7 @@ type QueryTradeResp struct {
|
||||
RefundState int32 `json:"refundState"`
|
||||
DrType *string `json:"drType"`
|
||||
ExtParam *string `json:"extParam"`
|
||||
PayTime *int64 `json:"payTime"`
|
||||
PayTime *string `json:"payTime"`
|
||||
Subject string `json:"subject"`
|
||||
TradeFee *int64 `json:"tradeFee"`
|
||||
CashFee *int64 `json:"cashFee"`
|
||||
@@ -443,3 +443,11 @@ const (
|
||||
SftRefundIng SftTradeState = "REFUND_ING"
|
||||
SftTradeClosed SftTradeState = "TRADE_CLOSED"
|
||||
)
|
||||
|
||||
type SftNotifyType string
|
||||
|
||||
var (
|
||||
SftNotifyTypeTrade = SftNotifyType("sft.trade.notify")
|
||||
SftNotifyTypeRefund = SftNotifyType("sft.refund.notify")
|
||||
SftNotifyTypeDivision = SftNotifyType("sft.division.notify")
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
"platform/web/auth"
|
||||
"platform/web/core"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// PageTradeByAdmin 分页查询所有订单
|
||||
@@ -429,3 +431,99 @@ func TradeCheck(c *fiber.Ctx) error {
|
||||
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
||||
// 交易回调
|
||||
func TradeCallbackSft(c *fiber.Ctx) error {
|
||||
|
||||
// 解析请求参数
|
||||
var req TradeCallbackSftReq
|
||||
if err := g.Validator.ParseBody(c, &req); err != nil {
|
||||
return core.NewServErr("解析请求失败", err)
|
||||
}
|
||||
|
||||
var bizData TradeCallbackSftReqBizData
|
||||
if err := json.Unmarshal([]byte(*req.BizData), &bizData); err != nil {
|
||||
return core.NewServErr("解析业务数据失败", err)
|
||||
}
|
||||
|
||||
// 检查通知
|
||||
if bizData.MsgType != string(g.SftNotifyTypeTrade) {
|
||||
return core.NewBizErr("消息类型处理异常")
|
||||
}
|
||||
|
||||
if bizData.State != string(g.SftTradeSuccess) {
|
||||
return core.NewBizErr("订单状态处理异常")
|
||||
}
|
||||
|
||||
// 更新订单状态
|
||||
|
||||
if bizData.PayType == nil {
|
||||
return core.NewBizErr("支付渠道解析错误")
|
||||
}
|
||||
|
||||
var acquirer m.TradeAcquirer
|
||||
switch *bizData.PayType {
|
||||
case string(g.SftAlipay):
|
||||
acquirer = m.TradeAcquirerAlipay
|
||||
case string(g.SftWeChat):
|
||||
acquirer = m.TradeAcquirerWechat
|
||||
case string(g.SftUnionPay):
|
||||
acquirer = m.TradeAcquirerUnionPay
|
||||
default:
|
||||
return core.NewBizErr("支付渠道类型异常")
|
||||
}
|
||||
|
||||
var time, err = time.Parse("2006-01-02 15:04:05", *bizData.PayTime)
|
||||
if err != nil {
|
||||
return core.NewBizErr("时间解析错误")
|
||||
}
|
||||
|
||||
err = s.Trade.CompleteTradeByNotify(bizData.MchOrderNo, bizData.PayOrderId, &s.TradeSuccessResult{
|
||||
Acquirer: acquirer,
|
||||
Actual: decimal.NewFromInt(bizData.Amount).Div(decimal.NewFromInt(100)),
|
||||
Time: time,
|
||||
})
|
||||
if err != nil {
|
||||
return core.NewServErr("完成交易失败", err)
|
||||
}
|
||||
|
||||
return c.Send([]byte("SUCCESS"))
|
||||
}
|
||||
|
||||
type TradeCallbackSftReq struct {
|
||||
Code string `json:"code"`
|
||||
Msg *string `json:"msg"`
|
||||
Sign *string `json:"sign"`
|
||||
BizData *string `json:"bizData"`
|
||||
SignType *string `json:"signType"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
type TradeCallbackSftReqBizData struct {
|
||||
MsgType string `json:"msgType"`
|
||||
PayOrderId string `json:"payOrderId"`
|
||||
State string `json:"state"`
|
||||
MercNo string `json:"mercNo"`
|
||||
StoreId string `json:"storeId"`
|
||||
MchOrderNo string `json:"mchOrderNo"`
|
||||
IfCode string `json:"ifCode"`
|
||||
Amount int64 `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
ChannelTradeNo *string `json:"channelTradeNo"`
|
||||
ChannelSendNo *string `json:"channelSendNo"`
|
||||
UserId *string `json:"userId"`
|
||||
ExtParam *string `json:"extParam"`
|
||||
PayTime *string `json:"payTime"`
|
||||
Note *string `json:"note"`
|
||||
PayType *string `json:"payType"`
|
||||
DrType *string `json:"drType"`
|
||||
TradeFee *int64 `json:"tradeFee"`
|
||||
CashFee *int64 `json:"cashFee"`
|
||||
RefundAmt *int64 `json:"refundAmt"`
|
||||
RefundState *int32 `json:"refundState"`
|
||||
SettlementType *string `json:"settlementType"`
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ func ApplyMiddlewares(app *fiber.App) {
|
||||
|
||||
// logger
|
||||
app.Use(logger.New(logger.Config{
|
||||
TimeFormat: "2006-01-02 15:04:05",
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.Path() == "/favicon.ico"
|
||||
},
|
||||
|
||||
@@ -23,6 +23,7 @@ func ApplyRouters(app *fiber.App) {
|
||||
// 回调
|
||||
callbacks := app.Group("/callback")
|
||||
callbacks.Get("/identify", handlers.IdentifyCallbackNew)
|
||||
callbacks.All("/trade/sft", handlers.TradeCallbackSft)
|
||||
|
||||
// 临时
|
||||
if env.RunMode == env.RunModeDev {
|
||||
|
||||
@@ -146,6 +146,7 @@ func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productD
|
||||
Currency: "cny",
|
||||
ClientIp: "123.52.74.23",
|
||||
OrderTimeout: u.P(expireAt.Format("2006-01-02 15:04:05")),
|
||||
NotifyUrl: &env.SftNotifyUrl,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -238,23 +239,47 @@ func (s *tradeService) CompleteTrade(user *m.User, ref *TradeRef) error {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取交易信息
|
||||
trade, err := q.Trade.
|
||||
Preload(q.Trade.User).
|
||||
Where(q.Trade.InnerNo.Eq(ref.TradeNo)).
|
||||
Take()
|
||||
if err != nil {
|
||||
return core.NewBizErr("获取交易信息失败", err)
|
||||
}
|
||||
if trade.User == nil || trade.User.ID != user.ID {
|
||||
return core.NewBizErr("交易信息不存在")
|
||||
}
|
||||
|
||||
// 更新交易状态
|
||||
err = s.OnCompleteTrade(user, ref.TradeNo, result.TransId, &result.Success)
|
||||
err = s.OnCompleteTrade(trade, ref.TradeNo, result.TransId, &result.Success)
|
||||
if err != nil {
|
||||
return core.NewServErr("处理交易失败", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo string, result *TradeSuccessResult) error {
|
||||
|
||||
// 获取交易信息
|
||||
func (s *tradeService) CompleteTradeByNotify(interNo string, outerNo string, result *TradeSuccessResult) error {
|
||||
trade, err := q.Trade.
|
||||
Preload(q.Trade.User).
|
||||
Where(q.Trade.InnerNo.Eq(interNo)).
|
||||
Take()
|
||||
if err != nil {
|
||||
return core.NewBizErr("获取交易信息失败", err)
|
||||
}
|
||||
if trade.User == nil {
|
||||
return core.NewBizErr("交易信息不存在")
|
||||
}
|
||||
|
||||
err = s.OnCompleteTrade(trade, interNo, outerNo, result)
|
||||
if err != nil {
|
||||
return core.NewServErr("处理交易失败", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (s *tradeService) OnCompleteTrade(trade *m.Trade, interNo string, outerNo string, result *TradeSuccessResult) error {
|
||||
user := trade.User
|
||||
|
||||
// 检查交易状态
|
||||
switch trade.Status {
|
||||
@@ -646,7 +671,10 @@ func (s *tradeService) CheckTrade(ref *TradeRef) (*CheckTradeResult, error) {
|
||||
result.Success.Acquirer = m.TradeAcquirerUnionPay
|
||||
}
|
||||
result.Success.Actual = decimal.NewFromInt(resp.Amount).Div(decimal.NewFromInt(100))
|
||||
result.Success.Time = time.UnixMilli(*resp.PayTime)
|
||||
result.Success.Time, err = time.Parse("2006-01-02 15:04:05", *resp.PayTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 不支持的支付方式
|
||||
|
||||
Reference in New Issue
Block a user