This commit is contained in:
孟帅
2023-05-10 23:54:50 +08:00
parent bbe655a4d8
commit 49a96750bf
314 changed files with 15138 additions and 6244 deletions

View File

@@ -0,0 +1,197 @@
package alipay
import (
"context"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts"
"hotgo/internal/model"
"hotgo/internal/model/input/payin"
)
func New(config *model.PayConfig) *aliPay {
return &aliPay{
config: config,
}
}
type aliPay struct {
config *model.PayConfig
}
// Refund 订单退款
func (h *aliPay) Refund(ctx context.Context, in payin.RefundInp) (res *payin.RefundModel, err error) {
client, err := GetClient(h.config)
if err != nil {
return
}
bm := make(gopay.BodyMap)
bm.Set("out_trade_no", in.Pay.OutTradeNo).
Set("refund_amount", in.RefundMoney).
Set("out_request_no", in.RefundSn).
Set("refund_reason", in.Remark)
refund, err := client.TradeRefund(ctx, bm)
if err != nil {
return
}
if refund.Response.FundChange != "Y" {
err = gerror.New("支付宝本次退款未发生资金变化!")
return
}
return
}
// Notify 异步通知
func (h *aliPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.NotifyModel, err error) {
notifyReq, err := alipay.ParseNotifyToBodyMap(ghttp.RequestFromCtx(ctx).Request)
if err != nil {
return
}
// 支付宝异步通知验签(公钥证书模式)
ok, err := alipay.VerifySignWithCert(h.config.AliPayCertPublicKeyRSA2, notifyReq)
if err != nil {
return
}
if !ok {
err = gerror.New("支付宝验签不通过!")
return
}
var notify *NotifyRequest
if err = gconv.Scan(notifyReq, &notify); err != nil {
return
}
if notify == nil {
err = gerror.New("解析订单参数失败!")
return
}
if notify.TradeStatus != "TRADE_SUCCESS" {
err = gerror.New("非交易支付成功状态,无需处理!")
// 这里如果相对非交易支付成功状态进行处理,可自行调整此处逻辑
// ...
return
}
if notify.OutTradeNo == "" {
err = gerror.New("订单中没有找到商户单号!")
return
}
res = new(payin.NotifyModel)
res.TransactionId = notify.TradeNo
res.OutTradeNo = notify.OutTradeNo
res.PayAt = notify.GmtPayment
res.ActualAmount = gconv.Float64(notify.ReceiptAmount)
return
}
// CreateOrder 创建订单
func (h *aliPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res *payin.CreateOrderModel, err error) {
client, err := GetClient(h.config)
if err != nil {
return nil, err
}
// 设置回调地址
client.SetReturnUrl(in.Pay.ReturnUrl).SetNotifyUrl(in.Pay.NotifyUrl)
switch in.Pay.TradeType {
case consts.TradeTypeAliScan, consts.TradeTypeAliWeb:
return h.scan(ctx, in)
case consts.TradeTypeAliWap:
return h.wap(ctx, in)
default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
}
return
}
func GetClient(config *model.PayConfig) (client *alipay.Client, err error) {
client, err = alipay.NewClient(config.AliPayAppId, gfile.GetContents(config.AliPayPrivateKey), true)
if err != nil {
err = gerror.Newf("创建支付宝客户端失败:%+v", err.Error())
return
}
// 打开Debug开关输出日志默认关闭
if config.Debug {
client.DebugSwitch = gopay.DebugOn
}
client.SetLocation(alipay.LocationShanghai) // 设置时区,不设置或出错均为默认服务器时间
// 证书路径
err = client.SetCertSnByPath(config.AliPayAppCertPublicKey, config.AliPayRootCert, config.AliPayCertPublicKeyRSA2)
return
}
// scan 扫码支付
func (h *aliPay) scan(ctx context.Context, in payin.CreateOrderInp) (res *payin.CreateOrderModel, err error) {
client, err := GetClient(h.config)
if err != nil {
return nil, err
}
// 设置回调地址
client.SetReturnUrl(in.Pay.ReturnUrl).SetNotifyUrl(in.Pay.NotifyUrl)
bm := make(gopay.BodyMap)
bm.Set("subject", in.Pay.Subject).
Set("out_trade_no", in.Pay.OutTradeNo).
Set("total_amount", in.Pay.PayAmount)
payUrl, err := client.TradePagePay(ctx, bm)
if err != nil {
if bizErr, ok := alipay.IsBizError(err); ok {
return nil, bizErr
}
return nil, err
}
res = new(payin.CreateOrderModel)
res.TradeType = in.Pay.TradeType
res.PayURL = payUrl
res.OutTradeNo = in.Pay.OutTradeNo
return
}
func (h *aliPay) wap(ctx context.Context, in payin.CreateOrderInp) (res *payin.CreateOrderModel, err error) {
client, err := GetClient(h.config)
if err != nil {
return nil, err
}
// 设置回调地址
client.SetReturnUrl(in.Pay.ReturnUrl).SetNotifyUrl(in.Pay.NotifyUrl)
bm := make(gopay.BodyMap)
bm.Set("subject", in.Pay.Subject).
Set("out_trade_no", in.Pay.OutTradeNo).
Set("total_amount", in.Pay.PayAmount).
Set("product_code", "QUICK_WAP_WAY")
// 手机网站支付请求
payUrl, err := client.TradeWapPay(ctx, bm)
if err != nil {
return
}
res = new(payin.CreateOrderModel)
res.TradeType = in.Pay.TradeType
res.PayURL = payUrl
res.OutTradeNo = in.Pay.OutTradeNo
return
}

View File

@@ -0,0 +1,61 @@
package alipay
import "github.com/gogf/gf/v2/os/gtime"
// NotifyRequest 支付宝异步通知参数
// 文档https://opendocs.alipay.com/open/203/105286
type NotifyRequest struct {
NotifyTime string `json:"notify_time,omitempty"`
NotifyType string `json:"notify_type,omitempty"`
NotifyId string `json:"notify_id,omitempty"`
AppId string `json:"app_id,omitempty"`
Charset string `json:"charset,omitempty"`
Version string `json:"version,omitempty"`
SignType string `json:"sign_type,omitempty"`
Sign string `json:"sign,omitempty"`
AuthAppId string `json:"auth_app_id,omitempty"`
TradeNo string `json:"trade_no,omitempty"`
OutTradeNo string `json:"out_trade_no,omitempty"`
OutBizNo string `json:"out_biz_no,omitempty"`
BuyerId string `json:"buyer_id,omitempty"`
BuyerLogonId string `json:"buyer_logon_id,omitempty"`
SellerId string `json:"seller_id,omitempty"`
SellerEmail string `json:"seller_email,omitempty"`
TradeStatus string `json:"trade_status,omitempty"`
TotalAmount string `json:"total_amount,omitempty"`
ReceiptAmount string `json:"receipt_amount,omitempty"`
InvoiceAmount string `json:"invoice_amount,omitempty"`
BuyerPayAmount string `json:"buyer_pay_amount,omitempty"`
PointAmount string `json:"point_amount,omitempty"`
RefundFee string `json:"refund_fee,omitempty"`
Subject string `json:"subject,omitempty"`
Body string `json:"body,omitempty"`
GmtCreate string `json:"gmt_create,omitempty"`
GmtPayment *gtime.Time `json:"gmt_payment,omitempty"`
GmtRefund string `json:"gmt_refund,omitempty"`
GmtClose string `json:"gmt_close,omitempty"`
FundBillList []*FundBillListInfo `json:"fund_bill_list,omitempty"`
PassbackParams string `json:"passback_params,omitempty"`
VoucherDetailList []*VoucherDetail `json:"voucher_detail_list,omitempty"`
Method string `json:"method,omitempty"` // 电脑网站支付 支付宝请求 return_url 同步返回参数
Timestamp string `json:"timestamp,omitempty"` // 电脑网站支付 支付宝请求 return_url 同步返回参数
}
type FundBillListInfo struct {
Amount string `json:"amount,omitempty"`
FundChannel string `json:"fundChannel,omitempty"` // 异步通知里是 fundChannel
}
type VoucherDetail struct {
Id string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Amount string `json:"amount,omitempty"`
MerchantContribute string `json:"merchant_contribute,omitempty"`
OtherContribute string `json:"other_contribute,omitempty"`
Memo string `json:"memo,omitempty"`
TemplateId string `json:"template_id,omitempty"`
PurchaseBuyerContribute string `json:"purchase_buyer_contribute,omitempty"`
PurchaseMerchantContribute string `json:"purchase_merchant_contribute,omitempty"`
PurchaseAntContribute string `json:"purchase_ant_contribute,omitempty"`
}