transfer_wallet.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package transfer
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. "strconv"
  6. "github.com/silenceper/wechat/v2/pay/config"
  7. "github.com/silenceper/wechat/v2/util"
  8. )
  9. // 付款到零钱
  10. // https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
  11. var walletTransferGateway = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"
  12. // Transfer struct extends context
  13. type Transfer struct {
  14. *config.Config
  15. }
  16. // NewTransfer return an instance of Transfer package
  17. func NewTransfer(cfg *config.Config) *Transfer {
  18. transfer := Transfer{cfg}
  19. return &transfer
  20. }
  21. // Params 调用参数
  22. type Params struct {
  23. DeviceInfo string
  24. PartnerTradeNo string
  25. OpenID string
  26. CheckName bool
  27. ReUserName string
  28. Amount int
  29. Desc string
  30. SpbillCreateIP string
  31. RootCa string // ca证书
  32. }
  33. // request 接口请求参数
  34. type request struct {
  35. AppID string `xml:"mch_appid"`
  36. MchID string `xml:"mchid"`
  37. NonceStr string `xml:"nonce_str"`
  38. Sign string `xml:"sign"`
  39. DeviceInfo string `xml:"device_info,omitempty"`
  40. PartnerTradeNo string `xml:"partner_trade_no"`
  41. OpenID string `xml:"openid"`
  42. CheckName string `xml:"check_name"`
  43. ReUserName string `xml:"re_user_name,omitempty"`
  44. Amount int `xml:"amount"`
  45. Desc string `xml:"desc"`
  46. SpbillCreateIP string `xml:"spbill_create_ip,omitempty"`
  47. }
  48. // Response 接口返回
  49. type Response struct {
  50. ReturnCode string `xml:"return_code"`
  51. ReturnMsg string `xml:"return_msg"`
  52. AppID string `xml:"appid,omitempty"`
  53. MchID string `xml:"mch_id,omitempty"`
  54. DeviceInfo string `xml:"device_info,omitempty"`
  55. NonceStr string `xml:"nonce_str,omitempty"`
  56. ResultCode string `xml:"result_code,omitempty"`
  57. ErrCode string `xml:"err_code,omitempty"`
  58. ErrCodeDes string `xml:"err_code_des,omitempty"`
  59. PartnerTradeNo string `xml:"partner_trade_no"`
  60. PaymentNo string `xml:"payment_no"`
  61. PaymentTime string `xml:"payment_time"`
  62. }
  63. // WalletTransfer 付款到零钱
  64. func (transfer *Transfer) WalletTransfer(p *Params) (rsp *Response, err error) {
  65. nonceStr := util.RandomStr(32)
  66. param := make(map[string]string)
  67. param["mch_appid"] = transfer.AppID
  68. param["mchid"] = transfer.MchID
  69. param["nonce_str"] = nonceStr
  70. param["partner_trade_no"] = p.PartnerTradeNo
  71. param["openid"] = p.OpenID
  72. param["amount"] = strconv.Itoa(p.Amount)
  73. param["desc"] = p.Desc
  74. if p.DeviceInfo != "" {
  75. param["device_info"] = p.DeviceInfo
  76. }
  77. param["check_name"] = "NO_CHECK"
  78. if p.CheckName {
  79. param["check_name"] = "FORCE_CHECK"
  80. param["re_user_name"] = p.ReUserName
  81. }
  82. if p.SpbillCreateIP != "" {
  83. param["spbill_create_ip"] = p.SpbillCreateIP
  84. }
  85. sign, err := util.ParamSign(param, transfer.Key)
  86. if err != nil {
  87. return
  88. }
  89. req := request{
  90. AppID: transfer.AppID,
  91. MchID: transfer.MchID,
  92. NonceStr: nonceStr,
  93. Sign: sign,
  94. DeviceInfo: p.DeviceInfo,
  95. PartnerTradeNo: p.PartnerTradeNo,
  96. OpenID: p.OpenID,
  97. Amount: p.Amount,
  98. Desc: p.Desc,
  99. SpbillCreateIP: p.SpbillCreateIP,
  100. }
  101. req.CheckName = "NO_CHECK"
  102. if p.CheckName {
  103. req.CheckName = "FORCE_CHECK"
  104. req.ReUserName = p.ReUserName
  105. }
  106. rawRet, err := util.PostXMLWithTLS(walletTransferGateway, req, p.RootCa, transfer.MchID)
  107. if err != nil {
  108. return
  109. }
  110. err = xml.Unmarshal(rawRet, &rsp)
  111. if err != nil {
  112. return
  113. }
  114. if rsp.ReturnCode == "SUCCESS" {
  115. if rsp.ResultCode == "SUCCESS" {
  116. err = nil
  117. return
  118. }
  119. err = fmt.Errorf("transfer error, errcode=%s,errmsg=%s", rsp.ErrCode, rsp.ErrCodeDes)
  120. return
  121. }
  122. err = fmt.Errorf("[msg : xmlUnmarshalError] [rawReturn : %s] [sign : %s]", string(rawRet), sign)
  123. return
  124. }