diff --git a/pkg/env/env.go b/pkg/env/env.go index 34bd3b4..a4ec8ad 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -148,8 +148,7 @@ func loadRedis() { // region log var ( - LogLevel = slog.LevelDebug - LogHttpDump = false // 是否打印HTTP请求和响应的原始数据 + LogLevel = slog.LevelDebug ) func loadLog() { @@ -164,17 +163,6 @@ func loadLog() { case "error": LogLevel = slog.LevelError } - - _LogHttpDump := os.Getenv("LOG_HTTP_DUMP") - if _LogHttpDump != "" { - value, err := strconv.ParseBool(_LogHttpDump) - if err != nil { - panic("环境变量 LOG_HTTP_DUMP 的值不是布尔值") - } - LogHttpDump = value - } else { - LogHttpDump = false // 默认不打印HTTP请求和响应的原始数据 - } } // endregion diff --git a/scripts/sql/init.sql b/scripts/sql/init.sql index 3ff4ca3..c44f237 100644 --- a/scripts/sql/init.sql +++ b/scripts/sql/init.sql @@ -910,7 +910,7 @@ comment on column trade.payment is '支付金额'; comment on column trade.method is '支付方式:1-支付宝,2-微信,3-商福通渠道支付宝,4-商福通渠道微信'; comment on column trade.platform is '支付平台:1-电脑网站,2-手机网站'; comment on column trade.acquirer is '收单机构:1-支付宝,2-微信,3-银联'; -comment on column trade.status is '订单状态:0-待支付,1-已支付,2-已取消,3-已退款'; +comment on column trade.status is '订单状态:0-待支付,1-已支付,2-已取消'; comment on column trade.pay_url is '支付链接'; comment on column trade.paid_at is '支付时间'; comment on column trade.cancel_at is '取消时间'; diff --git a/web/domains/trade/types.go b/web/domains/trade/types.go index decbd24..3771972 100644 --- a/web/domains/trade/types.go +++ b/web/domains/trade/types.go @@ -38,5 +38,4 @@ const ( StatusPending Status = iota // 待支付 StatusSuccess // 已支付 StatusCanceled // 已取消 - StatusRefunded ) // 已退款 diff --git a/web/globals/shangfutong.go b/web/globals/shangfutong.go index 79eb712..123d23d 100644 --- a/web/globals/shangfutong.go +++ b/web/globals/shangfutong.go @@ -107,23 +107,24 @@ func (s *SftClient) QueryTrade(req *QueryTradeReq) (*QueryTradeResp, error) { } type PaymentScanPayReq struct { - Subject string `json:"subject"` - Body string `json:"body"` - Amount int64 `json:"amount"` - Currency string `json:"currency"` - ClientIp string `json:"clientIp"` - MchOrderNo string `json:"mchOrderNo"` - StoreId *string `json:"storeId,omitempty"` - RouteNo *string `json:"routeNo,omitempty"` - HbFqNum *int `json:"hbFqNum,omitempty"` - HbFqPercent *int `json:"hbFqPercent,omitempty"` - BuyerRemark *string `json:"buyerRemark,omitempty"` - NotifyUrl *string `json:"notifyUrl,omitempty"` - ReturnUrl *string `json:"returnUrl,omitempty"` - ExpiredTime *int `json:"expiredTime,omitempty"` - OrderTimeout *string `json:"orderTimeout,omitempty"` - ExtParam *string `json:"extParam,omitempty"` - LimitPay *int `json:"limitPay,omitempty"` + Subject string `json:"subject"` + Body string `json:"body"` + Amount int64 `json:"amount"` + Currency string `json:"currency"` + PayType SftPayType `json:"payType"` + ClientIp string `json:"clientIp"` + MchOrderNo string `json:"mchOrderNo"` + StoreId *string `json:"storeId,omitempty"` + RouteNo *string `json:"routeNo,omitempty"` + HbFqNum *int `json:"hbFqNum,omitempty"` + HbFqPercent *int `json:"hbFqPercent,omitempty"` + BuyerRemark *string `json:"buyerRemark,omitempty"` + NotifyUrl *string `json:"notifyUrl,omitempty"` + ReturnUrl *string `json:"returnUrl,omitempty"` + ExpiredTime *int `json:"expiredTime,omitempty"` + OrderTimeout *string `json:"orderTimeout,omitempty"` + ExtParam *string `json:"extParam,omitempty"` + LimitPay *int `json:"limitPay,omitempty"` } type PaymentH5PayReq struct { @@ -269,7 +270,7 @@ func call[T any](s *SftClient, url string, req any) (*T, error) { } request.Header.Set("Content-Type", "application/json") - if env.LogHttpDump == true { + if env.DebugHttpDump == true { reqDump, err := httputil.DumpRequest(request, true) if err != nil { return nil, fmt.Errorf("请求内容转储失败:%w", err) @@ -282,7 +283,7 @@ func call[T any](s *SftClient, url string, req any) (*T, error) { return nil, fmt.Errorf("请求失败:%w", err) } - if env.LogHttpDump == true { + if env.DebugHttpDump == true { respDump, err := httputil.DumpResponse(response, true) if err != nil { return nil, fmt.Errorf("响应内容转储失败:%w", err) @@ -431,7 +432,7 @@ type SftTradeState string const ( SftInit SftTradeState = "INIT" - SftTradeAWAIT SftTradeState = "TRADE_WAIT" + SftTradeAwait SftTradeState = "TRADE_WAIT" SftTradeSuccess SftTradeState = "TRADE_SUCCESS" SftTradeFail SftTradeState = "TRADE_FAIL" SftTradeCancel SftTradeState = "TRADE_CANCEL" diff --git a/web/handlers/resource.go b/web/handlers/resource.go index 7d2a34f..ba18155 100644 --- a/web/handlers/resource.go +++ b/web/handlers/resource.go @@ -508,12 +508,7 @@ func ResourcePrice(c *fiber.Ctx) error { return err } - data, err := req.ToData() - if err != nil { - return err - } - return c.JSON(fiber.Map{ - "price": data.GetPrice().StringFixed(2), + "price": req.GetPrice().StringFixed(2), }) } diff --git a/web/handlers/trade.go b/web/handlers/trade.go index 18d7f1a..a25fc9c 100644 --- a/web/handlers/trade.go +++ b/web/handlers/trade.go @@ -45,10 +45,18 @@ func TradeCancelByTask(c *fiber.Ctx) error { return err } - // 取消支付 - err = s.Trade.CancelTrade(req.TradeNo, req.Method) + // 检查订单状态 + err = s.Trade.CheckTradeIfCanceled(&s.CheckTradeData{ + TradeNo: req.TradeNo, + Method: req.Method, + }) if err != nil { - slog.Warn("取消交易失败", "trade_no", req.TradeNo, "method", req.Method, "error", err) + slog.Debug(fmt.Sprintf("订单无需取消:%s", err.Error())) + } else { + err = s.Trade.CancelTrade(req.TradeNo, req.Method) + if err != nil { + slog.Warn("取消交易失败", "trade_no", req.TradeNo, "method", req.Method, "error", err) + } } return c.SendStatus(fiber.StatusNoContent) diff --git a/web/handlers/user.go b/web/handlers/user.go index 24ca870..78d90ce 100644 --- a/web/handlers/user.go +++ b/web/handlers/user.go @@ -163,154 +163,6 @@ type RechargeConfirmResp struct { Status string `json:"status"` } -func RechargePrepareAlipay(c *fiber.Ctx) error { - // 检查权限 - authContext, err := auth.Protect(c, []auth.PayloadType{auth.PayloadUser}, []string{}) - if err != nil { - return err - } - - // 解析请求参数 - req := new(RechargePrepareReq) - if err := c.BodyParser(req); err != nil { - return err - } - - // 保存交易信息 - var now = time.Now() - amount, err := decimal.NewFromString(req.Amount) - if err != nil { - return err - } - var result *s.TradeCreateResult - err = q.Q.Transaction(func(tx *q.Query) error { - result, err = s.Trade.CreateTrade(tx, authContext.Payload.Id, now, &s.TradeCreateData{ - Subject: "账户充值 - " + amount.StringFixed(2) + "元", - Amount: amount, - ExpireAt: time.Now().Add(30 * time.Minute), - Type: trade2.TypeRecharge, - Method: trade2.MethodAlipay, - Platform: req.Platform, - }) - return err - }) - if err != nil { - return err - } - - // 返回结果 - return c.JSON(RechargePrepareResp{ - TradeNo: result.TradeNo, - PayURL: result.PayURL, - }) -} - -func RechargeConfirmAlipay(c *fiber.Ctx) error { - // 检查权限 - _, err := auth.Protect(c, []auth.PayloadType{auth.PayloadUser}, []string{}) - if err != nil { - return err - } - - // 解析请求参数 - req := new(RechargeConfirmReq) - if err := c.BodyParser(req); err != nil { - return err - } - - // 验证支付结果 - result, err := s.Trade.VerifyTrade(&s.TradeVerifyData{ - TradeNo: req.TradeNo, - Method: trade2.MethodAlipay, - }) - if err != nil { - return err - } - - // 更新数据库 - err = s.User.RechargeConfirm(req.TradeNo, result) - if err != nil { - return err - } - - return c.JSON(fiber.Map{"status": "success"}) -} - -func RechargePrepareWechat(c *fiber.Ctx) error { - // 检查权限 - authContext, err := auth.Protect(c, []auth.PayloadType{auth.PayloadUser}, []string{}) - if err != nil { - return err - } - - // 解析请求参数 - req := new(RechargePrepareReq) - if err := c.BodyParser(req); err != nil { - return err - } - - // 保存交易信息 - var now = time.Now() - amount, err := decimal.NewFromString(req.Amount) - if err != nil { - return err - } - var result *s.TradeCreateResult - err = q.Q.Transaction(func(tx *q.Query) error { - result, err = s.Trade.CreateTrade(tx, authContext.Payload.Id, now, &s.TradeCreateData{ - Subject: "账户充值 - " + amount.StringFixed(2) + "元", - Amount: amount, - ExpireAt: now.Add(30 * time.Minute), - Type: trade2.TypeRecharge, - Method: trade2.MethodWeChat, - Platform: req.Platform, - }) - return err - }) - if err != nil { - return err - } - - // 返回结果 - return c.JSON(RechargePrepareResp{ - TradeNo: result.TradeNo, - PayURL: result.PayURL, - }) -} - -func RechargeConfirmWechat(c *fiber.Ctx) error { - // 检查权限 - _, err := auth.Protect(c, []auth.PayloadType{auth.PayloadUser}, []string{}) - if err != nil { - return err - } - - // 解析请求参数 - req := new(struct { - TradeNo string `json:"trade_no" validate:"required"` - }) - if err := c.BodyParser(req); err != nil { - return err - } - - // 验证支付结果 - result, err := s.Trade.VerifyTrade(&s.TradeVerifyData{ - TradeNo: req.TradeNo, - Method: trade2.MethodWeChat, - }) - if err != nil { - return err - } - - // 更新数据库 - err = s.User.RechargeConfirm(req.TradeNo, result) - if err != nil { - return err - } - - return c.JSON(fiber.Map{"status": "success"}) -} - func RechargePrepare(c *fiber.Ctx) error { // 检查权限 authContext, err := auth.Protect(c, []auth.PayloadType{auth.PayloadUser}, []string{}) @@ -367,7 +219,7 @@ func RechargeComplete(c *fiber.Ctx) error { } // 验证支付结果 - result, err := s.Trade.VerifyTrade(&s.TradeVerifyData{ + result, err := s.Trade.CheckTradeIfCreated(&s.CheckTradeData{ TradeNo: req.TradeNo, Method: trade2.MethodSft, }) diff --git a/web/services/resource.go b/web/services/resource.go index 5a2041b..236d8a8 100644 --- a/web/services/resource.go +++ b/web/services/resource.go @@ -90,20 +90,15 @@ func (s *resourceService) CreateResource(uid int32, now time.Time, ser *CreateRe func (s *resourceService) PrepareResource(uid int32, now time.Time, ser *PrepareResourceData) (*TradeCreateResult, error) { - data, err := ser.ToData() - if err != nil { - return nil, err - } - - name := data.GetName() - amount := data.GetPrice() + name := ser.GetName() + amount := ser.GetPrice() method := ser.PaymentMethod platform := ser.PaymentPlatform // 保存到数据库 var result *TradeCreateResult - err = q.Q.Transaction(func(q *q.Query) error { + err := q.Q.Transaction(func(q *q.Query) error { var err error // 生成交易订单 @@ -120,16 +115,11 @@ func (s *resourceService) PrepareResource(uid int32, now time.Time, ser *Prepare } // 保存请求缓存 - resourceSerializer := new(PrepareResourceData) - if err := resourceSerializer.ByData(data); err != nil { - return err - } - err = g.Redis.Set(context.Background(), resPrepareKey(result.TradeNo), &PrepareResourceCache{ Uid: uid, TradeId: result.Trade.ID, BillId: result.Bill.ID, - PrepareResourceData: resourceSerializer, + PrepareResourceData: ser, }, 30*time.Minute).Err() if err != nil { return err @@ -162,7 +152,7 @@ func (s *resourceService) CompleteResource(tradeNo string, now time.Time, opResu rs = opResult[0] } else { var err error - rs, err = Trade.VerifyTrade(&TradeVerifyData{ + rs, err = Trade.CheckTradeIfCreated(&CheckTradeData{ TradeNo: tradeNo, Method: cache.PaymentMethod, }) @@ -196,9 +186,8 @@ func (s *resourceService) CompleteResource(tradeNo string, now time.Time, opResu // 更新账单 _, err = q.Bill.Debug(). - Select(q.Bill.ResourceID). + Where(q.Bill.ID.Eq(cache.BillId)). Updates(&m.Bill{ - ID: cache.BillId, ResourceID: &resource.ID, }) if err != nil { @@ -416,6 +405,28 @@ type CreateResourceData struct { Long *CreateLongResourceData `json:"long,omitempty"` } +func (data *CreateResourceData) GetName() string { + switch data.Type { + case resource2.TypeShort: + return data.Short.GetName() + case resource2.TypeLong: + return data.Long.GetName() + default: + panic("未处理的 resource type 枚举值") + } +} + +func (data *CreateResourceData) GetPrice() decimal.Decimal { + switch data.Type { + case resource2.TypeShort: + return data.Short.GetPrice() + case resource2.TypeLong: + return data.Long.GetPrice() + default: + panic("未处理的 resource type 枚举值") + } +} + func (s *CreateResourceData) ToData() (CreateTypeResourceDataInter, error) { switch s.Type { case resource2.TypeShort: @@ -423,21 +434,8 @@ func (s *CreateResourceData) ToData() (CreateTypeResourceDataInter, error) { case resource2.TypeLong: return s.Long, nil } - return nil, fmt.Errorf("不支持的套餐类型") -} -func (s *CreateResourceData) ByData(data CreateTypeResourceDataInter) error { - switch data := data.(type) { - case *CreateShortResourceData: - s.Type = resource2.TypeShort - s.Short = data - case *CreateLongResourceData: - s.Type = resource2.TypeLong - s.Long = data - default: - return fmt.Errorf("不支持的套餐类型") - } - return nil + return nil, fmt.Errorf("不支持的套餐类型") } type PrepareResourceData struct { diff --git a/web/services/trade.go b/web/services/trade.go index 75c4354..1c9716d 100644 --- a/web/services/trade.go +++ b/web/services/trade.go @@ -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=%v,message=%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("不支持的支付方式") ) diff --git a/web/web.go b/web/web.go index 93dfc36..d6ddc6f 100644 --- a/web/web.go +++ b/web/web.go @@ -158,7 +158,9 @@ func newLogger() fiber.Handler { } func newRecover() fiber.Handler { - return recover.New() + return recover.New(recover.Config{ + EnableStackTrace: true, + }) } // endregion