|
@@ -0,0 +1,131 @@
|
|
|
|
|
+package redpacket
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "encoding/xml"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "strconv"
|
|
|
|
|
+
|
|
|
|
|
+ "github.com/silenceper/wechat/v2/pay/config"
|
|
|
|
|
+ "github.com/silenceper/wechat/v2/util"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// redpacketGateway 发放红包接口
|
|
|
|
|
+// https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
|
|
|
|
|
+var redpacketGateway = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"
|
|
|
|
|
+
|
|
|
|
|
+// Redpacket struct extends context
|
|
|
|
|
+type Redpacket struct {
|
|
|
|
|
+ *config.Config
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// NewRedpacket return an instance of Redpacket package
|
|
|
|
|
+func NewRedpacket(cfg *config.Config) *Redpacket {
|
|
|
|
|
+ return &Redpacket{cfg}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Params 调用参数
|
|
|
|
|
+type Params struct {
|
|
|
|
|
+ MchBillno string // 商户订单号
|
|
|
|
|
+ SendName string // 商户名称
|
|
|
|
|
+ ReOpenID string
|
|
|
|
|
+ TotalAmount int
|
|
|
|
|
+ TotalNum int
|
|
|
|
|
+ Wishing string
|
|
|
|
|
+ ClientIP string
|
|
|
|
|
+ ActName string
|
|
|
|
|
+ Remark string
|
|
|
|
|
+
|
|
|
|
|
+ RootCa string // ca证书
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// request 接口请求参数
|
|
|
|
|
+type request struct {
|
|
|
|
|
+ NonceStr string `xml:"nonce_str"`
|
|
|
|
|
+ Sign string `xml:"sign"`
|
|
|
|
|
+ MchID string `xml:"mch_id"`
|
|
|
|
|
+ MchBillno string `xml:"mch_billno"`
|
|
|
|
|
+ Wxappid string `xml:"wxappid"`
|
|
|
|
|
+ SendName string `xml:"send_name"`
|
|
|
|
|
+ ReOpenID string `xml:"re_openid"`
|
|
|
|
|
+ TotalAmount int `xml:"total_amount"`
|
|
|
|
|
+ TotalNum int `xml:"total_num"`
|
|
|
|
|
+ Wishing string `xml:"wishing"`
|
|
|
|
|
+ ClientIP string `xml:"client_ip"`
|
|
|
|
|
+ ActName string `xml:"act_name"`
|
|
|
|
|
+ Remark string `xml:"remark"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Response 接口返回
|
|
|
|
|
+type Response struct {
|
|
|
|
|
+ ReturnCode string `xml:"return_code"`
|
|
|
|
|
+ ReturnMsg string `xml:"return_msg"`
|
|
|
|
|
+ ResultCode string `xml:"result_code,omitempty"`
|
|
|
|
|
+ ErrCode string `xml:"err_code,omitempty"`
|
|
|
|
|
+ ErrCodeDes string `xml:"err_code_des,omitempty"`
|
|
|
|
|
+ MchBillno string `xml:"mch_billno,omitempty"`
|
|
|
|
|
+ MchID string `xml:"mch_id,omitempty"`
|
|
|
|
|
+ Wxappid string `xml:"wxappid"`
|
|
|
|
|
+ ReOpenID string `xml:"re_openid"`
|
|
|
|
|
+ TotalAmount int `xml:"total_amount"`
|
|
|
|
|
+ SendListid string `xml:"send_listid"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// SendRedpacket 发放红包
|
|
|
|
|
+func (redpacket *Redpacket) SendRedpacket(p *Params) (rsp *Response, err error) {
|
|
|
|
|
+ nonceStr := util.RandomStr(32)
|
|
|
|
|
+ param := make(map[string]string)
|
|
|
|
|
+
|
|
|
|
|
+ param["nonce_str"] = nonceStr
|
|
|
|
|
+ param["mch_id"] = redpacket.MchID
|
|
|
|
|
+ param["wxappid"] = redpacket.AppID
|
|
|
|
|
+ param["mch_billno"] = p.MchBillno
|
|
|
|
|
+ param["send_name"] = p.SendName
|
|
|
|
|
+ param["re_openid"] = p.ReOpenID
|
|
|
|
|
+ param["total_amount"] = strconv.Itoa(p.TotalAmount)
|
|
|
|
|
+ param["total_num"] = strconv.Itoa(p.TotalNum)
|
|
|
|
|
+ param["wishing"] = p.Wishing
|
|
|
|
|
+ param["client_ip"] = p.ClientIP
|
|
|
|
|
+ param["act_name"] = p.ActName
|
|
|
|
|
+ param["remark"] = p.Remark
|
|
|
|
|
+ //param["scene_id"] = "PRODUCT_2"
|
|
|
|
|
+
|
|
|
|
|
+ sign, err := util.ParamSign(param, redpacket.Key)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ req := request{
|
|
|
|
|
+ NonceStr: nonceStr,
|
|
|
|
|
+ Sign: sign,
|
|
|
|
|
+ MchID: redpacket.MchID,
|
|
|
|
|
+ Wxappid: redpacket.AppID,
|
|
|
|
|
+ MchBillno: p.MchBillno,
|
|
|
|
|
+ SendName: p.SendName,
|
|
|
|
|
+ ReOpenID: p.ReOpenID,
|
|
|
|
|
+ TotalAmount: p.TotalAmount,
|
|
|
|
|
+ TotalNum: p.TotalNum,
|
|
|
|
|
+ Wishing: p.Wishing,
|
|
|
|
|
+ ClientIP: p.ClientIP,
|
|
|
|
|
+ ActName: p.ActName,
|
|
|
|
|
+ Remark: p.Remark,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rawRet, err := util.PostXMLWithTLS(redpacketGateway, req, p.RootCa, redpacket.MchID)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ err = xml.Unmarshal(rawRet, &rsp)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if rsp.ReturnCode == "SUCCESS" {
|
|
|
|
|
+ if rsp.ResultCode == "SUCCESS" {
|
|
|
|
|
+ err = nil
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ err = fmt.Errorf("send redpacket error, errcode=%s,errmsg=%s", rsp.ErrCode, rsp.ErrCodeDes)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ err = fmt.Errorf("[msg : xmlUnmarshalError] [rawReturn : %s] [sign : %s]", string(rawRet), sign)
|
|
|
|
|
+ return
|
|
|
|
|
+}
|