redpacket.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package redpacket
  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. // redpacketGateway 发放红包接口
  10. // https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
  11. var redpacketGateway = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"
  12. // Redpacket struct extends context
  13. type Redpacket struct {
  14. *config.Config
  15. }
  16. // NewRedpacket return an instance of Redpacket package
  17. func NewRedpacket(cfg *config.Config) *Redpacket {
  18. return &Redpacket{cfg}
  19. }
  20. // Params 调用参数
  21. type Params struct {
  22. MchBillno string // 商户订单号
  23. SendName string // 商户名称
  24. ReOpenID string
  25. TotalAmount int
  26. TotalNum int
  27. Wishing string
  28. ClientIP string
  29. ActName string
  30. Remark string
  31. RootCa string // ca证书
  32. }
  33. // request 接口请求参数
  34. type request struct {
  35. NonceStr string `xml:"nonce_str"`
  36. Sign string `xml:"sign"`
  37. MchID string `xml:"mch_id"`
  38. MchBillno string `xml:"mch_billno"`
  39. Wxappid string `xml:"wxappid"`
  40. SendName string `xml:"send_name"`
  41. ReOpenID string `xml:"re_openid"`
  42. TotalAmount int `xml:"total_amount"`
  43. TotalNum int `xml:"total_num"`
  44. Wishing string `xml:"wishing"`
  45. ClientIP string `xml:"client_ip"`
  46. ActName string `xml:"act_name"`
  47. Remark string `xml:"remark"`
  48. }
  49. // Response 接口返回
  50. type Response struct {
  51. ReturnCode string `xml:"return_code"`
  52. ReturnMsg string `xml:"return_msg"`
  53. ResultCode string `xml:"result_code,omitempty"`
  54. ErrCode string `xml:"err_code,omitempty"`
  55. ErrCodeDes string `xml:"err_code_des,omitempty"`
  56. MchBillno string `xml:"mch_billno,omitempty"`
  57. MchID string `xml:"mch_id,omitempty"`
  58. Wxappid string `xml:"wxappid"`
  59. ReOpenID string `xml:"re_openid"`
  60. TotalAmount int `xml:"total_amount"`
  61. SendListid string `xml:"send_listid"`
  62. }
  63. // SendRedpacket 发放红包
  64. func (redpacket *Redpacket) SendRedpacket(p *Params) (rsp *Response, err error) {
  65. nonceStr := util.RandomStr(32)
  66. param := make(map[string]string)
  67. param["nonce_str"] = nonceStr
  68. param["mch_id"] = redpacket.MchID
  69. param["wxappid"] = redpacket.AppID
  70. param["mch_billno"] = p.MchBillno
  71. param["send_name"] = p.SendName
  72. param["re_openid"] = p.ReOpenID
  73. param["total_amount"] = strconv.Itoa(p.TotalAmount)
  74. param["total_num"] = strconv.Itoa(p.TotalNum)
  75. param["wishing"] = p.Wishing
  76. param["client_ip"] = p.ClientIP
  77. param["act_name"] = p.ActName
  78. param["remark"] = p.Remark
  79. //param["scene_id"] = "PRODUCT_2"
  80. sign, err := util.ParamSign(param, redpacket.Key)
  81. if err != nil {
  82. return
  83. }
  84. req := request{
  85. NonceStr: nonceStr,
  86. Sign: sign,
  87. MchID: redpacket.MchID,
  88. Wxappid: redpacket.AppID,
  89. MchBillno: p.MchBillno,
  90. SendName: p.SendName,
  91. ReOpenID: p.ReOpenID,
  92. TotalAmount: p.TotalAmount,
  93. TotalNum: p.TotalNum,
  94. Wishing: p.Wishing,
  95. ClientIP: p.ClientIP,
  96. ActName: p.ActName,
  97. Remark: p.Remark,
  98. }
  99. rawRet, err := util.PostXMLWithTLS(redpacketGateway, req, p.RootCa, redpacket.MchID)
  100. if err != nil {
  101. return
  102. }
  103. err = xml.Unmarshal(rawRet, &rsp)
  104. if err != nil {
  105. return
  106. }
  107. if rsp.ReturnCode == "SUCCESS" {
  108. if rsp.ResultCode == "SUCCESS" {
  109. err = nil
  110. return
  111. }
  112. err = fmt.Errorf("send redpacket error, errcode=%s,errmsg=%s", rsp.ErrCode, rsp.ErrCodeDes)
  113. return
  114. }
  115. err = fmt.Errorf("[msg : xmlUnmarshalError] [rawReturn : %s] [sign : %s]", string(rawRet), sign)
  116. return
  117. }