最近有个项目增加导游引流功能,因为项目只用的小程序,没有使用公众号,没法用”现金红包“功能,开通商家转账到零钱需要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}¬ify_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;
}
})
},
到这就结束了,请大家指教。