给用户发红包
用户买了商品,剩下的钱,可以自己再提出来。
问题1我纠结了好久,并没有找到合适解决方法,因为按照这个要求,操作由后台发起,由后台执行,而这样做,微信是不允许的,这也是为什么我会写一篇关于支付宝提现的帖子,但你去看支付宝的文档,会发现过程极其繁琐,还有时间差,而且微信与支付宝打架,这个功能还得放在微信外的页面,用户体验非常不好。
经过与老板的讨价还价,终于改变为了问题2 : 将发起者改为用户,这样以上的问题,就都不是问题了。
阅读代码之前墙裂建议先看完官方文档
业务场景:
用户点击页面上的按钮,post请求发送至后台,获取用户的id和要提现的金额,经过校验向用户微信钱包打款。
func (c *WXRedPacketController) Post() { uid, _ := c.GetSession("uid").(string) packegtMoney, err := c.GetFloat("packegtMoney", 0) o := orm.NewOrm() if err == nil { //检查用户钱包内是否有这么多钱可供提现 uwallet := models.UserWallet{Uid:uid} if _, _, err := o.ReadOrCreate(&uwallet, "uid"); err == nil { umoney, _ := strconv.ParseFloat(uwallet.Money, 64) if umoney >= packegtMoney { //提现至微信红包 str_req := makeRedPacketXML(packegtMoney, uid) if ok, errInfo := sendRedPacketRequest(str_req, uid); ok { uwallet.Money = strconv.FormatFloat(math.Floor((umoney - packegtMoney) * 100) / 100, 'f', 2, 64) _, err := o.Update(&uwallet, "money") if err != nil { fmt.Println("用户提现更新钱包失败", err) logUtils.GetLog().Error("用户提现更新钱包失败", err) c.Data["errinfo"] = "更新钱包失败" } else { //插入 wallet-his _, err = o.Insert(&models.UserWalletHis{Uid:uid, MoneyChange:strconv.FormatFloat(math.Floor(packegtMoney * 100) / 100, 'f', 2, 64), BonusChange:"0", ChangeReason:models.DRAW, BankType:"", BankNum:"", ReasonOrder:"", ReasonPerson:"", CreateTime:time.Now().Format(TIMELAYOUT), }) if err != nil { fmt.Printf("插入 UserWalletHis 错误 %v", err) logUtils.GetLog().Error("插入 UserWalletHis 错误 %v", err) } } c.Redirect("/wx_red_packet", 302) } else { c.Data["errinfo"] = errInfo } } else { c.Data["errinfo"] = "钱包余额不足" } } else { c.Data["errinfo"] = "钱包查询错误" } } c.Data["money"] = showWalletMoney(o, uid)//可提现 c.TplName = "wx_red_packget.html"} //生成红包的申请xml money 提现的金额 元 func makeRedPacketXML(money float64, uid string) string { //拼接xml var redPacket models.RedPacket redPacket.Nonce_str = RandomStrUtil.GetRandomString(32) redPacket.Mch_billno = beego.AppConfig.String("shopKey") + time.Now().Format(TIMELAYOUT3) + strconv.FormatInt(time.Now().Unix(), 10) redPacket.Mch_id = beego.AppConfig.String("shopKey") redPacket.Appid = beego.AppConfig.String("APPID") redPacket.Send_name = "商城" redPacket.Re_openid = uid redPacket.Total_amount = int(money * 100)//分钱 redPacket.Total_num = 1 redPacket.Wishing = "收红包啦" redPacket.Client_ip = "122.122.122.122" redPacket.Act_name = "红包名称" redPacket.Remark = "红包说明" var n map[string]interface{} n = make(map[string]interface{}, 0) n["nonce_str"] = redPacket.Nonce_str n["mch_billno"] = redPacket.Mch_billno n["mch_id"] = redPacket.Mch_id n["wxappid"] = redPacket.Appid n["send_name"] = redPacket.Send_name n["re_openid"] = redPacket.Re_openid n["total_amount"] = redPacket.Total_amount n["total_num"] = redPacket.Total_num n["wishing"] = redPacket.Wishing n["client_ip"] = redPacket.Client_ip n["act_name"] = redPacket.Act_name n["remark"] = redPacket.Remark redPacket.Sign = wxpayCalcSign(n, PAY_API_KEY) //这个key 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全 bytes_req, err := xml.Marshal(redPacket) if err != nil { fmt.Println("转换为xml错误:", err) logUtils.GetLog().Error("转换为xml错误:", err) } str_req := strings.Replace(string(bytes_req), "RedPacket", "xml", -1) fmt.Println("发红包参数转换为xml--------", str_req) return str_req } func sendRedPacketRequest(str_req, uid string) (bool, string) { bytes_req := []byte(str_req) //发送unified order请求. req, err := http.NewRequest("POST", "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack", bytes.NewReader(bytes_req)) if err != nil { fmt.Println("发送红包 Request发生错误,原因:", err) logUtils.GetLog().Error("发送红包 Request发生错误,原因:", err) return false, "未知错误" } req.Header.Set("Accept", "application/xml") //这里的http header的设置是必须设置的. req.Header.Set("Content-Type", "application/xml;charset=utf-8") tlsConfig, err := WxPlatUtil.GetTLSConfig() if err != nil { fmt.Println("解析证书出现错误", err) return false, "未知错误" } tr := &http.Transport{TLSClientConfig: tlsConfig} client := &http.Client{Transport: tr} resp, _err := client.Do(req) if _err != nil { fmt.Println("请求发送红包接口发送错误, 原因:", _err) logUtils.GetLog().Error("请求发送红包接口发送错误, 原因:", _err) return false, "未知错误" } respBytes, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("请求发送红包解析返回body错误", err) logUtils.GetLog().Error("请求发送红包解析返回body错误", err) return false, "未知错误" } else { fmt.Println("请求发送红包解析返回===================>", string(respBytes)) redPacketRes := models.RedPacketRes{} if err := xml.Unmarshal(respBytes, &redPacketRes); err == nil { recodeRedPacketRes(&redPacketRes, uid)//记录存入数据库 if redPacketRes.Return_code == "SUCCESS" { if redPacketRes.Result_code == "SUCCESS" { return true, "红包领取成功" } else { return false, redPacketRes.Err_code_des } } else { //签名失败 return false, "微信签名失败" } } else { fmt.Println("红包领取记录解析错误", err) logUtils.GetLog().Error("红包领取记录解析错误", err) } } return false, "未知错误"} func wxpayCalcSign(mReq map[string]interface{}, key string) string { //fmt.Println("========STEP 1, 对key进行升序排序.========") //fmt.Println("微信支付签名计算, API KEY:", key) //STEP 1, 对key进行升序排序. sorted_keys := make([]string, 0) for k, _ := range mReq { sorted_keys = append(sorted_keys, k) } sort.Strings(sorted_keys) //fmt.Println("========STEP2, 对key=value的键值对用&连接起来,略过空值========") //STEP2, 对key=value的键值对用&连接起来,略过空值 var signStrings string for _, k := range sorted_keys { //fmt.Printf("k=%v, v=%v/n", k, mReq[k]) value := fmt.Sprintf("%v", mReq[k]) if value != "" { signStrings = signStrings + k + "=" + value + "&" } } //fmt.Println("========STEP3, 在键值对的最后加上key=API_KEY========") //STEP3, 在键值对的最后加上key=API_KEY if key != "" { signStrings = signStrings + "key=" + key } //fmt.Println("========STEP4, 进行MD5签名并且将所有字符转为大写.========") //STEP4, 进行MD5签名并且将所有字符转为大写. md5Ctx := md5.New() md5Ctx.Write([]byte(signStrings)) cipherStr := md5Ctx.Sum(nil) upperSign := strings.ToUpper(hex.EncodeToString(cipherStr)) return upperSign } func recodeRedPacketRes(redPacketRes *models.RedPacketRes, uid string) { //插入数据库 红包领取记录 o := orm.NewOrm() wxUser := models.WxUser{WxId:uid} if err := o.Read(&wxUser, "wx_id"); err == nil { redPacketHis := models.RedPacketResHis{RedPacketRes:*redPacketRes, Name:wxUser.Name, Phone:wxUser.Phone, CreateTime:time.Now().Format(TIMELAYOUT)} _, err := o.Insert(&redPacketHis) if err != nil { fmt.Println("插入红包领取记录错误", err) logUtils.GetLog().Error("红包领取记录", err) } } else { fmt.Println("查询用户信息错误", err) logUtils.GetLog().Error("查询用户信息错误", err) } }
这就OK啦,用户的微信钱包是实时更新的。当然要是想再友好点,可以给用户发个消息,下一篇,就来写微信的客服功能。
本文来自:CSDN博客
感谢作者:u012210379
查看原文:使用golang快速开发微信公众平台(六):给用户发红包(用户提现至微信钱包)
查看原文:http://www.zoues.com/2016/10/27/%e4%bd%bf%e7%94%a8golang%e5%bf%ab%e9%80%9f%e5%bc%80%e5%8f%91%e5%be%ae%e4%bf%a1%e5%85%ac%e4%bc%97%e5%b9%b3%e5%8f%b0%e5%85%ad%e7%bb%99%e7%94%a8%e6%88%b7%e5%8f%91%e7%ba%a2%e5%8c%85%e7%94%a8%e6%88%b7/
使用golang快速开发微信公众平台(六):给用户发红包(用户提现至微信钱包)
最新推荐文章于 2023-10-29 18:57:18 发布