refund.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package wechat
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "errors"
  6. "fmt"
  7. "git.chuangxin1.com/cx/util"
  8. )
  9. /*
  10. 退款示例:
  11. <xml>
  12. <appid>wx2421b1c4370ec43b</appid>
  13. <mch_id>10000100</mch_id>
  14. <nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str>
  15. <out_refund_no>1415701182</out_refund_no>
  16. <out_trade_no>1415757673</out_trade_no>
  17. <refund_fee>1</refund_fee>
  18. <total_fee>1</total_fee>
  19. <transaction_id>4006252001201705123297353072</transaction_id>
  20. <sign>FE56DD4AA85C0EECA82C35595A69E153</sign>
  21. </xml>
  22. //*/
  23. // WePayRefund https://api.mch.weixin.qq.com/secapi/pay/refund
  24. type WePayRefund struct {
  25. XMLName xml.Name `xml:"xml"`
  26. AppID string `xml:"appid"` // 公众账号 ID string(32)
  27. MchID string `xml:"mch_id"` // 商户号 string(32)
  28. NonceStr string `xml:"nonce_str"` // 随机字符串 string(32)
  29. Sign string `xml:"sign"` // 签名 string(32)
  30. //SignType string `xml:"sign_type"` // 签名类型, 默认 MD5 string(32), HMAC-SHA256 和 MD5
  31. OutTradeNo string `xml:"out_trade_no"` // 商户订单号
  32. OutRefundNo string `xml:"out_refund_no"` // 商户退款单号
  33. TotalFee int `xml:"total_fee"` // 订单金额
  34. RefundFee int `xml:"refund_fee"` // 退款金额
  35. //RefundFeeType string `xml:"refund_fee_type"` // 退款货币种类, 款货币类型,需与支付一致,或者不填。符合ISO 4217标准的三位字母代码,默认人民币:CNY
  36. NotifyURL string `xml:"notify_url"` // 退款结果通知 url, 异步接收微信支付退款结果通知的回调地址,通知URL必须为外网可访问的url,不允许带参数。如果参数中传了notify_url,则商户平台上配置的回调地址将不会生效
  37. }
  38. // WePayRefundReply pay refund reply
  39. type WePayRefundReply struct {
  40. XMLName xml.Name `xml:"xml" json:"_,omitempty"`
  41. ReturnCode string `xml:"return_code"`
  42. ReturnMsg string `xml:"return_msg"`
  43. ResultCode string `xml:"result_code"`
  44. ErrCode string `xml:"err_code"`
  45. ErrCodeDes string `xml:"err_code_des"`
  46. AppID string `xml:"appid"`
  47. MchID string `xml:"mch_id"`
  48. NonceStr string `xml:"nonce_str"`
  49. Sign string `xml:"sign"`
  50. TransactionID string `xml:"transaction_id"`
  51. OutTradeNo string `xml:"out_trade_no"`
  52. OutRefundNo string `xml:"out_refund_no"`
  53. RefundFee int `xml:"refund_fee"` // 退款金额
  54. TotalFee int `xml:"total_fee"` // 标价金额, 订单总金额,单位为分,只能为整数
  55. FeeType int `xml:"fee_type"` // 退款货币种类, 款货币类型,需与支付一致,或者不填。符合ISO 4217标准的三位字母代码,默认人民币:CNY
  56. CashFee int `xml:"cash_fee"` // 现金支付金额
  57. }
  58. // PayRefundCheck check refund reply
  59. func PayRefundCheck(reply WePayRefundReply) (ok bool, err error) {
  60. // 通信是否正确
  61. if reply.ReturnCode == "FAIL" {
  62. err = errors.New(reply.ReturnMsg)
  63. return
  64. }
  65. // 交易是否成功
  66. if reply.ResultCode == "FAIL" {
  67. err = errors.New(reply.ErrCodeDes)
  68. return
  69. }
  70. ok = true
  71. return
  72. }
  73. // PayRefund 退款
  74. func PayRefund(config WePayConfig, order WePayRefund) (reply WePayRefundReply, err error) {
  75. var data []byte
  76. m := make(map[string]interface{})
  77. m["appid"] = order.AppID
  78. m["mch_id"] = order.MchID
  79. m["nonce_str"] = order.NonceStr
  80. m["total_fee"] = order.TotalFee
  81. m["out_trade_no"] = order.OutTradeNo
  82. m["out_refund_no"] = order.OutRefundNo
  83. m["total_fee"] = order.TotalFee
  84. m["refund_fee"] = order.RefundFee
  85. m["notify_url"] = order.NotifyURL
  86. //order.SignType = `MD5`
  87. order.Sign = Sign(m, config.Key)
  88. if data, err = xml.Marshal(order); err != nil {
  89. return
  90. }
  91. fmt.Println(string(data))
  92. url := WePayHost + WePayURLPayRefund
  93. reply, err = postRefund(url, config.SSLCert, config.SSLKey, data)
  94. bs, _ := xml.Marshal(reply)
  95. fmt.Println(string(bs))
  96. return
  97. }
  98. func postRefund(url, cert, key string, data []byte) (reply WePayRefundReply, err error) {
  99. var (
  100. msg util.Message
  101. headers = make(map[string]string)
  102. )
  103. headers["Accept"] = "application/xml"
  104. headers["Content-Type"] = "application/xml; charset=utf-8"
  105. msg, err = util.Post(url, cert, key, headers, bytes.NewReader(data))
  106. if err != nil {
  107. fmt.Println("util.Post", err)
  108. return
  109. }
  110. fmt.Println(string(msg.Body))
  111. err = xml.Unmarshal(msg.Body, &reply)
  112. return
  113. }