| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- package gopay
- import (
- "crypto/tls"
- "crypto/x509"
- "encoding/xml"
- "github.com/parnurzeal/gorequest"
- "io/ioutil"
- )
- type weChatClient struct {
- AppId string
- MchId string
- secretKey string
- isProd bool
- }
- //初始化微信客户端 ok
- // appId:应用ID
- // mchID:商户ID
- // secretKey:Key值
- // isProd:是否是正式环境
- func NewWeChatClient(appId, mchId, secretKey string, isProd bool) *weChatClient {
- client := new(weChatClient)
- client.AppId = appId
- client.MchId = mchId
- client.secretKey = secretKey
- client.isProd = isProd
- return client
- }
- //提交付款码支付 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
- func (this *weChatClient) Micropay(body BodyMap) (wxRsp *WeChatMicropayResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- bytes, err = this.doWeChat(body, wxURL_Micropay)
- if err != nil {
- return nil, err
- }
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_Micropay)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatMicropayResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //统一下单 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
- func (this *weChatClient) UnifiedOrder(body BodyMap) (wxRsp *WeChatUnifiedOrderResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- bytes, err = this.doWeChat(body, wxURL_UnifiedOrder)
- if err != nil {
- return nil, err
- }
- } else {
- body.Set("total_fee", 101)
- bytes, err = this.doWeChat(body, wxURL_SanBox_UnifiedOrder)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatUnifiedOrderResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //查询订单 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
- func (this *weChatClient) QueryOrder(body BodyMap) (wxRsp *WeChatQueryOrderResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- bytes, err = this.doWeChat(body, wxURL_OrderQuery)
- if err != nil {
- return nil, err
- }
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_OrderQuery)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatQueryOrderResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //关闭订单 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
- func (this *weChatClient) CloseOrder(body BodyMap) (wxRsp *WeChatCloseOrderResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- bytes, err = this.doWeChat(body, wxURL_CloseOrder)
- if err != nil {
- return nil, err
- }
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_CloseOrder)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatCloseOrderResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //撤销订单 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
- func (this *weChatClient) Reverse(body BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp *WeChatReverseResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- pkcsPool := x509.NewCertPool()
- pkcs, err := ioutil.ReadFile(pkcs12FilePath)
- if err != nil {
- return nil, err
- }
- pkcsPool.AppendCertsFromPEM(pkcs)
- certificate, err := tls.LoadX509KeyPair(certFilePath, keyFilePath)
- if err != nil {
- return nil, err
- }
- tlsConfig := new(tls.Config)
- tlsConfig.Certificates = []tls.Certificate{certificate}
- tlsConfig.RootCAs = pkcsPool
- tlsConfig.InsecureSkipVerify = true
- bytes, err = this.doWeChat(body, wxURL_Reverse, tlsConfig)
- if err != nil {
- return nil, err
- }
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_Reverse)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatReverseResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //申请退款 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
- func (this *weChatClient) Refund(body BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp *WeChatRefundResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- pkcsPool := x509.NewCertPool()
- pkcs, err := ioutil.ReadFile(pkcs12FilePath)
- if err != nil {
- return nil, err
- }
- pkcsPool.AppendCertsFromPEM(pkcs)
- certificate, err := tls.LoadX509KeyPair(certFilePath, keyFilePath)
- if err != nil {
- return nil, err
- }
- tlsConfig := new(tls.Config)
- tlsConfig.Certificates = []tls.Certificate{certificate}
- tlsConfig.RootCAs = pkcsPool
- tlsConfig.InsecureSkipVerify = true
- bytes, err = this.doWeChat(body, wxURL_Refund, tlsConfig)
- if err != nil {
- return nil, err
- }
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_Refund)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatRefundResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //查询退款 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
- func (this *weChatClient) QueryRefund(body BodyMap) (wxRsp *WeChatQueryRefundResponse, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- bytes, err = this.doWeChat(body, wxURL_RefundQuery)
- if err != nil {
- return nil, err
- }
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_RefundQuery)
- if err != nil {
- return nil, err
- }
- }
- wxRsp = new(WeChatQueryRefundResponse)
- err = xml.Unmarshal(bytes, wxRsp)
- if err != nil {
- return nil, err
- }
- return wxRsp, nil
- }
- //下载对账单 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6
- func (this *weChatClient) DownloadBill(body BodyMap) (wxRsp string, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- bytes, err = this.doWeChat(body, wxURL_DownloadBill)
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_DownloadBill)
- }
- wxRsp = string(bytes)
- if err != nil {
- return wxRsp, err
- }
- return wxRsp, nil
- }
- //下载资金账单 ok
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7
- // 好像不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
- func (this *weChatClient) DownloadFundFlow(body BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp string, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- pkcsPool := x509.NewCertPool()
- pkcs, err := ioutil.ReadFile(pkcs12FilePath)
- if err != nil {
- return "", err
- }
- pkcsPool.AppendCertsFromPEM(pkcs)
- certificate, err := tls.LoadX509KeyPair(certFilePath, keyFilePath)
- if err != nil {
- return "", err
- }
- tlsConfig := new(tls.Config)
- tlsConfig.Certificates = []tls.Certificate{certificate}
- tlsConfig.RootCAs = pkcsPool
- tlsConfig.InsecureSkipVerify = true
- bytes, err = this.doWeChat(body, wxURL_DownloadFundFlow, tlsConfig)
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_DownloadFundFlow)
- }
- if err != nil {
- return "", err
- }
- wxRsp = string(bytes)
- return wxRsp, nil
- }
- //拉取订单评价数据
- // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
- // 好像不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
- func (this *weChatClient) BatchQueryComment(body BodyMap, certFilePath, keyFilePath, pkcs12FilePath string) (wxRsp string, err error) {
- var bytes []byte
- if this.isProd {
- //正式环境
- body.Set("sign_type", SignType_HMAC_SHA256)
- pkcsPool := x509.NewCertPool()
- pkcs, err := ioutil.ReadFile(pkcs12FilePath)
- if err != nil {
- return "", err
- }
- pkcsPool.AppendCertsFromPEM(pkcs)
- certificate, err := tls.LoadX509KeyPair(certFilePath, keyFilePath)
- if err != nil {
- return "", err
- }
- tlsConfig := new(tls.Config)
- tlsConfig.Certificates = []tls.Certificate{certificate}
- tlsConfig.RootCAs = pkcsPool
- tlsConfig.InsecureSkipVerify = true
- bytes, err = this.doWeChat(body, wxURL_BatchQueryComment, tlsConfig)
- } else {
- bytes, err = this.doWeChat(body, wxURL_SanBox_BatchQueryComment)
- }
- if err != nil {
- return "", err
- }
- wxRsp = string(bytes)
- return wxRsp, nil
- }
- //向微信发送请求 ok
- func (this *weChatClient) doWeChat(body BodyMap, url string, tlsConfig ...*tls.Config) (bytes []byte, err error) {
- var sign string
- body.Set("appid", this.AppId)
- body.Set("mch_id", this.MchId)
- //===============生成参数===================
- if !this.isProd {
- //沙箱环境
- body.Set("sign_type", SignType_MD5)
- //从微信接口获取SanBoxSignKey
- key, err := getSanBoxSign(this.MchId, body.Get("nonce_str"), this.secretKey, body.Get("sign_type"))
- if err != nil {
- return nil, err
- }
- sign = getLocalSign(key, body.Get("sign_type"), body)
- } else {
- //正式环境
- //本地计算Sign
- sign = getLocalSign(this.secretKey, body.Get("sign_type"), body)
- }
- body.Set("sign", sign)
- reqXML := generateXml(body)
- //===============发起请求===================
- agent := gorequest.New()
- if this.isProd && tlsConfig != nil {
- agent.TLSClientConfig(tlsConfig[0])
- }
- agent.Post(url)
- agent.Type("xml")
- agent.SendString(reqXML)
- _, bytes, errs := agent.EndBytes()
- if len(errs) > 0 {
- return nil, errs[0]
- }
- return bytes, nil
- }
|