使用第三方库(Senparc)完成小程序支付
1.添加第三方库,如下图:
2.支付代码:
/// <summary> /// 支付 /// </summary> /// <param name="model"></param> /// <returns></returns> [Route("Pay")] public WeixinJsPaySignature Pay(PayRequest model) { string timeStamp = ""; string nonceStr = ""; string paySign = ""; string sp_billno = GeneratorHelper.GeneratorOrderNo(); using (var context = new TwoPoleRentContext()) { var devcie = context.Devices.FirstOrDefault(c => c.DeviceCode == model.DeviceId); if (devcie == null) { return null; } var supplier = context.Suppliers.FirstOrDefault(c => c.OpenId == model.OpenId); var order = new Order() { OrderId = Guid.NewGuid(), OrderCode = sp_billno, OrderName = Constants.OrderName, OrderPrice = model.Total, PayType = PayType.WxPay, OrderState = OrderState.Pending, OrderTotalMoney = model.Total, CreatedOn = DateTime.Now, SupplierId = supplier.Id, DeviceId = devcie.Id, ModifiedOn = DateTime.Now }; context.Orders.Add(order); context.SaveChanges(); } //创建支付应答对象 RequestHandler packageReqHandler = new RequestHandler(null); //初始化 packageReqHandler.Init(); timeStamp = TenPayV3Util.GetTimestamp(); Logger.DebugFormat("支付timeStamp{0}", timeStamp); nonceStr = TenPayV3Util.GetNoncestr(); Logger.DebugFormat("支付nonceStr{0}", nonceStr); var productName = "易考星"; //设置package订单参数 packageReqHandler.SetParameter("appid", Constants.AppID); //公众账号ID packageReqHandler.SetParameter("mch_id", Constants.TenPay3MchId); //商户号 packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串 packageReqHandler.SetParameter("body", productName); //商品信息 packageReqHandler.SetParameter("out_trade_no", sp_billno); //商家订单号 //todo 充数据库配置获取价格 packageReqHandler.SetParameter("total_fee", (model.Total * Constants.WeixinRedPackRatio/1000).ToString()); //商品金额,以分为单位(money * 100).ToString() packageReqHandler.SetParameter("spbill_create_ip", Request.GetClientIpAddress()); //用户的公网ip,不是商户服务器IP packageReqHandler.SetParameter("notify_url", string.Format("{0}/Api/WeixinPay/PayNotifyUrl", Constants.WeixinWebsite)); //接收财付通通知的URL packageReqHandler.SetParameter("trade_type", TenPayV3Type.JSAPI.ToString()); //交易类型 packageReqHandler.SetParameter("openid", model.OpenId); //用户的openId Logger.DebugFormat("支付OpenId{0}", model.OpenId); string sign = packageReqHandler.CreateMd5Sign("key", Constants.TenPayV3Key); Logger.DebugFormat("支付sign{0}", sign); packageReqHandler.SetParameter("sign", sign); //签名 string data = packageReqHandler.ParseXML(); Logger.DebugFormat("支付data{0}", data); var resultPay = TenPayV3.Unifiedorder(data); var res = XDocument.Parse(resultPay); Logger.DebugFormat("支付result{0}", resultPay); Logger.DebugFormat("支付res{0}", res); string prepayId = res.Element("xml").Element("prepay_id").Value; Logger.DebugFormat("支付prepayId{0}", prepayId); //设置支付参数 RequestHandler paySignReqHandler = new RequestHandler(null); paySignReqHandler.SetParameter("appId", Constants.AppID); paySignReqHandler.SetParameter("timeStamp", timeStamp); paySignReqHandler.SetParameter("nonceStr", nonceStr); paySignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepayId)); paySignReqHandler.SetParameter("signType", "MD5"); paySign = paySignReqHandler.CreateMd5Sign("key", Constants.TenPayV3Key); var jsmodel = new WeixinJsPaySignature { AppId = Constants.AppID, Timestamp = timeStamp, NonceStr = nonceStr, Package = string.Format("prepay_id={0}", prepayId), PaySign = paySign, OrderId = sp_billno }; return jsmodel; }
3.回调:
/// <summary> /// 支付回调 /// </summary> /// <returns></returns> [Route("PayNotifyUrl")] public HttpResponseMessage PayNotifyUrl() { Logger.Debug("PayNotifyUrl"); ResponseHandler resHandler = new ResponseHandler(null); var _xml = resHandler.ParseXML(); Logger.InfoFormat(_xml); string result_code = resHandler.GetParameter("result_code"); Logger.DebugFormat("result_code-{0}", result_code); string fee_type = resHandler.GetParameter("fee_type"); Logger.DebugFormat("fee_type-{0}", fee_type); string return_code = resHandler.GetParameter("return_code"); Logger.DebugFormat("return_code-{0}", return_code); string total_fee = resHandler.GetParameter("total_fee"); Logger.DebugFormat("total_fee-{0}", total_fee); string return_msg = resHandler.GetParameter("return_msg"); Logger.DebugFormat("return_msg-{0}", return_msg); string mch_id = resHandler.GetParameter("mch_id"); Logger.DebugFormat("mch_id-{0}", mch_id); string cash_fee = resHandler.GetParameter("cash_fee"); Logger.DebugFormat("cash_fee-{0}", cash_fee); string openid = resHandler.GetParameter("openid"); Logger.DebugFormat("openid-{0}", openid); string transaction_id = resHandler.GetParameter("transaction_id"); Logger.DebugFormat("transaction_id-{0}", transaction_id); string sign = resHandler.GetParameter("sign"); Logger.DebugFormat("sign-{0}", sign); string bank_type = resHandler.GetParameter("bank_type"); Logger.DebugFormat("bank_type-{0}", bank_type); string appid = resHandler.GetParameter("appid"); Logger.DebugFormat("appid-{0}", appid); string time_end = resHandler.GetParameter("time_end"); Logger.DebugFormat("time_end-{0}", time_end); string trade_type = resHandler.GetParameter("trade_type"); Logger.DebugFormat("trade_type-{0}", trade_type); string nonce_str = resHandler.GetParameter("nonce_str"); Logger.DebugFormat("nonce_str-{0}", nonce_str); string is_subscribe = resHandler.GetParameter("is_subscribe"); Logger.DebugFormat("is_subscribe-{0}", is_subscribe); string out_trade_no = resHandler.GetParameter("out_trade_no"); Logger.DebugFormat("out_trade_no-{0}", out_trade_no); Logger.DebugFormat("TotalFee:{0},CashFee:{1}", decimal.Parse(total_fee), decimal.Parse(cash_fee)); string xml = string.Format(@"<xml> <return_code><![CDATA[{0}]]></return_code> <return_msg><![CDATA[{1}]]></return_msg> </xml>", return_code, return_msg); try { using (var context = new TwoPoleRentContext()) { var pay = new Pay() { //PayId = Guid.NewGuid(), PayState = PayState.OrderSuccess, PayType = PayType.WxPay, ResultCode = result_code, FeeType = fee_type, ReturnCode = return_code, TotalFee = decimal.Parse(total_fee), MchId = mch_id, CashFee = decimal.Parse(cash_fee), TransactionId = transaction_id, Sign = sign, BankType = bank_type, Appid = appid, TimeEnd = DateTime.Now, TradeType = trade_type, NonceStr = nonce_str, OrderCode = out_trade_no, CreatedOn = DateTime.Now, ModifiedOn = DateTime.Now }; var order = context.Orders.Include("Device").FirstOrDefault(d => d.OrderCode == out_trade_no); if (order==null||order.PayId != null) { return new HttpResponseMessage { Content = new StringContent(xml, Encoding.GetEncoding("UTF-8"), "text/plain") }; } //更新设备使用情况 var deviceUsage = context.DeviceUsages.FirstOrDefault(c => c.DeviceId == order.DeviceId); var hours = (double) (order.OrderPrice/order.Device.UnitPrice); if (deviceUsage==null) { deviceUsage=new DeviceUsage { DeviceId =order.DeviceId, StarTime = DateTime.Now, EndTime = DateTime.Now.AddHours(hours) }; context.DeviceUsages.Add(deviceUsage); } else { if (deviceUsage.EndTime>DateTime.Now) { deviceUsage.EndTime= deviceUsage.EndTime.AddHours(hours); } else { deviceUsage.StarTime=DateTime.Now; deviceUsage.EndTime = DateTime.Now.AddHours(hours); } } order.PayId = pay.Id; order.PayType = (int)PayType.WxPay; order.OrderState = OrderState.Paid; context.Pays.Add(pay); //教练提成 var divided = context.Divideds.FirstOrDefault(c => c.SupplierId == order.SupplierId); if (divided==null) { Logger.Error(string.Format("设备提成未配置,订单号:{0},设备编号:{1}", out_trade_no, order.SupplierId)); } else { var money=divided.DividedState==DividedState.FixedAmount?divided.FixedAmount:order.OrderPrice*divided.Percentage; var account = context.Accounts.FirstOrDefault(c => c.Id == order.SupplierId); if (account==null) { account=new Account { Id = order.SupplierId, UserMoney = money, DepositForzeMoney=0, DepositLeftMoney=0, }; context.Accounts.Add(account); } else { account.UserMoney += money; } var accountDetail = new AccountDetail { AccountId = account.Id, UserMoney = money, FrozenMoney=0, DetailType = DepositDetailType.DetailCharge, DetailState = DetailState.DetailSuccess, OrderSource = out_trade_no, }; account.AccountDetails.Add(accountDetail); } var result = context.SaveChanges() > 0; Logger.InfoFormat("pay_result:{0}", result); } } catch (Exception ex) { Logger.Error(string.Format("支付回调出错,{0}",ex)); } return new HttpResponseMessage { Content = new StringContent(xml, Encoding.GetEncoding("UTF-8"), "text/plain") }; }
5.小程序端代码:
pay: function () { wx.showLoading({ title: '正在支付' }) app.httpService("weixinPay/Pay", { openId: this.data.openid, Total: this.data.Total, deviceId: this.data.deviceId }, function (res) { console.log(res) wx.hideLoading() if (res) { wx.requestPayment({ 'timeStamp': res.Timestamp, 'nonceStr': res.NonceStr, 'package': res.Package, 'signType': 'MD5', 'paySign': res.PaySign, 'success': function (res) { wx.showToast({ title: '支付成功,欢迎使用驾考设备', icon: 'none', duration: 3000 }); }, 'fail': function (res) { wx.showToast({ title: '支付失败,请重新支付', icon: 'none', duration: 2000 }); } }) } }) },