加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

使用golang快速开发微信公众平台(六):给用户发红包(用户提现至微

发布时间:2020-12-16 19:15:43 所属栏目:大数据 来源:网络整理
导读:给用户发红包 用户买了商品,剩下的钱,可以自己再提出来。 问题1我纠结了好久,并没有找到合适解决方法,因为按照这个要求,操作由后台发起,由后台执行, 而这样做,微信是不允许的 ,这也是为什么我会写一篇关于支付宝提现的帖子,但你去看支付宝的文档,
  1. 给用户发红包
  2. 用户买了商品,剩下的钱,可以自己再提出来。

问题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,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("解析证书出现错误","未知错误"
    }

    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错误","未知错误"
    } 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=%vn",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啦,用户的微信钱包是实时更新的。当然要是想再友好点,可以给用户发个消息,下一篇,就来写微信的客服功能。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读