package handlers import ( "fmt" "log/slog" "net/http" g "platform/web/globals" q "platform/web/queries" s "platform/web/services" "strconv" "time" "github.com/gofiber/fiber/v2" "github.com/smartwalle/alipay/v3" "github.com/valyala/fasthttp/fasthttpadaptor" "github.com/wechatpay-apiv3/wechatpay-go/services/payments" ) // region AlipayCallback func AlipayCallback(c *fiber.Ctx) error { // 解析请求 httpRequest := new(http.Request) if err := fasthttpadaptor.ConvertRequest(c.Context(), httpRequest, false); err != nil { return err } if err := httpRequest.ParseForm(); err != nil { return err } notification, err := g.Alipay.DecodeNotification(httpRequest.Form) if err != nil { return err } slog.Debug("支付宝支付回调", "notification", fmt.Sprintf("%+v", notification)) // todo 退款通知 if isRefund(notification) { return act(c) } // 查询交易信息 trade, err := q.Q.Trade.Where(q.Trade.InnerNo.Eq(notification.OutTradeNo)).Take() if err != nil { // 跳过测试通知 return act(c) } switch notification.NotifyType { // 支付成功 case string(alipay.TradeStatusSuccess): // 收集交易状态 payment, err := strconv.ParseFloat(notification.TotalAmount, 64) if err != nil { return err } paidAt, err := time.Parse("2006-01-02 15:04:05", notification.GmtPayment) if err != nil { return err } verified := &s.TransactionVerifyResult{ TransId: notification.TradeNo, Payment: payment, Time: paidAt, } switch trade.Type { // 余额充值 case 2: err := s.User.RechargeConfirm(c.Context(), notification.OutTradeNo, verified) if err != nil { return err } // 购买产品 case 1: err = s.Resource.CompleteResource(c.Context(), notification.OutTradeNo, verified) if err != nil { return err } } // 支付关闭 case string(alipay.TradeStatusClosed): switch trade.Type { // 购买产品 case 1: cancelAt, err := time.Parse("2006-01-02 15:04:05", notification.GmtClose) if err != nil { return err } err = s.Resource.CancelResource(c.Context(), notification.OutTradeNo, cancelAt, s.TransactionMethodAlipay) if err != nil { return err } } } return act(c) } type AdapterWriter struct { c *fiber.Ctx } func (a AdapterWriter) Header() http.Header { panic("implement me") } func (a AdapterWriter) Write(bytes []byte) (int, error) { return a.c.Write(bytes) } func (a AdapterWriter) WriteHeader(statusCode int) { a.c.Status(statusCode) } func isRefund(notification *alipay.Notification) bool { return notification.OutBizNo != "" || notification.RefundFee != "" || notification.GmtRefund != "" } func act(c *fiber.Ctx) error { g.Alipay.ACKNotification(AdapterWriter{c: c}) return nil } // endregion // region WechatPayCallback func WechatPayCallback(c *fiber.Ctx) error { // 解析请求参数 req := new(http.Request) if err := fasthttpadaptor.ConvertRequest(c.Context(), req, false); err != nil { return err } content := new(payments.Transaction) _, err := g.WechatPay.Notify.ParseNotifyRequest(c.Context(), req, content) if err != nil { return err } slog.Debug("微信支付回调", "content", fmt.Sprintf("%+v", content)) // 查询交易信息 trade, err := q.Q.Trade.Where(q.Trade.InnerNo.Eq(*content.OutTradeNo)).Take() if err != nil { // 跳过测试通知 return nil } switch *content.TradeState { // 支付成功 case "SUCCESS": // 收集交易状态 payment := float64(*content.Amount.PayerTotal) / 100 paidAt, err := time.Parse(time.RFC3339, *content.SuccessTime) if err != nil { return err } verified := &s.TransactionVerifyResult{ TransId: *content.TransactionId, Payment: payment, Time: paidAt, } switch { // 余额充值 case trade.Type == 2: err := s.User.RechargeConfirm(c.Context(), *content.OutTradeNo, verified) if err != nil { return err } // 购买产品 case trade.Type == 1: err = s.Resource.CompleteResource(c.Context(), *content.OutTradeNo, verified) if err != nil { return err } } } return nil } // endregion