优化交易状态检查逻辑

This commit is contained in:
2025-06-24 11:36:27 +08:00
parent 2fd17dde22
commit 065a7c77c3
10 changed files with 218 additions and 283 deletions

View File

@@ -146,12 +146,22 @@ func (s *tradeService) CreateTrade(q *q.Query, uid int32, now time.Time, data *T
payUrl = *resp.CodeUrl
// 商福通 + 电脑网站
case method == trade2.MethodSft && platform == trade2.PlatformDesktop:
case (method == trade2.MethodSftAlipay || method == trade2.MethodSftWeChat) && platform == trade2.PlatformDesktop:
var payType g.SftPayType
switch method {
case trade2.MethodSftAlipay:
payType = g.SftAlipay
case trade2.MethodSftWeChat:
payType = g.SftWeChat
default:
panic("unhandled default case")
}
resp, err := g.SFTPay.PaymentScanPay(&g.PaymentScanPayReq{
MchOrderNo: tradeNo,
Subject: subject,
Body: subject,
Amount: amountReal.Mul(decimal.NewFromInt(100)).Round(0).IntPart(),
PayType: payType,
Currency: "cny",
ClientIp: "123.52.74.23",
OrderTimeout: u.P(expire.Format("2006-01-02 15:04:05")),
@@ -164,10 +174,13 @@ func (s *tradeService) CreateTrade(q *q.Query, uid int32, now time.Time, data *T
// 商福通 + 手机网站
case (method == trade2.MethodSftAlipay || method == trade2.MethodSftWeChat) && platform == trade2.PlatformMobile:
var payType g.SftPayType
if method == trade2.MethodSftAlipay {
switch method {
case trade2.MethodSftAlipay:
payType = g.SftAlipay
} else {
case trade2.MethodSftWeChat:
payType = g.SftWeChat
default:
panic("unhandled default case")
}
resp, err := g.SFTPay.PaymentH5Pay(&g.PaymentH5PayReq{
MchOrderNo: tradeNo,
@@ -266,9 +279,11 @@ func (s *tradeService) OnTradeCreated(q *q.Query, data *OnTradeCreateData) (*m.T
// 检查交易状态
switch trade2.Status(trade.Status) {
// 如果已退款或取消,则返回错误
case trade2.StatusCanceled, trade2.StatusRefunded:
return nil, errors.New("交易已取消或已退款")
case trade2.StatusCanceled:
return nil, core.NewBizErr("交易已取消")
case trade2.StatusSuccess:
return nil, core.NewBizErr("交易已完成")
// 如果是未支付,则更新支付状态
case trade2.StatusPending:
@@ -284,7 +299,6 @@ func (s *tradeService) OnTradeCreated(q *q.Query, data *OnTradeCreateData) (*m.T
if err != nil {
return nil, err
}
case trade2.StatusSuccess:
}
return trade, nil
@@ -320,7 +334,7 @@ func (s *tradeService) CancelTrade(tradeNo string, method trade2.Method) error {
return errors.New("交易取消失败")
}
case trade2.MethodSft:
case trade2.MethodSft, trade2.MethodSftAlipay, trade2.MethodSftWeChat:
resp, err := g.SFTPay.OrderClose(&g.OrderCloseReq{
MchOrderNo: &tradeNo,
})
@@ -361,18 +375,18 @@ func (s *tradeService) OnTradeRefunded(q *q.Query, tradeNo string, now time.Time
panic("todo")
}
func (s *tradeService) VerifyTrade(data *TradeVerifyData) (*TradeSuccessResult, error) {
func (s *tradeService) CheckTrade(data *CheckTradeData) (*CheckTradeResult, error) {
var tradeNo = data.TradeNo
var method = data.Method
// 检查交易号是否存在
var transId string
var paidAt time.Time
var payment decimal.Decimal
var result = new(CheckTradeResult)
switch method {
// 检查支付宝交易
// 支付宝
case trade2.MethodAlipay:
// 查询交易状态
resp, err := g.Alipay.TradeQuery(context.Background(), alipay.TradeQuery{
OutTradeNo: tradeNo,
})
@@ -383,22 +397,34 @@ func (s *tradeService) VerifyTrade(data *TradeVerifyData) (*TradeSuccessResult,
slog.Warn("支付宝交易查询失败", "code", resp.Code, "sub_code", resp.SubCode, "msg", resp.Msg)
return nil, errors.New("交易查询失败")
}
if resp.TradeStatus != alipay.TradeStatusSuccess {
return nil, ErrTransactionNotPaid
// 填充返回值
result.TransId = resp.TradeNo
switch resp.TradeStatus {
case alipay.TradeStatusWaitBuyerPay:
result.Status = trade2.StatusPending
case alipay.TradeStatusClosed:
result.Status = trade2.StatusCanceled
case alipay.TradeStatusSuccess, alipay.TradeStatusFinished:
result.Status = trade2.StatusSuccess
result.Success.Acquirer = trade2.AcquirerAlipay
result.Success.Payment, err = decimal.NewFromString(resp.TotalAmount)
if err != nil {
return nil, err
}
result.Success.Time, err = time.Parse("2006-01-02 15:04:05", resp.SendPayDate)
if err != nil {
return nil, err
}
}
transId = resp.TradeNo
payment, err = decimal.NewFromString(resp.TotalAmount)
if err != nil {
return nil, err
}
paidAt, err = time.Parse("2006-01-02 15:04:05", resp.SendPayDate)
if err != nil {
return nil, err
}
// 检查微信交易
// 微信
case trade2.MethodWeChat:
// 查询交易状态
resp, _, err := g.WechatPay.Native.QueryOrderByOutTradeNo(context.Background(), native.QueryOrderByOutTradeNoRequest{
OutTradeNo: &tradeNo,
Mchid: &env.WechatPayMchId,
@@ -407,51 +433,76 @@ func (s *tradeService) VerifyTrade(data *TradeVerifyData) (*TradeSuccessResult,
var apiErr *wecahtpaycore.APIError
if errors.As(err, &apiErr) {
if apiErr.Code == "ORDER_NOT_EXIST" {
return nil, ErrTransactionNotPaid
return nil, core.NewBizErr("订单不存在")
}
return nil, core.NewServErr(
fmt.Sprintf("微信上游接口异常code=%vmessage=%v", apiErr.Code, apiErr.Message),
apiErr,
)
}
return nil, err
}
if *resp.TradeState != "SUCCESS" {
return nil, core.NewServErr(
fmt.Sprintf("预期之外的支付未完成state=%v, stateDesc=%v", resp.TradeState, resp.TradeStateDesc),
)
return nil, core.NewServErr(fmt.Sprintf("微信上游支付接口异常:%s", err.Error()))
}
transId = *resp.TransactionId
payment = decimal.NewFromInt(*resp.Amount.PayerTotal).Div(decimal.NewFromInt(100))
paidAt, err = time.Parse(time.RFC3339, *resp.SuccessTime)
if err != nil {
return nil, err
// 填充返回值
result.TransId = *resp.TransactionId
switch *resp.TradeState {
case "NOTPAY":
result.Status = trade2.StatusPending
case "CLOSED":
result.Status = trade2.StatusCanceled
case "SUCCESS", "REFUND":
result.Status = trade2.StatusSuccess
result.Success.Acquirer = trade2.AcquirerWeChat
result.Success.Payment = decimal.NewFromInt(*resp.Amount.PayerTotal).Div(decimal.NewFromInt(100))
result.Success.Time, err = time.Parse(time.RFC3339, *resp.SuccessTime)
if err != nil {
return nil, err
}
}
// 检查商福通交易
// 商福通
case trade2.MethodSft, trade2.MethodSftAlipay, trade2.MethodSftWeChat:
// 查询交易状态
resp, err := g.SFTPay.QueryTrade(&g.QueryTradeReq{
MchOrderNo: &tradeNo,
})
if err != nil {
return nil, err
}
if resp.State != g.SftTradeSuccess {
return nil, ErrTransactionNotPaid
}
if resp.PayOrderId == nil {
return nil, errors.New("商福通交易号不存在")
}
if resp.PayTime == nil {
return nil, errors.New("商福通交易时间不存在")
}
transId = *resp.PayOrderId
payment = decimal.NewFromInt(resp.Amount).Div(decimal.NewFromInt(100))
paidAt, err = time.Parse("2006-01-02 15:04:05", *resp.PayTime)
if err != nil {
return nil, err
// 填充返回值
result.TransId = *resp.PayOrderId
switch resp.State {
case g.SftInit, g.SftTradeAwait, g.SftTradeFail:
result.Status = trade2.StatusPending
case g.SftTradeClosed, g.SftTradeCancel:
result.Status = trade2.StatusCanceled
case g.SftTradeSuccess, g.SftTradeRefund, g.SftRefundIng:
result.Status = trade2.StatusSuccess
switch resp.PayType {
case "WECHAT":
result.Success.Acquirer = trade2.AcquirerWeChat
case "ALIPAY":
result.Success.Acquirer = trade2.AcquirerAlipay
case "UNIONPAY":
result.Success.Acquirer = trade2.AcquirerUnionPay
}
result.Success.Payment = decimal.NewFromInt(resp.Amount).Div(decimal.NewFromInt(100))
result.Success.Time, err = time.Parse("2006-01-02 15:04:05", *resp.PayTime)
if err != nil {
return nil, err
}
}
// 不支持的支付方式
@@ -459,11 +510,47 @@ func (s *tradeService) VerifyTrade(data *TradeVerifyData) (*TradeSuccessResult,
return nil, ErrTransactionNotSupported
}
return &TradeSuccessResult{
TransId: transId,
Payment: payment,
Time: paidAt,
}, nil
return result, nil
}
func (s *tradeService) CheckTradeIfCreated(data *CheckTradeData) (*TradeSuccessResult, error) {
rs, err := Trade.CheckTrade(&CheckTradeData{
TradeNo: data.TradeNo,
Method: data.Method,
})
if err != nil {
return nil, err
}
switch rs.Status {
case trade2.StatusPending:
return nil, core.NewBizErr("订单未支付")
case trade2.StatusCanceled:
return nil, core.NewBizErr("订单已关闭")
case trade2.StatusSuccess:
// pass
}
return rs.Success, nil
}
func (s *tradeService) CheckTradeIfCanceled(data *CheckTradeData) error {
rs, err := Trade.CheckTrade(&CheckTradeData{
TradeNo: data.TradeNo,
Method: data.Method,
})
if err != nil {
return err
}
switch rs.Status {
case trade2.StatusPending:
return core.NewBizErr("订单未支付")
case trade2.StatusSuccess:
return core.NewBizErr("订单已关闭")
case trade2.StatusCanceled:
// pass
}
return nil
}
type TradeCreateData struct {
@@ -483,16 +570,22 @@ type TradeCreateResult struct {
Trade *m.Trade
}
type TradeVerifyData struct {
type CheckTradeData struct {
TradeNo string
Method trade2.Method
}
type CheckTradeResult struct {
TransId string
Status trade2.Status
Success *TradeSuccessResult
}
type TradeSuccessResult struct {
TransId string
Acquirer trade2.Acquirer
Payment decimal.Decimal
Time time.Time
Acquirer trade2.Acquirer
}
type OnTradeCreateData struct {
@@ -507,6 +600,5 @@ func (e TradeErr) Error() string {
}
var (
ErrTransactionNotPaid = core.NewBizErr("交易未支付")
ErrTransactionNotSupported = core.NewBizErr("不支持的支付方式")
)