C# MVC 微信支付之小程序红包

news/2024/7/20 1:25:26 标签: 微信, 小程序, 微信小程序红包

       最近有个项目增加导游引流功能,因为项目只用的小程序,没有使用公众号,没法用”现金红包“功能,开通商家转账到零钱需要7-14天才能申请下来,暂时先用小程序红包顶上,一路都是坑啊,特此记录下。

        官方文档【微信支付】小程序红包开发者文档 (qq.com)

先开下具体效果,点击领取佣金=>生成红包=>领取红包

废话不多说,开始走起

1、开通(省略)

2、向运营账户中充值(开始以为可以用账户金额了,自己想多了,说明微信想的多么周到)

3、以用户OpenID为基础生成一个红包,然后在前端直接领取, 所以有两个流程   一个是生成红包,一个是领取红包。

4、具体实现(根据实际情况进行设计,我们的项目是凌晨对前一天的订单进行结算,结算完导游就能进行领取了,我这里是前端小程序进行的生成和领取的,这个要根据实际业务来设计)

5、部分代码(.net core)

生成红包

[HttpPost]
        public async Task<ActionResult> SendMiniProgramhb(string openid,string billno,decimal amount)
        {
            try
            {
                string url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendminiprogramhb";

                string nonce_str = WXPay.GetNoncestr();
                string total_amount = (Math.Round((decimal)amount * 100, 0)).ToString();
                //参与统一下单签名的参数,除最后的key外,已经按参数名ASCII码从小到大排序
                string unifiedorderSignParam = string.Format("act_name={0}&mch_billno={1}&mch_id={2}&nonce_str={3}&notify_way={4}&re_openid={5}&remark={6}&send_name={7}&total_amount={8}&total_num={9}&wishing={10}&wxappid={11}&key={12}"
                    , "导游分佣", billno, MCH_ID, nonce_str, "MINI_PROGRAM_JSAPI",openid, "导游分佣", "xxx", total_amount,"1", "感谢您的付出!",APP_ID, KEY);
                //MD5加密并将结果转换成大写
                string unifiedorderSign =WXPay.GetMD5(unifiedorderSignParam).ToUpper();

                //获取统一的下单的请求参数
                string param = string.Format(@"<xml>
                                                <act_name>导游分佣</act_name>
                                                <mch_billno>{0}</mch_billno>
                                                <mch_id>{1}</mch_id>
                                                <nonce_str>{2}</nonce_str>
                                                <notify_way>MINI_PROGRAM_JSAPI</notify_way>
                                                <re_openid>{3}</re_openid>
                                                <remark>导游分佣</remark>
                                                <send_name>xxx</send_name>
                                                <total_amount>{4}</total_amount>
                                                <total_num>1</total_num>
                                                <wishing>感谢您的付出!</wishing>
                                                <wxappid>{5}</wxappid>
                                                <sign>{6}</sign>
                                               </xml>", billno, MCH_ID, nonce_str,openid, total_amount,APP_ID, unifiedorderSign); ;


                string ret = WxRedPackPost(url, param);
                var payRes = XDocument.Parse(ret);
                var root = payRes.Element("xml");
                //序列化相应参数返回给小程序
                var res = GetPayRequestParam(root);
                if(res  == null)
                {
                    return Json(new TData<PayRequesEntity> { Tag = 0, Message="生成红包有误!" });
                }
                else
                {
                    return Json(new TData<PayRequesEntity> { Tag = 1, Data = res });
                }
                
               
            }
            catch (Exception ex)
            {

                return Json(new TData { Tag = 0, Message = ex.Message });
            }
        }

这个要注意,红包功能需要证书

public string WxRedPackPost(string posturl, string postData)
{
    Stream outstream = null;
    Stream instream = null;
    StreamReader sr = null;
    HttpWebResponse response = null;
    HttpWebRequest request = null;
    Encoding encoding = Encoding.UTF8;
    byte[] data = encoding.GetBytes(postData);
    // 准备请求...  
    try
    {
        //CerPath证书路径,这里是本机的路径,实际应用中,按照实际情况来填写
        string certPath = GlobalContext.WxConfig.SSLCERT_PATH;
        //证书密码
        string password = GlobalContext.WxConfig.SSLCERT_PASSWORD;
        X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath, password, X509KeyStorageFlags.MachineKeySet);

        // 设置参数  
        request = WebRequest.Create(posturl) as HttpWebRequest;
        CookieContainer cookieContainer = new CookieContainer();
        request.CookieContainer = cookieContainer;//不可少(个人理解为,返回的时候需要验证)
        request.AllowAutoRedirect = true;
        request.Method = "POST";
        request.ContentType = "text/xml";
        request.ContentLength = data.Length;
        request.ClientCertificates.Add(cert);//添加证书请求
        outstream = request.GetRequestStream();
        outstream.Write(data, 0, data.Length);
        outstream.Close();
        //发送请求并获取相应回应数据  
        response = request.GetResponse() as HttpWebResponse;
        //直到request.GetResponse()程序才开始向目标网页发送Post请求  
        instream = response.GetResponseStream();
        sr = new StreamReader(instream, encoding);
        //返回结果网页(html)代码  
        string content = sr.ReadToEnd();
        string err = string.Empty;
        return content;

    }
    catch (Exception ex)
    {
        string err = ex.Message;
        return string.Empty;
    }
}

paySign签名生成这里容易犯错

a 参与签名的字段包括:appId、nonceStr、package、timeStamp,就这四个,不要用之前经验来弄,

b 不用转成大写,转成大写就会签名错误。

c 返回前端的package要进行urlencode。

        private static PayRequesEntity GetPayRequestParam(XElement root)
        {
            //当return_code 和result_code都为SUCCESS时才有我们要的prepay_id
            if (root.Element("return_code").Value == "SUCCESS" && root.Element("result_code").Value == "SUCCESS")
            {
                if (root.Element("return_msg").Value == "发放成功")
                {

                    var package = root.Element("package").Value;//统一下单接口返回的 prepay_id 参数值
                    var nonceStr = WXPay.GetNoncestr();//获取随机字符串
                    var signType = "MD5";//加密方式
                    var timeStamp = Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString();//时间戳

                    var paySignParam = string.Format("appId={0}&nonceStr={1}&package={2}&timeStamp={3}&key={4}",
                          APP_ID, nonceStr, HttpUtility.UrlEncode(package), timeStamp, KEY);
                    //二次加签
                    var paySign = WXPay.GetMD5(paySignParam);

                    PayRequesEntity payEntity = new PayRequesEntity
                    {
                        package = HttpUtility.UrlEncode(package),
                        nonceStr = nonceStr,
                        paySign = paySign,
                        signType = signType,
                        timeStamp = timeStamp
                    };
                    return payEntity;
                }
            }

            return null;
        }

此方法又增加了一个“return_msg”的判断,因为出现了这种情况,正常情况下面领取红包后进行状态修改,发现如果再领取完页面不返回是不走领取成功事件,也就出现了领取了但是状态没有改变,再次领取的时候就会返回这样的数据(下面xml),所以只用“SUCCESS”判断没法友好提醒,所以加了这个逻辑,如果有好办法,大伙告诉我哦!

<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[该红包已经成功,已经被领取或者发起退款]]></return_msg>
  <result_code><![CDATA[SUCCESS]]></result_code>
  <err_code><![CDATA[SUCCESS]]></err_code>
  <err_code_des><![CDATA[该红包已经成功,已经被领取或者发起退款]]></err_code_des>
  <mch_billno><![CDATA[]]></mch_billno>
  <mch_id><![CDATA[]]></mch_id>
  <wxappid><![CDATA[]]></wxappid>
  <re_openid><![CDATA[]]></re_openid>
  <total_amount>100</total_amount>
</xml>

前端微信小程序

这个要注意就是场景只支持1011、1025、1047和1124,只能用摄像头扫,长按是不行的。

getUserHongbao(e) {
    const _this = this
    let user_id = ''
    wx.login({
      success: function (res) {
        console.log('wxlogin code:' + res.code);
        codeWx({
            code: res.code
          })
          .then(res => {
            wx.setStorageSync('openId', res.Data.openid)
            _this.setData({
              openId: res.Data.openid
            })
            var sceneCode = wx.getLaunchOptionsSync() //获取场景代码
            if (sceneCode.scene == 1047 || sceneCode.scene == 1011 || sceneCode.scene == 1025 || sceneCode.scene == 1124) {
            }
            else
            {
              wxShowToast('领取方式有误,请联系工作人员。', 'none', 4000);
              return;
            }
            //检测是否有提现金额
            wx.request({
              url: baseUrl + '***/GetFormJsonByOpenId?openid=' + _this.data.openId,
              method: "POST",
              success(res) {
                if (res.data.Tag == 1) {
                  //创建红包
                  wx.request({
                    url: baseUrl + '***/GenMiniProgramhb?openid=' + _this.data.openId,
                    method: "POST",
                    success(res) {
                      if (res.data.Tag == 0) {
                        wxShowToast(res.data.Message, 'none', 4000);
                      } else {
                        var orderid = res.data.Data.OrderCode
                        //领取红包
                        //1011 扫描二维码 1025 扫描一维码 1047 扫描小程序码 1124 扫“一物一码”打开小程序                        
                          //领取红包的代码
                          wx.sendBizRedPacket({
                            "timeStamp": res.data.Data.timeStamp, // 支付签名时间戳,
                            "nonceStr": res.data.Data.nonceStr, // 支付签名随机串,不长于 32 位
                            "package": res.data.Data.package, //扩展字段,由商户传入
                            "signType": res.data.Data.signType, // 签名方式,
                            "paySign": res.data.Data.paySign, // 支付签名
                            "success": function (res) {
                              console.log("success:");
                              console.log(res);
                              wx.request({
                                url: baseUrl + '***/MiniProgramhbC?id=' + orderid,
                                method: "POST",
                                success(res) {
                                  console.log(res);
                                }
                              })
                            },
                            "fail": function (res) {
                              console.log("fail:");
                              console.log(res);
                            },
                            "complete": function (res) {
                              console.log("complete:");
                              console.log(res);
                            }
                          })                        
                      }
                    }
                  })
                } else {
                  wxShowToast(res.data.Message, 'none', 4000);
                }
              }
            })
          })
      },
      fail: function () {
        console.info("1授权失败返回数据");
        wx.hideLoading()
        wx.showModal({
          title: '提示',
          content: '请重新授权哦'
        })
        return;
      }
    })
  },

到这就结束了,请大家指教。


http://www.niftyadmin.cn/n/352761.html

相关文章

Transformer网络原理与实战

Transformer网络原理与实战 1. 什么是Transformer网络2. Transformer网络原理2.1 自注意力机制2.2 多头自注意力机制2.3 Transformer网络的训练 3.Transformer网络实战 1. 什么是Transformer网络 Transformer网络是一种基于自注意力机制的神经网络&#xff0c;由Google于2017年…

【ZYNQ】ZYNQ7000 UART 控制器及驱动示例

简介 UART 控制器介绍 UART 控制器是一个全双工异步收发控制器&#xff0c;ZYNQ 内部包含两个 UART 控制器&#xff0c;UART0 和 UART1。每一个 UART 控制器支持可编程的波特率发生器、64 字节的接收 FIFO 和发送 FIFO、产生中断、RXD 和 TXD 信号的环回模式设置以及可配置的…

Java设计模式-责任链模式

简介 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;它允许将请求沿着处理链进行传递&#xff0c;直到有一个对象能够处理该请求。该模式将请求的发送者和接收者解耦&#xff0c;使多个对象都有机会处理请求&#xff0c;从…

Java开发常见状态码,Web开发状态码返回

文章目录 100开头200开头300开头400开头500开头参考文档 100开头 说明&#xff1a;响应中——临时状态码&#xff0c;表示请求已经接受&#xff0c;告诉客户端应该继续请求或者如果它已经完成则忽略它 200开头 说明&#xff1a;成功——表示请求已经被成功接收&#xff0c;处…

数字图像处理 使用C#进行图像处理八 Unsharp Masking

一、Unsharp Masking简述 Unsharp Masking是一种线性图像处理技术,用于锐化图像。清晰的细节被识别为两者之间的差异原始图像及其模糊版本。然后缩放这些细节, 并添加回原始图像: 增强图像 = 原始图像 + 数量 *(原始图像 - 模糊) 模糊步骤可以使用任何图像滤波方法,例如…

java_day01_单元测试_配置文件

一、软件的生命周期 **软件的可行性分析:**分析该软件是否值的研发,会消耗多少成本,能带来多少的利益等分析 **需求分析:**分析该软件具体该具备有那些功能,产品经理与客户一起讨论 **软件设计:**该软件应该使用什么样的架构,用什么样的数据库,每个模块的具体功能 **程序编…

c语言json库parson的介绍和使用

简介 本文章主要介绍下parson库的使用parson : parson是用C语言开发的一个json解析库&#xff0c; 提供json的序列化和反序列化功能。使用时只需要在我们的工程中引入头文件parson.h和源文件parson.c即可使用。 使用parson解析json 单层json结构解析 代码 const char* res…

国外顶尖高校、企业分享人工智能自学课程英文原课程分享

人工智能无疑已经是当下最火热的方向&#xff0c;在很多领域已经融入我们生活&#xff0c;ChatGPT,Midjourney只是其中一个细分热点。目前这个领域&#xff0c;虽说国内也有不少课程&#xff0c;但是大部分源头还得从英文资料中找。如何学到最新最强得人工智能技能&#xff0c;…