197 lines
4.0 KiB
Go
197 lines
4.0 KiB
Go
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
|