115 lines
2.6 KiB
Go
115 lines
2.6 KiB
Go
package alipay
|
|
|
|
import (
|
|
"context"
|
|
"net/url"
|
|
|
|
"github.com/perfect-panel/server/pkg/logger"
|
|
"github.com/perfect-panel/server/pkg/tool"
|
|
"github.com/pkg/errors"
|
|
"github.com/smartwalle/alipay/v3"
|
|
)
|
|
|
|
type Config struct {
|
|
AppId string
|
|
PrivateKey string
|
|
PublicKey string
|
|
InvoiceName string
|
|
NotifyURL string
|
|
Sandbox bool
|
|
}
|
|
|
|
type Notification struct {
|
|
OrderNo string
|
|
Amount int64
|
|
Status Status
|
|
}
|
|
|
|
type Status string
|
|
|
|
const (
|
|
Success Status = "TRADE_SUCCESS"
|
|
Pending Status = "WAIT_BUYER_PAY"
|
|
Closed Status = "TRADE_CLOSED"
|
|
Finished Status = "TRADE_FINISHED"
|
|
Error Status = "TRADE_ERROR"
|
|
)
|
|
|
|
type Client struct {
|
|
Config
|
|
client *alipay.Client
|
|
}
|
|
type Order struct {
|
|
OrderNo string
|
|
Amount int64
|
|
}
|
|
|
|
func NewClient(c Config) *Client {
|
|
client, err := alipay.New(c.AppId, c.PrivateKey, c.Sandbox)
|
|
if err != nil {
|
|
logger.Error("[Alipay] NewClient failed: ", logger.Field("errors", err), logger.Field("config", c))
|
|
return nil
|
|
}
|
|
err = client.LoadAliPayPublicKey(c.PublicKey)
|
|
if err != nil {
|
|
logger.Error("[Alipay] NewClient failed: ", logger.Field("errors", err), logger.Field("config", c))
|
|
}
|
|
return &Client{
|
|
Config: c,
|
|
client: client,
|
|
}
|
|
}
|
|
|
|
func (c *Client) PreCreateTrade(ctx context.Context, order Order) (string, error) {
|
|
amountString := tool.FormatFloat(float64(order.Amount)/float64(100), 2)
|
|
trade, err := c.client.TradePreCreate(ctx, alipay.TradePreCreate{
|
|
Trade: alipay.Trade{
|
|
OutTradeNo: order.OrderNo,
|
|
TotalAmount: amountString,
|
|
Subject: c.InvoiceName,
|
|
NotifyURL: c.NotifyURL,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if trade.Code != alipay.CodeSuccess {
|
|
return "", errors.New("PreCreateTrade failed: " + trade.Msg)
|
|
}
|
|
return trade.QRCode, nil
|
|
}
|
|
|
|
func (c *Client) QueryTrade(ctx context.Context, orderNo string) (Status, error) {
|
|
trade, err := c.client.TradeQuery(ctx, alipay.TradeQuery{
|
|
OutTradeNo: orderNo,
|
|
})
|
|
if err != nil {
|
|
return Error, err
|
|
}
|
|
switch trade.TradeStatus {
|
|
case alipay.TradeStatusSuccess:
|
|
return Success, nil
|
|
case alipay.TradeStatusWaitBuyerPay:
|
|
return Pending, nil
|
|
case alipay.TradeStatusClosed:
|
|
return Closed, nil
|
|
case alipay.TradeStatusFinished:
|
|
return Finished, nil
|
|
default:
|
|
return Error, errors.New("QueryTrade failed: " + trade.Msg)
|
|
}
|
|
}
|
|
|
|
func (c *Client) DecodeNotification(form url.Values) (*Notification, error) {
|
|
notify, err := c.client.DecodeNotification(form)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Notification{
|
|
OrderNo: notify.OutTradeNo,
|
|
Amount: int64(tool.FormatStringToFloat(notify.TotalAmount) * 100),
|
|
Status: Status(notify.TradeStatus),
|
|
}, nil
|
|
}
|