wechat_client.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. package gopay
  2. import (
  3. "encoding/xml"
  4. "github.com/parnurzeal/gorequest"
  5. )
  6. type weChatClient struct {
  7. AppId string
  8. MchId string
  9. secretKey string
  10. isProd bool
  11. }
  12. //初始化微信客户端 ok
  13. // appId:应用ID
  14. // mchID:商户ID
  15. // secretKey:Key值
  16. // isProd:是否是正式环境
  17. func NewWeChatClient(appId, mchId, secretKey string, isProd bool) *weChatClient {
  18. client := new(weChatClient)
  19. client.AppId = appId
  20. client.MchId = mchId
  21. client.secretKey = secretKey
  22. client.isProd = isProd
  23. return client
  24. }
  25. //提交付款码支付 ok
  26. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
  27. func (this *weChatClient) Micropay(body BodyMap) (wxRsp *WeChatMicropayResponse, err error) {
  28. var bytes []byte
  29. if this.isProd {
  30. //正式环境
  31. bytes, err = this.doWeChat(body, wxURL_Micropay)
  32. if err != nil {
  33. return nil, err
  34. }
  35. } else {
  36. bytes, err = this.doWeChat(body, wxURL_SanBox_Micropay)
  37. if err != nil {
  38. return nil, err
  39. }
  40. }
  41. wxRsp = new(WeChatMicropayResponse)
  42. err = xml.Unmarshal(bytes, wxRsp)
  43. if err != nil {
  44. return nil, err
  45. }
  46. return wxRsp, nil
  47. }
  48. //统一下单 ok
  49. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
  50. func (this *weChatClient) UnifiedOrder(body BodyMap) (wxRsp *WeChatUnifiedOrderResponse, err error) {
  51. var bytes []byte
  52. if this.isProd {
  53. //正式环境
  54. bytes, err = this.doWeChat(body, wxURL_UnifiedOrder)
  55. if err != nil {
  56. return nil, err
  57. }
  58. } else {
  59. body.Set("total_fee", 101)
  60. bytes, err = this.doWeChat(body, wxURL_SanBox_UnifiedOrder)
  61. if err != nil {
  62. return nil, err
  63. }
  64. }
  65. wxRsp = new(WeChatUnifiedOrderResponse)
  66. err = xml.Unmarshal(bytes, wxRsp)
  67. if err != nil {
  68. return nil, err
  69. }
  70. return wxRsp, nil
  71. }
  72. //查询订单 ok
  73. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
  74. func (this *weChatClient) QueryOrder(body BodyMap) (wxRsp *WeChatQueryOrderResponse, err error) {
  75. var bytes []byte
  76. if this.isProd {
  77. //正式环境
  78. bytes, err = this.doWeChat(body, wxURL_OrderQuery)
  79. if err != nil {
  80. return nil, err
  81. }
  82. } else {
  83. bytes, err = this.doWeChat(body, wxURL_SanBox_OrderQuery)
  84. if err != nil {
  85. return nil, err
  86. }
  87. }
  88. wxRsp = new(WeChatQueryOrderResponse)
  89. err = xml.Unmarshal(bytes, wxRsp)
  90. if err != nil {
  91. return nil, err
  92. }
  93. return wxRsp, nil
  94. }
  95. //关闭订单 ok
  96. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
  97. func (this *weChatClient) CloseOrder(body BodyMap) (wxRsp *WeChatCloseOrderResponse, err error) {
  98. var bytes []byte
  99. if this.isProd {
  100. //正式环境
  101. bytes, err = this.doWeChat(body, wxURL_CloseOrder)
  102. if err != nil {
  103. return nil, err
  104. }
  105. } else {
  106. bytes, err = this.doWeChat(body, wxURL_SanBox_CloseOrder)
  107. if err != nil {
  108. return nil, err
  109. }
  110. }
  111. wxRsp = new(WeChatCloseOrderResponse)
  112. err = xml.Unmarshal(bytes, wxRsp)
  113. if err != nil {
  114. return nil, err
  115. }
  116. return wxRsp, nil
  117. }
  118. //撤销订单 ok
  119. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
  120. func (this *weChatClient) Reverse(body BodyMap) (wxRsp *WeChatReverseResponse, err error) {
  121. var bytes []byte
  122. if this.isProd {
  123. //正式环境
  124. bytes, err = this.doWeChat(body, wxURL_Reverse)
  125. if err != nil {
  126. return nil, err
  127. }
  128. } else {
  129. bytes, err = this.doWeChat(body, wxURL_SanBox_Reverse)
  130. if err != nil {
  131. return nil, err
  132. }
  133. }
  134. wxRsp = new(WeChatReverseResponse)
  135. err = xml.Unmarshal(bytes, wxRsp)
  136. if err != nil {
  137. return nil, err
  138. }
  139. return wxRsp, nil
  140. }
  141. //申请退款 ok
  142. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
  143. func (this *weChatClient) Refund(body BodyMap) (wxRsp *WeChatRefundResponse, err error) {
  144. var bytes []byte
  145. if this.isProd {
  146. //正式环境
  147. bytes, err = this.doWeChat(body, wxURL_Refund)
  148. if err != nil {
  149. return nil, err
  150. }
  151. } else {
  152. bytes, err = this.doWeChat(body, wxURL_SanBox_Refund)
  153. if err != nil {
  154. return nil, err
  155. }
  156. }
  157. wxRsp = new(WeChatRefundResponse)
  158. err = xml.Unmarshal(bytes, wxRsp)
  159. if err != nil {
  160. return nil, err
  161. }
  162. return wxRsp, nil
  163. }
  164. //查询退款 ok
  165. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
  166. func (this *weChatClient) QueryRefund(body BodyMap) (wxRsp *WeChatQueryRefundResponse, err error) {
  167. var bytes []byte
  168. if this.isProd {
  169. //正式环境
  170. bytes, err = this.doWeChat(body, wxURL_RefundQuery)
  171. if err != nil {
  172. return nil, err
  173. }
  174. } else {
  175. bytes, err = this.doWeChat(body, wxURL_SanBox_RefundQuery)
  176. if err != nil {
  177. return nil, err
  178. }
  179. }
  180. wxRsp = new(WeChatQueryRefundResponse)
  181. err = xml.Unmarshal(bytes, wxRsp)
  182. if err != nil {
  183. return nil, err
  184. }
  185. return wxRsp, nil
  186. }
  187. //下载对账单 ok
  188. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6
  189. func (this *weChatClient) DownloadBill(body BodyMap) (wxRsp string, err error) {
  190. var bytes []byte
  191. if this.isProd {
  192. //正式环境
  193. bytes, err = this.doWeChat(body, wxURL_DownloadBill)
  194. } else {
  195. bytes, err = this.doWeChat(body, wxURL_SanBox_DownloadBill)
  196. }
  197. wxRsp = string(bytes)
  198. if err != nil {
  199. return wxRsp, err
  200. }
  201. return wxRsp, nil
  202. }
  203. //下载资金账单 ok
  204. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7
  205. // 好像不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
  206. func (this *weChatClient) DownloadFundFlow(body BodyMap) (wxRsp string, err error) {
  207. var bytes []byte
  208. if this.isProd {
  209. //正式环境
  210. bytes, err = this.doWeChat(body, wxURL_DownloadFundFlow)
  211. } else {
  212. bytes, err = this.doWeChat(body, wxURL_SanBox_DownloadFundFlow)
  213. }
  214. wxRsp = string(bytes)
  215. if err != nil {
  216. return wxRsp, err
  217. }
  218. return wxRsp, nil
  219. }
  220. //拉取订单评价数据
  221. // 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
  222. // 好像不支持沙箱环境,因为沙箱环境默认需要用MD5签名,但是此接口仅支持HMAC-SHA256签名
  223. func (this *weChatClient) BatchQueryComment(body BodyMap) (wxRsp string, err error) {
  224. var bytes []byte
  225. if this.isProd {
  226. //正式环境
  227. body.Set("sign_type", SignType_HMAC_SHA256)
  228. bytes, err = this.doWeChat(body, wxURL_BatchQueryComment)
  229. } else {
  230. bytes, err = this.doWeChat(body, wxURL_SanBox_BatchQueryComment)
  231. }
  232. wxRsp = string(bytes)
  233. if err != nil {
  234. return wxRsp, err
  235. }
  236. return wxRsp, nil
  237. }
  238. //向微信发送请求 ok
  239. func (this *weChatClient) doWeChat(body BodyMap, url string) (bytes []byte, err error) {
  240. var sign string
  241. body.Set("appid", this.AppId)
  242. body.Set("mch_id", this.MchId)
  243. //===============生成参数===================
  244. if !this.isProd {
  245. //沙箱环境
  246. body.Set("sign_type", SignType_MD5)
  247. //从微信接口获取SanBoxSignKey
  248. key, err := getSanBoxSign(this.MchId, body.Get("nonce_str"), this.secretKey, body.Get("sign_type"))
  249. if err != nil {
  250. return nil, err
  251. }
  252. sign = getLocalSign(key, body.Get("sign_type"), body)
  253. } else {
  254. //正式环境
  255. //本地计算Sign
  256. sign = getLocalSign(this.secretKey, body.Get("sign_type"), body)
  257. }
  258. body.Set("sign", sign)
  259. reqXML := generateXml(body)
  260. //===============发起请求===================
  261. agent := gorequest.New()
  262. if this.isProd {
  263. agent.Post(url)
  264. } else {
  265. agent.Post(url)
  266. }
  267. agent.Type("xml")
  268. agent.SendString(reqXML)
  269. _, bytes, errs := agent.EndBytes()
  270. if len(errs) > 0 {
  271. return nil, errs[0]
  272. }
  273. return bytes, nil
  274. }