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:商户证书的证书序列号 // apiV3Key:apiV3Key,商户平台获取 // 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 }