⽀付-案例代码配置
⼀. 案例介绍
这⾥模拟⼀个实际业务场景,进⾏介绍⽀付,业务功能包括:登录、注册、充值、查看充值记录。
页⾯图:
⼆. 概要设计
1.数据库设计
  这⾥数据库包括两张表:⽤户表和订单表。
  ⽤户表:主键id、⽤户名、密码、openid、注册时间
  订单表:主键id、⽤户id,商品名称、订单状态(0代表下单了未⽀付,1代表⽀付成功)、商品价钱、下单时间
2.⽀付流程
  这⾥结合该案例,来说明⽀付流程。
  该流程中涉及到4种⾓⾊,分别是⽤户、客户端、商户系统(⾃⼰的系统)、⽀付系统。
  流程1:
  ①⽤户登录客户端系统→②进⼊主页→③去⽀付→④⽣成商户系统订单→⑤调⽤统⼀下单API,在⽀付系统⾥⽣成预⽀付订单,并返回预⽀付订单信息→
  ⑥商户系统拿到返回的预⽀付订单信息,进⾏签名,便按照⼀定的格式返给客户端(JSAPI页⾯)→⑦客户端JSAPI页⾯拿到参数,请求⽀付,输⼊密码,进⾏⽀付→
  ⑧这时会进⾏2个并⾏处理→异步通知商户⽀付结果,商户系统接到通知后,需要修改订单的业务逻辑(该案例修改订单状态0改为1),商户系统需要告知系统处理结果
  →给客户端发送⽀付结果,并发消息提⽰ 
  ⑨客户端跳转到商户H5页⾯,查询商户后台⽀付结果
  ⑩这时候分两种情况
    A. 商户后台系统,已经接到通知,进⾏了业务修改,直接返回成功。
    B. 商户后台系统,没有接到通知,这时去查询⽀付系统,如果⽀付系统成功,说明确实付款成功,只是因为⽹络延迟造成商户后台暂时没有接到通知,如果查询后发现未付款成功,则返回付款失败。
⽀付业务流程图:
3.代码配置
(1).参数配置
(2).前端页⾯代码
1    $(function () {
2// 当内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
3            document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
4//⽀付
5                ElementById("pay").onclick = function () {
6//1.前端验证
7var money = $('#num').val();
8if (money == "") {
9                        alert('请将信息输⼊完整');
10return;
11                    }
12                    mui('#pay').button('loading');
13//2.进⾏下单
14                    $.ajax({
15                        type: 'POST',
16                        url: '/WeiXinGz/GetAPI',
17                        data: { "money": money },
18                        cache: false,
19                        dataType: 'json',
20                        success: function (jsonData) {
21if (jsonData.status == "1") {
22//⽀付
23                                WeixinJSBridge.invoke('getBrandWCPayRequest', jsonData.payData, function (res) {
24// 使⽤以下⽅式判断前端返回,团队郑重提⽰:_msg将在⽤户⽀付成功后返回ok,但并不保证它绝对可靠。25//【因此团队建议:】当收到ok返回时,向商户后台询问是否收到交易成功的通知,
26//若收到通知,前端展⽰交易成功的界⾯;
27//若此时未收到通知,商户后台主动调⽤查询订单接⼝,查询订单的当前状态,并反馈给前端展⽰相应的界⾯。
28if (_msg == "get_brand_wcpay_request:ok") {
29//JS API的返回结果get_brand_wcpay_request:ok仅在⽤户成功完成⽀付时返回
30                                        $.ajax({
31                                            type: 'POST',
32                                            url: '/WeiXinGz/QueryOrder',
33                                            data: {
34                                                orderId: derId
35                                            },
36                                            cache: false,
37                                            dataType: 'text',
38                                            success: function (jsonData) {
39if (jsonData == "ok") {
40                                                    alert("⽀付成功", "提⽰", function () {
41                                                        alert("页⾯跳转等业务处理");
42                                                    });
43                                                    mui('#pay').button('reset');
44                                                } else {
45                                                    alert("⽀付失败,请稍后重试!如果收到⽀付通知,切勿重复⽀付1!");
46                                                    mui('#pay').button('reset');
47                                                }
48                                            },
49                                            error: function (XMLHttpRequest, textStatus, errorThrown) {
50                                                alert("⽀付失败,请稍后重试!如果收到⽀付通知,切勿重复⽀付2!");
51                                                mui('#pay').button('reset');
51                                                mui('#pay').button('reset');
52                                            }
53                                        });
54                                    } else if (_msg == "get_brand_wcpay_request:cancel") {
55//由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统⼀处理为⽤户遇到错误或者主动放弃,不必细化区分。
56                                        alert("您放弃了⽀付");
57                                        mui('#pay').button('reset');
58                                    } else {
59//由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统⼀处理为⽤户遇到错误或者主动放弃,不必细化区分。
60                                        alert("⽀付失败,请稍后重试!如果收到⽀付通知,切勿重复⽀付3!");
61                                        mui('#pay').button('reset');
62                                    }
63                                });
64                            } else {
65                                alert(jsonData.promptInfor);
66                                mui('#pay').button('reset');
67                            }
68                        },
69                        error: function (XMLHttpRequest, textStatus, errorThrown) {
70                            alert("订单提交失败,请稍后重试4!");
71                            mui('#pay').button('reset');
72                        }
73                    });
74
75                }
76            }, false);
77        });
(3).统⼀下单接⼝
1///<summary>
2///统⼀下单接⼝
3///</summary>
4///<param name="money">钱数</param>
5///<returns></returns>
6public ActionResult GetAPI(string money)
7        {
8try
9            {
10//⼀.系统本⾝⾃有的业务处理
11//1.必要信息的初始化
12string userId = Session["userId"].ToString();    //⽤户主键
13                UserInfor userInfor = db.Set<UserInfor>().Where(a => a.id == userId).FirstOrDefault();
14string orderId = GenerateOrderNum(); //⽣成订单号
15string totalFee = money;//设置默认商品费⽤为【1分】
16string nonceStr = TenPayV3Util.GetNoncestr();  //获取随机字符串
17string openid = userInfor.openId;
18//2.⾃⼰商户系统下单
19                OrderInfor orderInfor = new OrderInfor();
20                orderInfor.id = orderId;
21                orderInfor.uid = userInfor.id;
代码转换22                dName = "测试商品";
23                dPrice = totalFee;
24                orderInfor.addTime = DateTime.Now;
25                orderInfor.status = "0";  //已经下单,但未付款
26                db.Set<OrderInfor>().Add(orderInfor);
27                db.SaveChanges();
28
29
30//⼆.系统下单
30//⼆.系统下单
31//1.创建⽀付应答对象并初始化
32                RequestHandler packageReqHandler = new RequestHandler(null);
33                packageReqHandler.Init();
34//1.1设置统⼀下单的参数
35                packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId"));    //公众账号ID
36                packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId"));    //商户号
37                packageReqHandler.SetParameter("nonce_str", nonceStr);    //随机字符串
38                packageReqHandler.SetParameter("body", "科技-服务");    //商品描述
39                packageReqHandler.SetParameter("out_trade_no", orderId);    //商户订单号
40                packageReqHandler.SetParameter("total_fee", totalFee);    //商品⾦额,以分为单位
41                packageReqHandler.SetParameter("spbill_create_ip", Request.UserHostAddress);  //终端IP
42                packageReqHandler.SetParameter("notify_url", ConfigHelp.AppSettings("notify_url"));    //⽀付异步通知回调地址
43                packageReqHandler.SetParameter("trade_type", "JSAPI");    //交易类型代表⽀付
44                packageReqHandler.SetParameter("openid", openid);    //⽤户标识
45string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //预⽀付签名
46                packageReqHandler.SetParameter("sign", sign);
47//1.2 下单数据格式转换
48string data = packageReqHandler.ParseXML();
49//1.3 进⾏下单
50string result = TenPayV3.Unifiedorder(data);
51//2.对下单返回结果进⾏分析
52                XDocument res = XDocument.Parse(result);
53//2.1 对返回结果进⾏判断
54
55//2.2 成功的情况下获取必要的参数
56string prepayId = res.Element("xml").Element("prepay_id").Value;  //获取预⽀付订单编号prepayId
57//3. 获取⽀付参数并签名
58string timeStamp = TenPayV3Util.GetTimestamp(); //获取时间戳
59//设置⽀付参数
60                RequestHandler paySignReqHandler = new RequestHandler(null);
61                paySignReqHandler.SetParameter("appId", ConfigHelp.AppSettings("AppId"));
62                paySignReqHandler.SetParameter("timeStamp", TenPayV3Util.GetTimestamp());
63                paySignReqHandler.SetParameter("nonceStr", nonceStr);
64                paySignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepayId));
65                paySignReqHandler.SetParameter("signType", "MD5"); //签名【MD5】
66string paySign = paySignReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //JSAPI⽀付签名
67var payData = new
68                {
69                    appId = ConfigHelp.AppSettings("AppId"),
70                    timeStamp = timeStamp,
71                    nonceStr = nonceStr,
72                    package = string.Format("prepay_id={0}", prepayId),
73                    signType = "MD5",
74                    paySign = paySign,
75                };
76return Json(new
77                {
78                    status = "1",
79                    promptInfor = "下单成功",
80                    payData = payData,
81                    orderId = orderId
82                });
83            }
84catch (Exception ex)
85            {
86string a = ex.Message;
87
88return Json(new
89                {
90                    status = "0",
91                    promptInfor = a
92                });
93            }
94        }