redpack.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package paytool
  2. import (
  3. "errors"
  4. "fmt"
  5. "time"
  6. "github.com/astaxie/beego"
  7. "github.com/yaotian/gowechat/mch/base"
  8. "github.com/yaotian/gowechat/util"
  9. )
  10. //官方文档: https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
  11. var (
  12. //ErrNoEnoughMoney 商户平台上的余额不足,给用户发不了红包
  13. ErrNoEnoughMoney = errors.New("No enough money")
  14. )
  15. const (
  16. //SceneIDPromotion 商品促销
  17. SceneIDPromotion = "PRODUCT_1"
  18. //SceneIDLuckyDraw 抽奖
  19. SceneIDLuckyDraw = "PRODUCT_2"
  20. //SceneIDPrize 虚拟物品兑奖
  21. SceneIDPrize = "PRODUCT_3"
  22. //SceneIDBenefit 企业内部福利
  23. SceneIDBenefit = "PRODUCT_4"
  24. //SceneIDAgentBonous 渠道分润
  25. SceneIDAgentBonous = "PRODUCT_5"
  26. //SceneIDInsurance 保险回馈
  27. SceneIDInsurance = "PRODUCT_6"
  28. //SceneIDLottery 彩票派奖
  29. SceneIDLottery = "PRODUCT_7"
  30. //SceneIDTax 税务刮奖
  31. SceneIDTax = "PRODUCT_8"
  32. )
  33. //RedPackInput 发红包的配置
  34. type RedPackInput struct {
  35. ToOpenID string //接红包的OpenID
  36. MoneyFen int //分为单位
  37. SendName string //商户名称,String(32) 谁发的红包,一般为发红包的单位
  38. Wishing string //红包祝福语 String(128) “感谢您参加猜灯谜活动,祝您元宵节快乐!”
  39. ActName string //活动名称 String(32) 猜灯谜抢红包活动
  40. Remark string //备注 String(256)
  41. IP string
  42. //非必填,但大于200元,此必填, 有8个选项可供选择
  43. SceneID string
  44. }
  45. //Check check input
  46. func (m *RedPackInput) Check() (isGood bool, err error) {
  47. if m.ToOpenID == "" || m.MoneyFen == 0 || m.SendName == "" || m.Wishing == "" || m.ActName == "" || m.Remark == "" || m.IP == "" {
  48. err = fmt.Errorf("%s", "Input有必填项没有值")
  49. return
  50. }
  51. if m.MoneyFen >= 200*100 && m.SceneID == "" {
  52. err = fmt.Errorf("%s", "大于200元的红包,必须设置SceneID")
  53. return
  54. }
  55. return true, nil
  56. }
  57. //SendRedPack 发红包
  58. func (c *PayTool) SendRedPack(input RedPackInput) (isSuccess bool, err error) {
  59. if isGood, err := input.Check(); !isGood {
  60. return false, err
  61. }
  62. now := time.Now()
  63. dayStr := beego.Date(now, "Ymd")
  64. billno := c.MchID + dayStr + util.RandomStr(10)
  65. var signMap = make(map[string]string)
  66. signMap["nonce_str"] = util.RandomStr(5)
  67. signMap["mch_billno"] = billno //mch_id+yyyymmdd+10位一天内不能重复的数字
  68. signMap["mch_id"] = c.MchID
  69. signMap["wxappid"] = c.AppID
  70. signMap["send_name"] = input.SendName
  71. signMap["re_openid"] = input.ToOpenID
  72. signMap["total_amount"] = util.ToStr(input.MoneyFen)
  73. signMap["total_num"] = "1"
  74. signMap["wishing"] = input.Wishing
  75. signMap["client_ip"] = input.IP
  76. signMap["act_name"] = input.ActName
  77. signMap["remark"] = input.Remark
  78. signMap["sign"] = base.Sign(signMap, c.MchAPIKey, nil)
  79. respMap, err := c.SendRedPackRaw(signMap)
  80. if err != nil {
  81. return false, err
  82. }
  83. resultCode, ok := respMap["result_code"]
  84. if !ok {
  85. err = errors.New("no result_code")
  86. return false, err
  87. }
  88. if resultCode != "SUCCESS" {
  89. returnMsg, _ := respMap["return_msg"]
  90. errMsg, _ := respMap["err_code_des"]
  91. errCode, _ := respMap["err_code"]
  92. if errCode == "NOTENOUGH" {
  93. return false, ErrNoEnoughMoney
  94. }
  95. err = fmt.Errorf("Err:%s return_msg:%s err_code:%s err_code_des:%s", "result code is not success", returnMsg, errCode, errMsg)
  96. return false, err
  97. }
  98. mchBillNo, ok := respMap["mch_billno"]
  99. if !ok {
  100. err = errors.New("no mch_billno")
  101. return false, err
  102. }
  103. if billno != mchBillNo {
  104. err = errors.New("billno is not correct")
  105. return false, err
  106. }
  107. return true, nil
  108. }