pay.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package wechat
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "errors"
  6. "fmt"
  7. "git.chuangxin1.com/cx/util"
  8. )
  9. const (
  10. // WePayHost base host
  11. WePayHost = `https://api.mch.weixin.qq.com`
  12. // WePayURLUnifiedOrder pay 付款
  13. WePayURLUnifiedOrder = `/pay/unifiedorder`
  14. // WePayURLUnifiedQuery order query 订单查询
  15. WePayURLUnifiedQuery = `/pay/orderquery`
  16. // WePayURLPayRefund pay refund 退款
  17. WePayURLPayRefund = `/secapi/pay/refund`
  18. // WePayURLPapPay 委托代扣申请扣款
  19. WePayURLPapPay = `/pay/pappayapply`
  20. // WePayURLPapayEntrust H5 纯签约
  21. WePayURLPapayEntrust = `/papay/h5entrustweb`
  22. // WePayTradeTypeJS JSAPI 公众号支付
  23. WePayTradeTypeJS = `JSAPI`
  24. // WePayTradeTypeNative NATIVE 扫码支付
  25. WePayTradeTypeNative = `NATIVE`
  26. // WePayTradeTypeAPP APP APP支付
  27. WePayTradeTypeAPP = `APP`
  28. // WeOrderPaySuccess pay ok
  29. WeOrderPaySuccess = 0
  30. )
  31. // WePayConfig WeChat pay configure
  32. type WePayConfig struct {
  33. AppID string `json:"appid"`
  34. MchID string `json:"mchid"`
  35. Key string `json:"key"`
  36. AppSecret string `json:"appsecret"`
  37. SSLCert string `json:"sslcert"`
  38. SSLKey string `json:"sslkey"`
  39. ContractID string `json:"contractid"`
  40. NotifyURL string `json:"notify_url"`
  41. }
  42. // UnifiedOrder https://api.mch.weixin.qq.com/pay/unifiedorder
  43. type UnifiedOrder struct {
  44. XMLName xml.Name `xml:"xml"`
  45. AppID string `xml:"appid"`
  46. MchID string `xml:"mch_id"`
  47. Body string `xml:"body"`
  48. NonceStr string `xml:"nonce_str"`
  49. NotifyURL string `xml:"notify_url"`
  50. TradeType string `xml:"trade_type"`
  51. OpenID string `xml:"openid"`
  52. SpbillCreateIP string `xml:"spbill_create_ip"`
  53. TimeStart string `xml:"time_start"`
  54. TotalFee int `xml:"total_fee"`
  55. OutTradeNo string `xml:"out_trade_no"`
  56. Attach string `xml:"attach"`
  57. Sign string `xml:"sign"`
  58. }
  59. // OrderQuery https://api.mch.weixin.qq.com/pay/orderquery
  60. type OrderQuery struct {
  61. XMLName xml.Name `xml:"xml"`
  62. AppID string `xml:"appid"`
  63. MchID string `xml:"mch_id"`
  64. NonceStr string `xml:"nonce_str"`
  65. TransactionID string `xml:"transaction_id,omitempty"`
  66. OutTradeNo string `xml:"out_trade_no,omitempty"`
  67. Sign string `xml:"sign"`
  68. }
  69. /*
  70. <xml><appid><![CDATA[wx0e9caf2ab1fcd508]]></appid>
  71. <attach><![CDATA[邦泰商旅]]></attach>
  72. <bank_type><![CDATA[CITIC_CREDIT]]></bank_type>
  73. <cash_fee><![CDATA[349000]]></cash_fee>
  74. <fee_type><![CDATA[CNY]]></fee_type>
  75. <is_subscribe><![CDATA[N]]></is_subscribe>
  76. <mch_id><![CDATA[1340131101]]></mch_id>
  77. <nonce_str><![CDATA[0gwbd25n61bxkw6m64kj4ovf60i2q2sg]]></nonce_str>
  78. <openid><![CDATA[o7-PevpkcTqeJOkOF4X7VFhX_SwY]]></openid>
  79. <out_trade_no><![CDATA[134013110120180709134447]]></out_trade_no>
  80. <result_code><![CDATA[SUCCESS]]></result_code>
  81. <return_code><![CDATA[SUCCESS]]></return_code>
  82. <sign><![CDATA[8E581E734384DB2EA6FC08B1482BCCFC]]></sign>
  83. <time_end><![CDATA[20180709134502]]></time_end>
  84. <total_fee>349000</total_fee>
  85. <trade_type><![CDATA[JSAPI]]></trade_type>
  86. <transaction_id><![CDATA[4200000120201807096318807841]]></transaction_id>
  87. </xml>
  88. <xml>
  89. <return_code>SUCCESS</return_code>
  90. <return_msg></return_msg>
  91. <appid>wx84998d72abc5970a</appid>
  92. <mch_id>1511843111</mch_id>
  93. <nonce_str>1534475690</nonce_str>
  94. <sign>27577C258DD809DCE0F8A515233494D1</sign>
  95. <result_code>SUCCESS</result_code>
  96. <prepay_id></prepay_id>
  97. <trade_type>JSAPI</trade_type>
  98. <code_url></code_url>
  99. <err_code></err_code>
  100. <err_code_des></err_code_des>
  101. <openid>opCl81S2TyHPx7IJRZxc2yGrom5E</openid>
  102. <attach>{&#34;PlaceNo&#34;:&#34;603009&#34;,&#34;VNO&#34;:&#34;&#34;,&#34;Start&#34;:&#34;2018-08-17 11:14:50&#34;</attach>
  103. <is_subscribe>Y</is_subscribe>
  104. <bank_type>CFT</bank_type>
  105. <cash_fee>2</cash_fee>
  106. <fee_type>CNY</fee_type>
  107. <out_trade_no>1534475690957535612</out_trade_no>
  108. <time_end>20180817111506</time_end>
  109. <total_fee>2</total_fee>
  110. <trade_state></trade_state>
  111. <trade_state_desc></trade_state_desc>
  112. <transaction_id>4200000159201808174345835044</transaction_id>
  113. </xml>
  114. // */
  115. // FormWePayNotify notify
  116. type FormWePayNotify struct {
  117. XMLName xml.Name `xml:"xml" json:"_,omitempty"`
  118. AppID string `form:"appid" xml:"appid"`
  119. Attach string `form:"attach" xml:"attach"`
  120. BankType string `form:"bank_type" xml:"bank_type"`
  121. CashFee int `form:"cash_fee" xml:"cash_fee"`
  122. FeeType string `form:"fee_type" xml:"fee_type"`
  123. MchID string `form:"mch_id" xml:"mch_id"`
  124. IsSubscribe string `form:"is_subscribe" xml:"is_subscribe"`
  125. NonceStr string `form:"nonce_str" xml:"nonce_str"`
  126. OpenID string `form:"openid" xml:"openid"`
  127. OutTradeNo string `form:"out_trade_no" xml:"out_trade_no"`
  128. ResultCode string `form:"result_code" xml:"result_code"`
  129. ReturnMsg string `form:"return_msg" xml:"return_msg"`
  130. ReturnCode string `form:"return_code" xml:"return_code"`
  131. ErrCodeDes string `form:"err_code_des" xml:"err_code_des"`
  132. ErrCode string `form:"err_code" xml:"err_code"`
  133. Sign string `form:"sign" xml:"sign"`
  134. TimeEnd string `form:"time_end" xml:"time_end"`
  135. TotalFee int `form:"total_fee" xml:"total_fee"`
  136. TradeType string `form:"trade_type" xml:"trade_type"`
  137. TransactionID string `form:"transaction_id" xml:"transaction_id"`
  138. ContractID string `form:"contract_id" xml:"contract_id"`
  139. }
  140. // WePayReply pay reply
  141. type WePayReply struct {
  142. XMLName xml.Name `xml:"xml" json:"_,omitempty"`
  143. ReturnCode string `xml:"return_code"`
  144. ReturnMsg string `xml:"return_msg"`
  145. AppID string `xml:"appid"`
  146. MchID string `xml:"mch_id"`
  147. NonceStr string `xml:"nonce_str"`
  148. Sign string `xml:"sign"`
  149. ResultCode string `xml:"result_code"`
  150. PrePayID string `xml:"prepay_id"`
  151. TradeType string `xml:"trade_type"`
  152. URL string `xml:"code_url"`
  153. ErrCode string `xml:"err_code"`
  154. ErrCodeDes string `xml:"err_code_des"`
  155. OpenID string `xml:"openid"`
  156. Attach string `xml:"attach"`
  157. IsSubscribe string `xml:"is_subscribe"`
  158. BankType string `xml:"bank_type"`
  159. CashFee string `xml:"cash_fee"`
  160. FeeType string `xml:"fee_type"`
  161. OutTradeNo string `xml:"out_trade_no"`
  162. TimeEnd string `xml:"time_end"`
  163. TotalFee string `xml:"total_fee"`
  164. TradeState string `xml:"trade_state"`
  165. TradeStateDesc string `xml:"trade_state_desc"`
  166. TransactionID string `xml:"transaction_id"`
  167. ContractID string `form:"contract_id" xml:"contract_id"`
  168. }
  169. var (
  170. // WePayTradeState 交易状态
  171. WePayTradeState = map[string]int{"SUCCESS": 0, "REFUND": 2, "NOTPAY": 3, "CLOSED": 4, "REVOKED": 5, "USERPAYING": 6, "PAYERROR": 7}
  172. )
  173. // PayCheck check reply
  174. func PayCheck(reply WePayReply) (ok bool, err error) {
  175. // 通信是否正确
  176. if reply.ReturnCode == "FAIL" {
  177. err = errors.New(reply.ReturnMsg)
  178. return
  179. }
  180. // 交易是否成功
  181. if reply.ResultCode == "FAIL" {
  182. err = errors.New(reply.ErrCodeDes)
  183. return
  184. }
  185. ok = true
  186. return
  187. }
  188. // PayNotifyCheck check reply
  189. func PayNotifyCheck(reply FormWePayNotify) (ok bool, err error) {
  190. // 通信是否正确
  191. if reply.ReturnCode == "FAIL" {
  192. err = errors.New(reply.ReturnMsg)
  193. return
  194. }
  195. // 交易是否成功
  196. if reply.ResultCode == "FAIL" {
  197. err = errors.New(reply.ErrCodeDes)
  198. return
  199. }
  200. ok = true
  201. return
  202. }
  203. // PayQuery order query
  204. func PayQuery(cpyid int, config WePayConfig, order OrderQuery) (reply WePayReply, err error) {
  205. m := make(map[string]interface{})
  206. m["appid"] = order.AppID
  207. m["mch_id"] = order.MchID
  208. m["out_trade_no"] = order.OutTradeNo
  209. m["nonce_str"] = order.NonceStr
  210. //m["transaction_id"] = order.TransactionID
  211. var (
  212. data []byte
  213. )
  214. order.Sign = Sign(m, config.Key)
  215. data, err = xml.Marshal(order)
  216. if err != nil {
  217. return
  218. }
  219. reply, err = post(WePayHost+WePayURLUnifiedQuery, data)
  220. return
  221. }
  222. // Pay pay
  223. func Pay(config WePayConfig, order UnifiedOrder) (reply WePayReply, err error) {
  224. m := make(map[string]interface{})
  225. m["appid"] = order.AppID
  226. m["mch_id"] = order.MchID
  227. m["body"] = order.Body
  228. m["notify_url"] = order.NotifyURL
  229. m["trade_type"] = order.TradeType
  230. m["spbill_create_ip"] = order.SpbillCreateIP
  231. m["total_fee"] = order.TotalFee
  232. m["out_trade_no"] = order.OutTradeNo
  233. m["nonce_str"] = order.NonceStr
  234. m["attach"] = order.Attach
  235. m["time_start"] = order.TimeStart
  236. m["openid"] = order.OpenID
  237. var data []byte
  238. order.Sign = Sign(m, config.Key)
  239. if data, err = xml.Marshal(order); err != nil {
  240. return
  241. }
  242. reply, err = post(WePayHost+WePayURLUnifiedOrder, data)
  243. return
  244. }
  245. func post(url string, data []byte) (reply WePayReply, err error) {
  246. var (
  247. msg util.Message
  248. headers = make(map[string]string)
  249. )
  250. headers["Accept"] = "application/xml"
  251. headers["Content-Type"] = "application/xml; charset=utf-8"
  252. msg, err = util.Post(url, "", "", headers, bytes.NewReader(data))
  253. if err != nil {
  254. return
  255. }
  256. fmt.Println("************Response************")
  257. fmt.Println(string(msg.Body))
  258. fmt.Println("************ResponseEnd************")
  259. err = xml.Unmarshal(msg.Body, &reply)
  260. return
  261. }