mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-10-12 21:13:45 +08:00
This commit is contained in:
134
server/internal/library/payment/qqpay/handle.go
Normal file
134
server/internal/library/payment/qqpay/handle.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package qqpay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/qq"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/grand"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/input/payin"
|
||||
)
|
||||
|
||||
func New(config *model.PayConfig) *qqPay {
|
||||
return &qqPay{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
type qqPay struct {
|
||||
config *model.PayConfig
|
||||
}
|
||||
|
||||
// Refund 订单退款
|
||||
func (h *qqPay) Refund(ctx context.Context, in payin.RefundInp) (res *payin.RefundModel, err error) {
|
||||
err = gerror.New("暂不支持QQ支付申请退款,如有疑问请联系管理员")
|
||||
return
|
||||
}
|
||||
|
||||
// Notify 异步通知
|
||||
func (h *qqPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.NotifyModel, err error) {
|
||||
notifyReq, err := qq.ParseNotifyToBodyMap(ghttp.RequestFromCtx(ctx).Request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 验签操作
|
||||
ok, err := qq.VerifySign(h.config.QQPayApiKey, qq.SignType_MD5, notifyReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !ok {
|
||||
err = gerror.New("QQ支付验签不通过!")
|
||||
return
|
||||
}
|
||||
|
||||
var notify *NotifyRequest
|
||||
if err = gconv.Scan(notifyReq, ¬ify); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if notify == nil {
|
||||
err = gerror.New("解析订单参数失败!")
|
||||
return
|
||||
}
|
||||
|
||||
if notify.TradeState != "SUCCESS" {
|
||||
err = gerror.New("非交易支付成功状态,无需处理!")
|
||||
// 这里如果相对非交易支付成功状态进行处理,可自行调整此处逻辑
|
||||
// ...
|
||||
return
|
||||
}
|
||||
|
||||
if notify.OutTradeNo == "" {
|
||||
err = gerror.New("订单中没有找到商户单号!")
|
||||
return
|
||||
}
|
||||
|
||||
res = new(payin.NotifyModel)
|
||||
res.TransactionId = notify.TransactionId
|
||||
res.OutTradeNo = notify.OutTradeNo
|
||||
res.PayAt = gtime.New(notify.TimeEnd)
|
||||
res.ActualAmount = gconv.Float64(notify.CouponFee) / 100 // 用户本次交易中,实际支付的金额 转为元,和系统内保持一至
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CreateOrder 创建订单
|
||||
func (h *qqPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res *payin.CreateOrderModel, err error) {
|
||||
client := GetClient(h.config)
|
||||
|
||||
switch in.Pay.TradeType {
|
||||
case consts.TradeTypeQQWeb, consts.TradeTypeQQWap:
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.
|
||||
Set("mch_id", h.config.QQPayMchId).
|
||||
Set("body", in.Pay.Subject).
|
||||
Set("out_trade_no", in.Pay.OutTradeNo).
|
||||
Set("notify_url", in.Pay.NotifyUrl).
|
||||
Set("nonce_str", grand.Letters(32)).
|
||||
Set("spbill_create_ip", in.Pay.CreateIp).
|
||||
Set("trade_type", "NATIVE"). // MICROPAY、APP、JSAPI、NATIVE
|
||||
Set("total_fee", int64(in.Pay.PayAmount*100))
|
||||
|
||||
qqRsp, err := client.UnifiedOrder(ctx, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if qqRsp.ReturnCode != "SUCCESS" {
|
||||
err = gerror.New(qqRsp.ReturnMsg)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if qqRsp.ResultCode != "SUCCESS" {
|
||||
err = gerror.New(qqRsp.ErrCodeDes)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = new(payin.CreateOrderModel)
|
||||
res.TradeType = in.Pay.TradeType
|
||||
res.PayURL = qqRsp.CodeUrl
|
||||
res.OutTradeNo = in.Pay.OutTradeNo
|
||||
|
||||
default:
|
||||
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GetClient(config *model.PayConfig) (client *qq.Client) {
|
||||
client = qq.NewClient(config.QQPayMchId, config.QQPayApiKey)
|
||||
|
||||
// 打开Debug开关,输出日志,默认关闭
|
||||
if config.Debug {
|
||||
client.DebugSwitch = gopay.DebugOn
|
||||
}
|
||||
return
|
||||
}
|
23
server/internal/library/payment/qqpay/model.go
Normal file
23
server/internal/library/payment/qqpay/model.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package qqpay
|
||||
|
||||
// NotifyRequest QQ支付异步通知参数
|
||||
// 文档:https://mp.qpay.tenpay.cn/buss/wiki/38/1204
|
||||
type NotifyRequest struct {
|
||||
Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
|
||||
MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
|
||||
NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
|
||||
Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
|
||||
DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
|
||||
TradeType string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
|
||||
TradeState string `xml:"trade_state,omitempty" json:"trade_state,omitempty"`
|
||||
BankType string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
|
||||
FeeType string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
|
||||
TotalFee string `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
|
||||
CashFee string `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
|
||||
CouponFee string `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
|
||||
TransactionId string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
|
||||
OutTradeNo string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
|
||||
Attach string `xml:"attach,omitempty" json:"attach,omitempty"`
|
||||
TimeEnd string `xml:"time_end,omitempty" json:"time_end,omitempty"`
|
||||
Openid string `xml:"openid,omitempty" json:"openid,omitempty"`
|
||||
}
|
Reference in New Issue
Block a user