优化表结构,重构模型,重新实现基于白银网关的提取节点流程

This commit is contained in:
2025-11-24 18:44:06 +08:00
parent 9a574f55cb
commit cb2a963a37
142 changed files with 6528 additions and 5808 deletions

View File

@@ -10,11 +10,8 @@ import (
"platform/pkg/env"
"platform/pkg/u"
"platform/web/core"
coupon2 "platform/web/domains/coupon"
trade2 "platform/web/domains/trade"
e "platform/web/events"
g "platform/web/globals"
"platform/web/globals/orm"
m "platform/web/models"
q "platform/web/queries"
"time"
@@ -53,7 +50,7 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
coupon, err := q.Coupon.
Where(
q.Coupon.Code.Eq(*data.CouponCode),
q.Coupon.Status.Eq(int32(coupon2.StatusUnused)),
q.Coupon.Status.Eq(int(m.CouponStatusUnused)),
).
Take()
if err != nil {
@@ -67,7 +64,7 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
if !expireAt.IsZero() && expireAt.Before(now) {
_, err = q.Coupon.
Where(q.Coupon.ID.Eq(coupon.ID)).
Update(q.Coupon.Status, coupon2.StatusExpired)
Update(q.Coupon.Status, m.CouponStatusExpired)
if err != nil {
return nil, err
}
@@ -86,7 +83,7 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
if expireAt.IsZero() {
_, err = q.Coupon.
Where(q.Coupon.ID.Eq(coupon.ID)).
Update(q.Coupon.Status, int32(coupon2.StatusUsed))
Update(q.Coupon.Status, int(m.CouponStatusUsed))
if err != nil {
return nil, err
}
@@ -112,7 +109,7 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
switch {
// 支付宝 + 电脑网站
case method == trade2.MethodAlipay && platform == trade2.PlatformDesktop:
case method == m.TradeMethodAlipay && platform == m.TradePlatformPC:
resp, err := g.Alipay.TradePagePay(alipay.TradePagePay{
QRPayMode: "4",
QRCodeWidth: "196", // 二维码宽度需要-4支付宝页面布局有问题
@@ -130,7 +127,7 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
paymentUrl = resp.String()
// 微信 + 电脑网站
case method == trade2.MethodWeChat && platform == trade2.PlatformDesktop:
case method == m.TradeMethodWechat && platform == m.TradePlatformPC:
resp, _, err := g.WechatPay.Native.Prepay(context.Background(), native.PrepayRequest{
Appid: &env.WechatPayAppId,
Mchid: &env.WechatPayMchId,
@@ -149,14 +146,14 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
// 商福通 + 电脑网站
case
method == trade2.MethodSftAlipay && platform == trade2.PlatformDesktop,
method == trade2.MethodSftWeChat && platform == trade2.PlatformDesktop:
method == m.TradeMethodSftAlipay && platform == m.TradePlatformPC,
method == m.TradeMethodSftWechat && platform == m.TradePlatformPC:
var payType g.SftPayType
switch method {
case trade2.MethodSftAlipay:
case m.TradeMethodSftAlipay:
payType = g.SftAlipay
case trade2.MethodSftWeChat:
case m.TradeMethodSftWechat:
payType = g.SftWeChat
default:
panic("unhandled default case")
@@ -178,13 +175,13 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
// 商福通 + 手机网站
case
method == trade2.MethodSftAlipay && platform == trade2.PlatformMobile,
method == trade2.MethodSftWeChat && platform == trade2.PlatformMobile:
method == m.TradeMethodSftAlipay && platform == m.TradePlatformMobile,
method == m.TradeMethodSftWechat && platform == m.TradePlatformMobile:
var payType g.SftPayType
switch method {
case trade2.MethodSftAlipay:
case m.TradeMethodSftAlipay:
payType = g.SftAlipay
case trade2.MethodSftWeChat:
case m.TradeMethodSftWechat:
payType = g.SftWeChat
default:
panic("unhandled default case")
@@ -214,11 +211,11 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
err = q.Trade.Create(&m.Trade{
UserID: uid,
InnerNo: tradeNo,
Type: int32(tType),
Type: tType,
Subject: subject,
Amount: amount,
Method: int32(method),
Platform: int32(platform),
Method: method,
Platform: platform,
PaymentURL: &paymentUrl,
})
if err != nil {
@@ -266,11 +263,11 @@ func (s *tradeService) CompleteTrade(data *ModifyTradeData) error {
if err != nil {
return core.NewServErr("检查订单状态失败", err)
}
if result.Status != trade2.StatusSuccess {
if result.Status != m.TradeStatusSuccess {
switch result.Status {
case trade2.StatusPending:
case m.TradeStatusPending:
return core.NewBizErr("订单未支付")
case trade2.StatusCanceled:
case m.TradeStatusCanceled:
return core.NewBizErr("订单已过期")
}
}
@@ -331,22 +328,22 @@ func completeTrade(data *OnTradeCompletedData) (*m.Trade, error) {
}
// 检查交易状态
switch trade2.Status(trade.Status) {
case trade2.StatusCanceled:
switch trade.Status {
case m.TradeStatusCanceled:
return core.NewBizErr("交易已取消")
case trade2.StatusSuccess:
case m.TradeStatusSuccess:
return nil // 跳过更新交易信息
case trade2.StatusPending:
case m.TradeStatusPending:
}
// 更新交易信息
trade.Status = int32(trade2.StatusSuccess)
trade.Status = m.TradeStatusSuccess
trade.OuterNo = &transId
trade.Payment = payment
trade.Acquirer = u.P(int32(acquirer))
trade.CompletedAt = u.P(orm.LocalDateTime(paidAt))
trade.Acquirer = u.P(acquirer)
trade.CompletedAt = u.P(paidAt)
rs, err := q.Trade.
Where(q.Trade.InnerNo.Eq(tradeNo), q.Trade.Status.Eq(int32(trade2.StatusPending))).
Where(q.Trade.InnerNo.Eq(tradeNo), q.Trade.Status.Eq(int(m.TradeStatusPending))).
Updates(trade)
if rs.RowsAffected == 0 {
return core.NewBizErr("交易状态已发生变化")
@@ -372,13 +369,13 @@ func afterTradeComplete(trade *m.Trade) error {
}
// 执行资源创建
var ComplementEvents = []trade2.CompleteEvent{
var ComplementEvents = []CompleteEvent{
ResourceOnTradeComplete{},
UserOnTradeComplete{},
}
for _, event := range ComplementEvents {
info, ok := event.Check(trade2.Type(trade.Type))
info, ok := event.Check(trade.Type)
if !ok {
continue
}
@@ -405,7 +402,7 @@ func (s *tradeService) CancelTrade(data *ModifyTradeData, now time.Time) error {
return g.Redsync.WithLock(tradeLockKey(tradeNo), func() error {
switch method {
case trade2.MethodAlipay:
case m.TradeMethodAlipay:
resp, err := g.Alipay.TradeCancel(context.Background(), alipay.TradeCancel{
OutTradeNo: tradeNo,
})
@@ -417,7 +414,7 @@ func (s *tradeService) CancelTrade(data *ModifyTradeData, now time.Time) error {
return errors.New("上游取消交易失败")
}
case trade2.MethodWeChat:
case m.TradeMethodWechat:
resp, err := g.WechatPay.Native.CloseOrder(context.Background(), native.CloseOrderRequest{
Mchid: &env.WechatPayMchId,
OutTradeNo: &tradeNo,
@@ -435,7 +432,7 @@ func (s *tradeService) CancelTrade(data *ModifyTradeData, now time.Time) error {
return errors.New("上游取消交易失败")
}
case trade2.MethodSft, trade2.MethodSftAlipay, trade2.MethodSftWeChat:
case m.TradeMethodSft, m.TradeMethodSftAlipay, m.TradeMethodSftWechat:
_, err := g.SFTPay.OrderClose(&g.OrderCloseReq{
MchOrderNo: &tradeNo,
})
@@ -468,7 +465,7 @@ func (s *tradeService) OnTradeCanceled(tradeNo string, now time.Time) error {
func cancelTrade(tradeNo string, now time.Time) error {
return q.Q.Transaction(func(q *q.Query) error {
// 获取交易信息
var status trade2.Status
var status m.TradeStatus
err := q.Trade.
Where(q.Trade.InnerNo.Eq(tradeNo)).
Select(q.Trade.Status).
@@ -479,19 +476,19 @@ func cancelTrade(tradeNo string, now time.Time) error {
// 检查交易状态
switch status {
case trade2.StatusCanceled:
case m.TradeStatusCanceled:
return core.NewBizErr("交易已取消")
case trade2.StatusSuccess:
case m.TradeStatusSuccess:
return core.NewBizErr("交易已完成")
case trade2.StatusPending:
case m.TradeStatusPending:
}
// 更新交易状态
_, err = q.Trade.
Where(q.Trade.InnerNo.Eq(tradeNo)).
UpdateSimple(
q.Trade.Status.Value(int32(trade2.StatusCanceled)),
q.Trade.CanceledAt.Value(orm.LocalDateTime(now)),
q.Trade.Status.Value(int(m.TradeStatusCanceled)),
q.Trade.CanceledAt.Value(now),
)
if err != nil {
return core.NewServErr("更新交易状态失败", err)
@@ -518,7 +515,7 @@ func (s *tradeService) CheckTrade(data *ModifyTradeData) (*CheckTradeResult, err
switch method {
// 支付宝
case trade2.MethodAlipay:
case m.TradeMethodAlipay:
// 查询交易状态
resp, err := g.Alipay.TradeQuery(context.Background(), alipay.TradeQuery{
@@ -537,15 +534,15 @@ func (s *tradeService) CheckTrade(data *ModifyTradeData) (*CheckTradeResult, err
switch resp.TradeStatus {
case alipay.TradeStatusWaitBuyerPay:
result.Status = trade2.StatusPending
result.Status = m.TradeStatusPending
case alipay.TradeStatusClosed:
result.Status = trade2.StatusCanceled
result.Status = m.TradeStatusCanceled
case alipay.TradeStatusSuccess, alipay.TradeStatusFinished:
result.Status = trade2.StatusSuccess
result.Status = m.TradeStatusSuccess
result.Success = &TradeSuccessResult{}
result.Success.Acquirer = trade2.AcquirerAlipay
result.Success.Acquirer = m.TradeAcquirerAlipay
result.Success.Payment, err = decimal.NewFromString(resp.TotalAmount)
if err != nil {
return nil, err
@@ -557,7 +554,7 @@ func (s *tradeService) CheckTrade(data *ModifyTradeData) (*CheckTradeResult, err
}
// 微信
case trade2.MethodWeChat:
case m.TradeMethodWechat:
// 查询交易状态
resp, _, err := g.WechatPay.Native.QueryOrderByOutTradeNo(context.Background(), native.QueryOrderByOutTradeNoRequest{
@@ -583,15 +580,15 @@ func (s *tradeService) CheckTrade(data *ModifyTradeData) (*CheckTradeResult, err
switch *resp.TradeState {
case "NOTPAY":
result.Status = trade2.StatusPending
result.Status = m.TradeStatusPending
case "CLOSED":
result.Status = trade2.StatusCanceled
result.Status = m.TradeStatusCanceled
case "SUCCESS", "REFUND":
result.Status = trade2.StatusSuccess
result.Status = m.TradeStatusSuccess
result.Success = &TradeSuccessResult{}
result.Success.Acquirer = trade2.AcquirerWeChat
result.Success.Acquirer = m.TradeAcquirerWechat
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 {
@@ -600,7 +597,7 @@ func (s *tradeService) CheckTrade(data *ModifyTradeData) (*CheckTradeResult, err
}
// 商福通
case trade2.MethodSft, trade2.MethodSftAlipay, trade2.MethodSftWeChat:
case m.TradeMethodSft, m.TradeMethodSftAlipay, m.TradeMethodSftWechat:
// 查询交易状态
resp, err := g.SFTPay.QueryTrade(&g.QueryTradeReq{
@@ -619,21 +616,21 @@ func (s *tradeService) CheckTrade(data *ModifyTradeData) (*CheckTradeResult, err
switch resp.State {
case g.SftInit, g.SftTradeAwait, g.SftTradeFail:
result.Status = trade2.StatusPending
result.Status = m.TradeStatusPending
case g.SftTradeClosed, g.SftTradeCancel:
result.Status = trade2.StatusCanceled
result.Status = m.TradeStatusCanceled
case g.SftTradeSuccess, g.SftTradeRefund, g.SftRefundIng:
result.Status = trade2.StatusSuccess
result.Status = m.TradeStatusSuccess
result.Success = &TradeSuccessResult{}
switch resp.PayType {
case "WECHAT":
result.Success.Acquirer = trade2.AcquirerWeChat
result.Success.Acquirer = m.TradeAcquirerWechat
case "ALIPAY":
result.Success.Acquirer = trade2.AcquirerAlipay
result.Success.Acquirer = m.TradeAcquirerAlipay
case "UNIONPAY":
result.Success.Acquirer = trade2.AcquirerUnionPay
result.Success.Acquirer = m.TradeAcquirerUnionPay
}
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)
@@ -659,10 +656,10 @@ func tradeLockKey(no string) string {
}
type CreateTradeData struct {
Platform trade2.Platform `json:"platform" validate:"required"`
Method trade2.Method `json:"method" validate:"required"`
Platform m.TradePlatform `json:"platform" validate:"required"`
Method m.TradeMethod `json:"method" validate:"required"`
CouponCode *string `json:"coupon_code"`
Product trade2.ProductInfo
Product ProductInfo
}
type CreateTradeResult struct {
@@ -672,17 +669,17 @@ type CreateTradeResult struct {
type ModifyTradeData struct {
TradeNo string `json:"trade_no" validate:"required"`
Method trade2.Method `json:"method" validate:"required"`
Method m.TradeMethod `json:"method" validate:"required"`
}
type CheckTradeResult struct {
TransId string
Status trade2.Status
Status m.TradeStatus
Success *TradeSuccessResult
}
type TradeSuccessResult struct {
Acquirer trade2.Acquirer
Acquirer m.TradeAcquirer
Payment decimal.Decimal
Time time.Time
}
@@ -693,6 +690,19 @@ type OnTradeCompletedData struct {
*TradeSuccessResult
}
type ProductInfo interface {
GetType() m.TradeType
GetSubject() string
GetAmount() decimal.Decimal
Serialize() (string, error)
Deserialize(str string) error
}
type CompleteEvent interface {
Check(t m.TradeType) (ProductInfo, bool)
OnTradeComplete(info ProductInfo, trade *m.Trade) error
}
type TradeErr string
func (e TradeErr) Error() string {