light-core/pkg/myPay/wechat.go

262 lines
7.1 KiB
Go
Raw Normal View History

2024-12-17 22:28:48 +08:00
package myPay
import (
"context"
"errors"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/wechat/v3"
"net/http"
"time"
)
type Wechat struct {
ctx context.Context
cli *wechat.ClientV3
params *WechatPayV3Impl
orderNo string
amount int
description string
notifyUrl string
profitSharing bool
}
func NewWechat(params *WechatPayV3Impl) *Wechat {
// NewClientV3 初始化微信客户端 v3
// mchid商户ID 或者服务商模式的 sp_mchid
// serialNo商户证书的证书序列号
// apiV3KeyapiV3Key商户平台获取
// privateKey私钥 apiclient_key.pem 读取后的内容
client, err := wechat.NewClientV3(params.MchId, params.SerialNo, params.ApiV3Key, params.PKContent)
if err != nil {
panic(err.Error())
}
// 设置微信平台API证书和序列号推荐开启自动验签无需手动设置证书公钥等信息
//client.SetPlatformCert([]byte(""), "")
// 启用自动同步返回验签并定时更新微信平台API证书开启自动验签时无需单独设置微信平台API证书和序列号
client.SetPlatformCert([]byte(params.WxPkContent), params.WxPkSerialNo)
// 启用自动同步返回验签并定时更新微信平台API证书
//err = client.AutoVerifySign()
//if err != nil {
// return nil, err
//}
// 打开Debug开关输出日志默认是关闭的
if params.IsProd {
client.DebugSwitch = gopay.DebugOff
} else {
client.DebugSwitch = gopay.DebugOn
}
return &Wechat{params: params, cli: client, ctx: context.Background()}
}
func (t *Wechat) GetCli() *wechat.ClientV3 {
return t.cli
}
func (t *Wechat) SetCommonConfig(notifyUrl string) *Wechat {
t.notifyUrl = notifyUrl
return t
}
func (t *Wechat) SetOrderInfo(orderNo string, amount int, description string) *Wechat {
t.orderNo = orderNo
t.amount = amount
t.description = description
return t
}
func (t *Wechat) setBodyMap() gopay.BodyMap {
if t.description == "" || t.orderNo == "" || t.notifyUrl == "" {
panic("param is empty")
}
if t.amount == 0 {
panic("amount is zero")
}
bm := make(gopay.BodyMap)
bm.Set("description", t.description).
Set("out_trade_no", t.orderNo).
Set("time_expire", time.Now().Add(10*time.Minute).Format(time.RFC3339)).
Set("notify_url", t.notifyUrl).
SetBodyMap("amount", func(bm gopay.BodyMap) {
bm.Set("total", t.amount).Set("currency", "CNY")
})
if t.profitSharing {
bm.SetBodyMap("settle_info", func(bm gopay.BodyMap) {
bm.Set("profit_sharing", true)
})
}
return bm
}
func (t *Wechat) SetProfitSharing(b bool) *Wechat {
t.profitSharing = b
return t
}
func (t *Wechat) GetApp() (*wechat.AppPayParams, error) {
wxRsp, err := t.cli.V3TransactionApp(t.ctx, t.setBodyMap().Set("appid", t.params.AppAppid))
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return t.cli.PaySignOfApp(t.params.AppAppid, wxRsp.Response.PrepayId)
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetJsapi(openId string) (*wechat.JSAPIPayParams, error) {
wxRsp, err := t.cli.V3TransactionJsapi(t.ctx,
t.setBodyMap().Set("appid", t.params.MpAppid).SetBodyMap("payer", func(bm gopay.BodyMap) {
bm.Set("openid", openId)
}),
)
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return t.cli.PaySignOfJSAPI(t.params.MpAppid, wxRsp.Response.PrepayId)
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetJsapiForMini(openId string) (*wechat.JSAPIPayParams, error) {
wxRsp, err := t.cli.V3TransactionJsapi(t.ctx,
t.setBodyMap().Set("appid", t.params.MiniAppid).SetBodyMap("payer", func(bm gopay.BodyMap) {
bm.Set("openid", openId)
}),
)
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return t.cli.PaySignOfJSAPI(t.params.MiniAppid, wxRsp.Response.PrepayId)
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetNative() (*wechat.Native, error) {
wxRsp, err := t.cli.V3TransactionNative(t.ctx, t.setBodyMap().Set("appid", t.params.MpAppid))
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return wxRsp.Response, err
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetH5(ip string, appName string, appUrl string) (*wechat.H5Url, error) {
wxRsp, err := t.cli.V3TransactionH5(t.ctx, t.setBodyMap().Set("appid", t.params.MpAppid).SetBodyMap("scene_info", func(bm gopay.BodyMap) {
bm.Set("payer_client_ip", ip)
bm.SetBodyMap("h5_info", func(bm gopay.BodyMap) {
bm.Set("type", "Wap")
bm.Set("app_url", appUrl)
bm.Set("app_name", appName)
})
}))
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return wxRsp.Response, nil
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) Notify(req *http.Request) (*WechatNotifyResp, error) {
notifyReq, err := wechat.V3ParseNotify(req)
if err != nil {
return nil, errors.New("解析回调失败")
}
err = notifyReq.VerifySignByPK(t.cli.WxPublicKey())
if err != nil {
return nil, errors.New("sign Error")
}
if notifyReq.EventType == "TRANSACTION.SUCCESS" {
result, err := notifyReq.DecryptPayCipherText(t.params.ApiV3Key)
if err != nil {
return nil, errors.New("解密错误")
} else {
return &WechatNotifyResp{resp: result}, nil
}
}
return nil, errors.New(notifyReq.EventType)
}
func (t *Wechat) GetOrderNo() string {
return t.orderNo
}
func (t *Wechat) GetAmount() int {
return t.amount
}
func NotifySuccess(msg string) (int, *wechat.V3NotifyRsp) {
return http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: msg}
}
func NotifyFail(msg string) (int, *wechat.V3NotifyRsp) {
return http.StatusBadRequest, &wechat.V3NotifyRsp{Code: gopay.FAIL, Message: msg}
}
type WechatPayV3Impl struct {
MpAppid string
AppAppid string
MiniAppid string
MchId string
ApiV3Key string
SerialNo string
PKContent string
WxPkSerialNo string
WxPkContent string
IsProd bool
}