• 微信接口C#.net

    2020-06-17 18:01:44
     微信公众号支付是基于微信公众号而开发的支付接口,已有的公众号里可以添加ASP的公众号支付,微信中生成订单后,可以直接调出微信钱包直接支付,非常方便,同样支持自动更新订单状态,刷卡支付则适用于商场类的...
  • 会员领取了会员卡之后需要做一个跳转性激活,模式请看下图: 创建会员卡的时候需要配置下这个参数的值: memberActivate.aspx页面代码如下: <%@ Page Language="C#" AutoEventWireup="true" ...

    在会员领取了会员卡之后需要做 一个跳转性激活,模式请看下图:

    在创建会员卡的时候需要配置下这个参数的值:

     

     memberActivate.aspx页面代码如下:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="memberActivate.aspx.cs" Inherits="ChainStock.mobile.member.memberActivate" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <title>激活会员卡</title>
        <script src="js/jquery.min.js" type="text/javascript"></script>
        <%--<script src="scripts/bootstrap.min.js" type="text/javascript"></script>--%>
        <link href="css/bootstrap.min.css" rel="stylesheet" />
        <style type="text/css">
            .no-padding {
                padding: 0px;
            }
    
            .no-margin {
                margin: 0px;
            }
    
            .btn_active {
                background-color: #019a01;
                width: 100%;
                padding: 7px 0px;
                color: white;
                border: 1px solid #019a01;
            }
    
            .btn_return {
                background-color: #f8f8f8;
                width: 100%;
                padding: 7px 0px;
                color: black;
                border: 1px solid #e6e6e6;
            }
        </style>
        <script type="text/javascript">
            $(function () {
                $(".btn_return").bind("click", function () {
                    event.preventDefault();
                    window.history.back();
                })
            });
        </script>
    </head>
    <body style="background-color: #f2f2f2;" class="no-padding no-margin">
        <form id="form1" runat="server">
            <div class="container no-padding">
                <br />
                <div class="col-xs-12">
                    <div class="col-xs-12">
                        <label>请确定以下信息:</label>
    
                    </div>
                </div>
                <div class="clearfix"></div>
                <br />
                <div style="background-color: white; padding: 30px 0px; border-bottom: 1px solid #dbdbdb; border-top: 1px solid #dbdbdb;">
                    <div class="col-xs-12">
                        <div class="col-xs-3">
                            用户名
                        </div>
                        <div class="col-xs-9 no-padding text-left" id="divMemName" runat="server"></div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="col-xs-12" style="padding-top: 10px;">
                        <div class="col-xs-3">
                            手机号
                        </div>
                        <div class="col-xs-9 no-padding text-left" id="divMemMobile" runat="server">
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="clearfix"></div>
                </div>
                <br />
    
                <div class="col-xs-12 no-padding">
                    <div class="col-xs-12 text-center">
                        <input type="button" class="btn btn-sm btn_active" value="激活会员卡" id="btnActiveMem" />
                        <input type="hidden" id="hd_MemMobile" value="" runat="server" />
                        <input type="hidden" id="hd_CardCode" value="" runat="server" />
                        <input type="hidden" id="hd_CardId" value="" runat="server" />
                    </div>
    
                    <div class="col-xs-12 text-center">
                        <br />
                        <input type="button" class="btn btn-sm btn_return" value="返 回" />
                    </div>
                    <div class="col-xs-12 ">
                        <h6 style="color: red;">注:激活后不可修改上面的信息</h6>
                    </div>
    
                    <div class="clearfix"></div>
                </div>
            </div>
        </form>
    
        <script type="text/javascript" src="scripts/jquery-2.1.4.min.js"></script>
        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
        <script type="text/javascript">
            $(function () {
                //激活会员卡
                $("#btnActiveMem").click(function () {
                    $.ajax({
                        type: "GET",
                        url: "../../Service/AjaxService.ashx?Method=Wx_ActivateCard",
                        data: {
                            memMobile: $("#hd_MemMobile").val(),
                            cardCode: $("#hd_CardCode").val(),
                            cardId: $("#hd_CardId").val()
                        },
                        dataType: "text",
                        success: function (result) {
                            if (result != null && result != "") {
                                switch (result) {
                                    case "0":
                                        alert("系统错误,请稍后再试");
                                        break;
                                    case "-1":
                                        alert("系统异常,请联系管理员");
                                        break;
                                    case "-2":
                                        alert("您还不是会员,激活失败");
                                        break;
                                    default:
                                        alert("激活成功");
                                        wx.closeWindow();//这一步就是会员激活了之后就自动跳转到会员卡详细页面
                                }
                            }
                        }
                    });
                });
            })
        </script>
    </body>
    </html>

    后台代码:

    using Chain.Wechat;
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace ChainStock.mobile.member
    {
        public partial class memberActivate : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
                BindData();
    
            }
            void BindData()
            {
                string code = "";
                string openid = "";
                string access_token = "";
                string strEncrypt_code = "";
                string tick_code = "";
                string strActivate_ticket = "";
                string cardId = "";
    
                try
                {
                    if (!string.IsNullOrEmpty(Request.QueryString["encrypt_code"]))
                    {
                        strEncrypt_code = Request.QueryString["encrypt_code"].ToString();
                    }
                    if (!string.IsNullOrEmpty(Request.QueryString["card_id"]))
                    {
                        cardId = Request.QueryString["card_id"].ToString();
                        hd_CardId.Value = cardId;
                    }
                    string getAuthorize = GetAuthorize();
                    if (getAuthorize != "")
                    {
                        getAuthorize = "[" + getAuthorize + "]";
    
                        Newtonsoft.Json.Linq.JArray javascript = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(getAuthorize);
                        Newtonsoft.Json.Linq.JObject obj = (Newtonsoft.Json.Linq.JObject)javascript[0];
    
                        if (obj["access_token"] != null && obj["access_token"].ToString() != "")
                        {
                            access_token = obj["access_token"].ToString();//用户OpenID             
                        }
                    }
                    if (!string.IsNullOrEmpty(access_token))
                    {
                        if (!string.IsNullOrEmpty(Request.QueryString["encrypt_code"]))
                        {
                            strEncrypt_code = Request.QueryString["encrypt_code"].ToString();
                            string postUrl = "https://api.weixin.qq.com/card/code/decrypt?access_token=" + access_token;
                            string postDate = "{\"encrypt_code\":\"" + strEncrypt_code + "\"}";
    
                            string strResult = PostWebRequest(postUrl, postDate);
                            strResult = "[" + strResult + "]";
                            Newtonsoft.Json.Linq.JArray codeArray = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(strResult);
                            Newtonsoft.Json.Linq.JObject objResult = (Newtonsoft.Json.Linq.JObject)codeArray[0];
                            if (objResult["errmsg"].ToString() == "ok")
                            {
                                code = objResult["code"].ToString();
                                hd_CardCode.Value = code;
                                if (!string.IsNullOrEmpty(Request["activate_ticket"]))
                                {
                                    strActivate_ticket = Request["activate_ticket"].ToString();
                                }
    
                                if (!string.IsNullOrEmpty(strActivate_ticket))
                                {
                                    string ticketPostUrl = "https://api.weixin.qq.com/card/membercard/activatetempinfo/get?access_token=" + access_token;
                                    string ticketPostData = "{ \"activate_ticket\" : \"" + strActivate_ticket + "\"}";
                                    string userInfoResult = PostWebRequest(ticketPostUrl, ticketPostData);
                                    userInfoResult = "[" + userInfoResult + "]";
    
                                    Newtonsoft.Json.Linq.JArray userInfoArray = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(userInfoResult);
                                    Newtonsoft.Json.Linq.JObject objUserInfo = (Newtonsoft.Json.Linq.JObject)userInfoArray[0];
                                    if (objUserInfo["errmsg"].ToString() == "ok")
                                    {
                                        string userMobile = objUserInfo["info"]["common_field_list"][0]["value"].ToString();
                                        string userName = objUserInfo["info"]["common_field_list"][1]["value"].ToString();
                                        if (!string.IsNullOrEmpty(userMobile))
                                        {
                                            hd_MemMobile.Value = userMobile;
                                            divMemMobile.InnerText = userMobile;
                                            divMemName.InnerText = userName;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    PubFunction.LogError("微信激活会员授权异常:" + ex);
                }
            }
    
    
            //通过code换取网页授权access_token
            public string GetAuthorize()
            {
                //PubFunction.curParameter.strWeiXinAppID = "wxcb014df3a2583811";
                //PubFunction.curParameter.strWeiXinAppSecret = "1fb18946950b112cd79103a7b1f9249b";
                if (PubFunction.curParameter.strWeiXinAppID != null && PubFunction.curParameter.strWeiXinAppSecret != null)
                {
                    string templateUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
                    templateUrl = string.Format(templateUrl, PubFunction.curParameter.strWeiXinAppID, PubFunction.curParameter.strWeiXinAppSecret);
                    HttpRequestHelper hrh = new HttpRequestHelper();
                    return hrh.Reqeust(templateUrl);
                }
                else
                {
                    return "";
                }
            }
    
            /// <summary>
            /// 发送Post请求到微信端
            /// </summary>
            /// <param name="postUrl">请求的路径</param>
            /// <param name="paramData">发送的数据</param>
            /// <returns></returns>
            public string PostWebRequest(string postUrl, string paramData)
            {
                string ret = string.Empty;
                try
                {
                    byte[] byteArray = Encoding.UTF8.GetBytes(paramData); //转化
                    HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));
                    webReq.Method = "POST";
                    webReq.ContentType = "application/json";
    
                    webReq.ContentLength = byteArray.Length;
                    Stream newStream = webReq.GetRequestStream();
                    newStream.Write(byteArray, 0, byteArray.Length);//写入参数
                    newStream.Close();
                    HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
                    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                    ret = sr.ReadToEnd();
                    sr.Close();
                    response.Close();
                    newStream.Close();
                }
                catch (Exception ex)
                {
                    PubFunction.LogError(ex);
                }
                return ret;
    
            }
        }
    }

    激活时我使用了一般处理程序来激活的代码如下:这个是根据我的系统做了一个判断,是我系统中的会员才能激活,否则不能激活

    #region 跳转式激活会员卡 参考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025283   6.6.2
            public void Wx_ActivateCard()
            {
                int flag = 0;
                string access_token = "";
                try
                {
                    string strMemMobile = !string.IsNullOrEmpty(Request["memMobile"]) ? Request["memMobile"].ToString() : "";//手机号
                    string strCardCode = !string.IsNullOrEmpty(Request["cardCode"]) ? Request["cardCode"].ToString() : "";//卡Code
                    string strCardId = !string.IsNullOrEmpty(Request["cardId"]) ? Request["cardId"].ToString() : "";//卡ID
                    if (!string.IsNullOrEmpty(strMemMobile))
                    {
                        Chain.BLL.Mem bllMem = new Chain.BLL.Mem();
                        DataTable dtMem = bllMem.GetList(" MemMobile='" + strMemMobile + "' ").Tables[0];
                        if (dtMem.Rows.Count > 0)//执行激活(只有系统中的会员才能激活)
                        {
                            string getAuthorize = GetAuthorize();
                            if (getAuthorize != "")
                            {
                                getAuthorize = "[" + getAuthorize + "]";
    
                                Newtonsoft.Json.Linq.JArray javascript = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(getAuthorize);
                                Newtonsoft.Json.Linq.JObject obj = (Newtonsoft.Json.Linq.JObject)javascript[0];
    
                                if (obj["access_token"] != null && obj["access_token"].ToString() != "")
                                {
                                    access_token = obj["access_token"].ToString();
                                }
                                if (!string.IsNullOrEmpty(strCardCode) && !string.IsNullOrEmpty(strCardId))
                                {
                                    string postData = "{";
                                    postData += "\"membership_number\": \"" + strMemMobile + "\",";
                                    postData += "\"code\": \"" + strCardCode + "\",";
                                    postData += "\"card_id\": \"" + strCardId + "\"";
                                    postData += "}";
                                    string postUrl = "https://api.weixin.qq.com/card/membercard/activate?access_token=" + access_token;
                                    string result = PostWebRequest(postUrl, postData);
    
                                    if (!string.IsNullOrEmpty(result))
                                    {
                                        result = "[" + result + "]";
                                        Newtonsoft.Json.Linq.JArray cardResult = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(result);
                                        Newtonsoft.Json.Linq.JObject cardObj = (Newtonsoft.Json.Linq.JObject)cardResult[0];
    
                                        if (cardObj["errmsg"] != null && cardObj["errmsg"].ToString() != "")
                                        {
                                            if (cardObj["errmsg"].ToString() == "ok")
                                            {
                                                flag = 1;
                                            }
                                            else
                                            {
                                                flag = -1;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else//禁止激活 
                        {
                            flag = -2;
                        }
                    }
                    else
                    {
                        flag = -1;
                    }
                }
                catch (Exception ex)
                {
                    LogError(ex);
                    flag = -1;
                }
                Context.Response.Write(flag);
            }
            #endregion

     

    转载于:https://www.cnblogs.com/LoveQin/p/10176045.html

    展开全文
  • 开发微信wepApp时,可能会有调用到摄像头的需要,如调用微信开发平台的JS-SKD有相关的图片上传的开发文档。 微信JS-SDK 相关资料参考微信官方文档: 微信网页开发:...

    当开发微信wepApp时,可能会有调用到摄像头的需要,如调用微信开发平台的JS-SKD有相关的图片上传的开发文档。

    微信JS-SDK

    相关资料参考微信官方文档:
    微信网页开发:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
    查看到第4大点,图像接口。里面有详情的调用说明。

    html5

    如果对于简洁开发,或者不会调用微信JS-SDK的话,可使用属性 capture=“camera” 即可

    <input type="file" capture="camera">
    
    展开全文
  • 经过一个多周的焦傲、摧残,终于完成了微信支付及退款,做一下总结,主要是参数、签名、数据接收问题有几个小点要注意,本文基于c#进行开发。 2. 项目背景 项目为商城,这就需要支付功能,主要做的就是支付模块,...

    1. 前言

    1. 经过一个多周的焦傲、摧残,终于完成了微信支付及退款,做一下总结,主要是参数、签名、数据接收问题有几个小点要注意,本文基于c#进行开发。

    2. 项目背景

    1. 项目为商城,这就需要支付功能,主要做的就是支付模块,所以就要实现现在主流的支付方式,如微信支付、支付宝支付…
    2. 项目业务:系统暂时要求点击支付时网站弹出生成的微信支付二维码,由用户进行扫描购买,数据回调记录数据库。
    3. 微信支付平台:转到
    4. 给出的支付方式如下图,本文主要讲Native支付模式二
      在这里插入图片描述

    3.Native支付

    1. Native支付场景介绍→转到
    2. 扫码支付模式二文档→转到
    3. 准备工作
      (1)申请 微信商户号 微信公众号 (这里具体步骤不描述,因为我做的商城,这里有商家去微信平台申请);
      (2)开通 Native支付(点击开通,很简单,但是是商家的事,不解释);
      (3)微信认证证书(商家提供,仅退款时跟撤销订单时需要);
      ①证书路径,注意应该填写绝对路径;
      ②证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载;
      ③建议将证书文件名改为复杂且不容易猜测的文件;
      ④商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。
    4. 下载微信官方提供的工具类Demo,地址:转到
      在这里插入图片描述
    5. 解压并进入WxPayAPI文件夹,将 business example lib 三个文件夹复制到咱们项目的工程中(本项目使用VS[Visual Studio 2015] ,如果不会添加 ,VS将复制过来的文件或文件夹显示到解决方案管理)
      在这里插入图片描述在这里插入图片描述
    6. 下面来说一下这三个文件夹
      (1)business文件夹中主要是 NativePay.cs 类,推荐其他文件也不要删除
      (2)example文件夹中ResultNotifyPage.aspx页面,将此文件放在工程根目录下,MakeQRCode.aspx页面保留,其他文件建议删除
      (3)lib文件夹全部保留,因为这里面是所依赖的工具类
      在这里插入图片描述在这里插入图片描述
    7. 后端进行页面配置
      (1)对于lib文件夹,仅需修改DemoConfig.cs[作用:配置微信商户号和公众号、回调地址等相关信息];(我是商城网站,商家总后台设置参数,这里从数据库调出,根据个人需求)
      在这里插入图片描述Appsert公众帐号secert(仅JSAPI支付的时候需要配置)给出了设置了也没关系,

    在这里插入图片描述支付只需要这私四个参数:
    在这里插入图片描述在这里插入图片描述
    (2)对于business文件夹,仅需修改NativePay.cs文件[作用:用来调用微信接口根据我们提供的数据生成二维码链接]
    点击支付ajax提交到后台的一个静态方法:(仅供借鉴payment为支付类型(微信、支付宝),indentid订单ID)

    $.ajax({
        contentType: "application/json",
        url: "pay.aspx/Pay_btn",
        type: "post",
        data: JSON.stringify({"payment":payment,"indentid":indentid}),
        dataType: "json",
        success: function (date) {
            if (payment == "1") {
                alert(date.d);
            } else {
                window.location.href="Wx_Payment-" + indentid + "-" + date.d + ".html";
            }
        }
    });
    

    后台静态方法里,Encrypt()加密方法

    NativePay nativePay = new NativePay();//定义这个类
    string url2 = nativePay.GetPayUrl(DESEncrypt.Decrypt(indentid));//indentid订单ID(返回二维码的url)
     string imgurl = "WX/example/MakeQRCode.aspx?data=" + HttpUtility.UrlEncode(url2);//(将url加入二维码生成页面)
     return DESEncrypt.Encrypt(imgurl);//(加密返回给前台)
    

    nativepay类(直接看模式二,根据个人逻辑写入参数):
    例:

     public string GetPayUrl(string indentid)
            {
                // Log.Info(this.GetType().ToString(), "Native pay mode 2 url is producing...");
                IndentBLL indentbll = new IndentBLL();//订单类
                IndenterBLL indenterbll = new IndenterBLL();//订单明细类
                Indent showindent = indentbll.GetModel(int.Parse(indentid));//通过订单ID获取当前订单
                BasicBLL basicbll = new BasicBLL();//网站信息设置类
                DataTable showbasic = new DataTable();
                showbasic = basicbll.GetAllList().Tables[0];//获取网站信息设置
    
                WxPayData data = new WxPayData();
                data.SetValue("body", showbasic.Rows[0]["Webname"].ToString());//商品描述(我这里给的是网站标题中文,默认是只能英文字符串,如何改下边说到)
                data.SetValue("attach", showindent.OrderNo);//附加数据,如商家数据包,自身系统生成的订单号
                data.SetValue("out_trade_no", showindent.OrderNo);//随机字符串(系统生成的订单号)
                data.SetValue("total_fee",Convert.ToInt32((showindent.Total*100)).ToString());//总金额
                data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
                data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
                data.SetValue("goods_tag", showindent.UserID);//商品标记 会员用户名
                data.SetValue("trade_type", "NATIVE");//交易类型
                data.SetValue("product_id", indentid);//商品ID(订单ID)
    
                WxPayData result = WxPayApi.UnifiedOrder(data);//调用统一下单接口
                string url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接
    
                //Log.Info(this.GetType().ToString(), "Get native pay mode 2 url : " + url);
                return url;
            }
    

    注:1. body,传入值必须为英文,负责签名错误;2.total_fee商品金额 单位是分!!!单位是分!!!单位是分!!!3.trade_type交易类型 一定为NATIVE。
    (3)返回的url做了一个页面Wx_Payment.aspx接收传入加密的订单ID(indnetid)和加密的imgurl;
    局部代码获取两个值,Decrypt()为解密方法:

     string indentid = Request.QueryString["key1"];
    imgurl =DESEncrypt.Decrypt(Request.QueryString["key2"]);
     showindent = indentbll.GetModel(int.Parse(DESEncrypt.Decrypt(indentid)));//查询订单
     showindenter = indenterbll.GetList("IndentID="+ int.Parse(DESEncrypt.Decrypt(indentid))).Tables[0];//查询订单明细
    

    在这里插入图片描述效果:
    在这里插入图片描述(4)回调,用户扫码支付成功后微信平台异步回调ResultNotifyPage.aspx

    后台调用了ResultNotify 类:

    protected void Page_Load(object sender, EventArgs e)
    {
         //File.WriteAllText(Server.MapPath("/log.txt"), Request.Url.ToString() + "==" + DateTime.Now.ToString());
         ResultNotify resultNotify = new ResultNotify(this);
         resultNotify.ProcessNotify();
     }
    

    ResultNotify 类里:

    public override void ProcessNotify()
    {
        WxPayData notifyData = GetNotifyData();
        HelpClass helpclass = new HelpClass();//自己写的帮助类
    
        //File.WriteAllText(HttpContext.Current.Server.MapPath("/log2.txt"), notifyData.ToXml() + "==" + DateTime.Now.ToString());
        //File.WriteAllText(HttpContext.Current.Server.MapPath("/log3.txt"), notifyData.IsSet("transaction_id").ToString() + "==" + DateTime.Now.ToString());
        //检查支付结果中transaction_id是否存在
        if (!notifyData.IsSet("transaction_id"))
        {
            //若transaction_id不存在,则立即返回结果给微信支付后台
            WxPayData res = new WxPayData();
            res.SetValue("return_code", "FAIL");
            res.SetValue("return_msg", "支付结果中微信订单号不存在");
            //File.WriteAllText(HttpContext.Current.Server.MapPath("/log4.txt"), res.ToXml() + "==" + DateTime.Now.ToString());
            page.Response.Write(res.ToXml());
            page.Response.End();
        }
    
        string transaction_id = notifyData.GetValue("transaction_id").ToString();//获取微信平台返回的交易号
        string orderno= notifyData.GetValue("out_trade_no").ToString();//返回的有传入的系统自动生成的订单号
    
        //File.WriteAllText(HttpContext.Current.Server.MapPath("/log5.txt"), transaction_id + "="+ QueryOrder(transaction_id).ToString() + "=" + DateTime.Now.ToString());
    
    
        //查询订单,判断订单真实性
        if (!QueryOrder(transaction_id))
        {
            //若订单查询失败,则立即返回结果给微信支付后台
            WxPayData res = new WxPayData();
            res.SetValue("return_code", "FAIL");
            res.SetValue("return_msg", "订单查询失败");
            page.Response.Write(res.ToXml());
            page.Response.End();
        }
        //查询订单成功
        else
        {
            //File.WriteAllText(HttpContext.Current.Server.MapPath("/log6.txt"), "=sql=" + DateTime.Now.ToString());
    
            WxPayData res = new WxPayData();
            res.SetValue("return_code", "SUCCESS");
            res.SetValue("return_msg", "OK");
           helpclass.Update_table("Indent", "PaymentType=2,PaymentNumber='" + transaction_id + "',PaymentTime='" + DateTime.Now.ToString() + "',PaymentStatus=1,OrdStatus=2", "OrderNo='" + orderno + "'");//通过订单编号修改支付状态,支付类型,处理结果,微信交易号,订单状态,支付时间等(修改数据库信息)
            page.Response.Write(res.ToXml());
            page.Response.End();
        }
    }
    

    订单表一个支付状态字段,在用户扫码页面隔段时间判断一下是否支付,付过了就给支付页面关了,不能用户付完之后一直还停留在扫码二维码页面,然后二维码扫码页面(Wx_Payment.aspx)ajax一秒一提交订单ID(indentid)到后台判断订单支付状态,付过了跳转到订单详情页;

    <script>
       window.setInterval(function () {
            var entid = $("#entid").val();
            $.ajax({
                contentType: "application/json",
                url: "Wx_Payment.aspx/Status",
                type: "post",
                data: JSON.stringify({ "indentid": entid }),
                dataType: "json",
                success: function (date) {
                    if (date.d == true) {
                        window.location.href = "order_info-" + entid + ".html";
                    }
                }
            });
        }, 1000);
    </script>
    

    后台:

    [WebMethod]
    public static bool Status(string indentid)
    {
        IndentBLL indentbll = new IndentBLL();
        Indent showindent = indentbll.GetModel(int.Parse(DESEncrypt.Decrypt(indentid)));
        if (showindent.PaymentStatus == 1)//PaymentStatus支付状态
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    

    (5)传参时body设置中文签名错误问题,参考:https://blog.csdn.net/YuanMxy/article/details/89331113
    找到Data类的CalcHMACSHA256Hash方法将var enc = Encoding.Default;改为var enc = Encoding.UTF8;

    微信支付、支付参数还可以参考:https://blog.csdn.net/YuanMxy/article/details/89359573?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158632862519724845049815%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=158632862519724845049815&biz_id=14&utm_source=distribute.pc_search_result.none-task-blog-soetl_SOETL-18

    (7)退款,此时需要证书和证书密码,在DemoConfig.cs加入
    用户点击退款

    $('.tuibtn').click(function () {
                var id = $(this).attr("tid");//获取要退款订单的ID
                $.ajax({
                    contentType: "application/json",
                    url: "SelectIndent.aspx/TuiKuan",
                    type: "post",
                    data: JSON.stringify({ "indentid": id }),//订单ID传入后台的静态方法
                    dataType: "json",
                    success: function (date) {
                        if (date.d == "ok") {
                            alert("退款成功!");
                            window.location.reload();
                        } else if (date.d == "no") {
                            alert("退款失败!");
                        }
                        else {
                            alert("退款失败!" + date.d);
                        }
                    }
                });
            });
    

    后台:

    [WebMethod]
    public static string TuiKuan(string indentid)
    {
        HelpClass helpclass = new HelpClass();
        IndentBLL indentbll = new IndentBLL();
        Indent showindent = indentbll.GetModel(int.Parse(indentid));//获取当前订单
        try
        {
            WxPayData result = Refund.Run(showindent.PaymentNumber,showindent.OrderNo,Convert.ToInt32(showindent.Total*100).ToString(),Convert.ToInt32((Convert.ToDecimal(showindent.Refund_fee)*100)).ToString());//调起退款
            string result_code = result.GetValue("result_code").ToString();//业务结果(SUCCESS)
            string out_trade_no= result.GetValue("out_trade_no").ToString();//商户订单号(系统自己生产的订单号)
            string out_refund_no= result.GetValue("out_refund_no").ToString();//商户退款订单号(自己生成的返回回来了)
            string refund_id= result.GetValue("refund_id").ToString();//微信退款单号
            string refund_fee= result.GetValue("refund_fee").ToString();//实际退款金额
            if(result_code== "SUCCESS")//证明退款成功了
            {
                helpclass.Update_table("Indent", "Payrefund_bool='1',Refund_id='" + refund_id + "',Refund_no='" + out_refund_no + "',Yesrun_fee='" + (Convert.ToDecimal(refund_fee)/100).ToString() + "'", "OrderNo='" + out_trade_no + "'");//保存处理结果(记录到数据库,修改当前订单,自己的逻辑代码)
                IndenterBLL indenterbll = new IndenterBLL();
                DataTable showindenter = new DataTable();
                GoodsBLL goodsbll = new GoodsBLL();
                showindenter = indenterbll.GetList("IndentID=" + indentid).Tables[0];//获取当前订单的订单详情
                foreach (DataRow item in showindenter.Rows)
                {
                    if (goodsbll.GetList("ID=" + int.Parse(item["GoodID"].ToString())).Tables[0].Rows.Count > 0)
                    {
                        Goods goods = goodsbll.GetModel(int.Parse(item["GoodID"].ToString()));
                        helpclass.Update_table("Goods", "Sales=" + (goods.Sales - (int.Parse(item["GoodCount"].ToString()))) + ",Inventory=" + (goods.Inventory + (int.Parse(item["GoodCount"].ToString()))), "ID=" + (int.Parse(item["GoodID"].ToString())));//修改商品的销售量和库存量
                    }
                }
                return "ok";
                
            }
            else
            {
                return "no";
            }
    
        }
        catch (WxPayException ex)
        {
            return ex.ToString();
        }
        catch (Exception ex)
        {
            return ex.ToString();
        }
    }
    

    Refund类的 Run方法:

     /***
            * 申请退款完整业务流程逻辑
            * @param transaction_id 微信订单号(优先使用)
            * @param out_trade_no 商户订单号
            * @param total_fee 订单总金额
            * @param refund_fee 退款金额
            * @return 退款结果(xml格式)
            */
            public static WxPayData Run(string transaction_id, string out_trade_no, string total_fee, string refund_fee)
            {
                //File.WriteAllText(HttpContext.Current.Server.MapPath("/log.txt"), transaction_id + "==" + out_trade_no+"=="+ total_fee+"=="+ refund_fee+"=="+DateTime.Now.ToString());
                WxPayData data = new WxPayData();
                if (!string.IsNullOrEmpty(transaction_id))//微信订单号存在的条件下,则已微信订单号为准
                {
                    data.SetValue("transaction_id", transaction_id);
                }
                else//微信订单号不存在,才根据商户订单号去退款
                {
                    data.SetValue("out_trade_no", out_trade_no);
                }
                data.SetValue("total_fee", int.Parse(total_fee));//订单总金额
                data.SetValue("refund_fee", int.Parse(refund_fee));//退款金额
                data.SetValue("out_refund_no", WxPayApi.GenerateOutTradeNo());//随机生成商户退款单号
                data.SetValue("op_user_id", WxPayConfig.GetConfig().GetMchID());//操作员,默认为商户号
                WxPayData result = WxPayApi.Refund(data);//提交退款申请给API,接收返回数据
                //File.WriteAllText(HttpContext.Current.Server.MapPath("/log1.txt"), result.ToXml()+"==" + DateTime.Now.ToString());
                return result;
            }
    

    WxPayApi的Refund():

     /**
            * 
            * 申请退款
            * @param WxPayData inputObj 提交给申请退款API的参数
            * @param int timeOut 超时时间
            * @throws WxPayException
            * @return 成功时返回接口调用结果,其他抛异常
            */
            public static WxPayData Refund(WxPayData inputObj, int timeOut = 6)
            {
                string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
                //检测必填参数
                if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
                {
                    throw new WxPayException("退款申请接口中,out_trade_no、transaction_id至少填一个!");
                }
                else if (!inputObj.IsSet("out_refund_no"))
                {
                    throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!");
                }
                else if (!inputObj.IsSet("total_fee"))
                {
                    throw new WxPayException("退款申请接口中,缺少必填参数total_fee!");
                }
                else if (!inputObj.IsSet("refund_fee"))
                {
                    throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!");
                }
                else if (!inputObj.IsSet("op_user_id"))
                {
                    throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!");
                }
                inputObj.SetValue("appid", WxPayConfig.GetConfig().GetAppID());//公众账号ID
                inputObj.SetValue("mch_id", WxPayConfig.GetConfig().GetMchID());//商户号
                inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
                inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型
                inputObj.SetValue("sign", inputObj.MakeSign());//签名
                string xml = inputObj.ToXml();
                var start = DateTime.Now;
                string response = HttpService.Post(xml, url, true, timeOut);//调用HTTP通信接口提交数据到API
                var end = DateTime.Now;
                int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
                //将xml格式的结果转换为对象以返回
                WxPayData result = new WxPayData();
                result.FromXml(response);
                ReportCostTime(url, timeCost, result);//测速上报
                return result;
            }
    

    Post():

    public static string Post(string xml, string url, bool isUseCert, int timeout)
            {
                System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接
    
                string result = "";//返回结果
    
                HttpWebRequest request = null;
                HttpWebResponse response = null;
                Stream reqStream = null;
    
                try
                {
                    //设置最大连接数
                    ServicePointManager.DefaultConnectionLimit = 200;
                    //设置https验证方式
                    if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                    {
                        ServicePointManager.ServerCertificateValidationCallback =
                                new RemoteCertificateValidationCallback(CheckValidationResult);
                    }
    
                    /***************************************************************
                    * 下面设置HttpWebRequest的相关属性
                    * ************************************************************/
                    request = (HttpWebRequest)WebRequest.Create(url);
                    request.UserAgent = USER_AGENT;
                    request.Method = "POST";
                    request.Timeout = timeout * 1000;
    
                    //设置代理服务器
                    //WebProxy proxy = new WebProxy();                          //定义一个网关对象
                    //proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //网关服务器端口:端口
                    //request.Proxy = proxy;
    
                    //设置POST的数据类型和长度
                    request.ContentType = "text/xml";
                    byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                    request.ContentLength = data.Length;
    
                    //是否使用证书
                    if (isUseCert)
                    {
                        string path = HttpContext.Current.Request.PhysicalApplicationPath;
                        X509Certificate2 cert = new X509Certificate2(path + WxPayConfig.GetConfig().GetSSlCertPath(), WxPayConfig.GetConfig().GetSSlCertPassword());//将证书相对地址拼成了绝对地址
                        request.ClientCertificates.Add(cert);
                    }
    
                    //往服务器写入数据
                    reqStream = request.GetRequestStream();
                    reqStream.Write(data, 0, data.Length);
                    reqStream.Close();
    
                    //获取服务端返回
                    response = (HttpWebResponse)request.GetResponse();
                   
                    //获取服务端返回数据
                    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                    
                    result = sr.ReadToEnd().Trim();
                    sr.Close();
                }
                catch (System.Threading.ThreadAbortException e)
                {
                    Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
                    Log.Error("Exception message: {0}", e.Message);
                    System.Threading.Thread.ResetAbort();
                }
                catch (WebException e)
                {
                    Log.Error("HttpService", e.ToString());
                    if (e.Status == WebExceptionStatus.ProtocolError)
                    {
                        Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
                        Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
                    }
                    throw new WxPayException(e.ToString());
                }
                catch (Exception e)
                {
                    Log.Error("HttpService", e.ToString());
                    throw new WxPayException(e.ToString());
                }
                finally
                {
                    //关闭连接和流
                    if (response != null)
                    {
                        response.Close();
                    }
                    if(request != null)
                    {
                        request.Abort();
                    }
                }
                return result;
            }
    

    注:WxPayData 支付或退款时传进去的参数,成功后微信平台有的参数不一定传回,付款时统一下单传进和返回的参数见:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1,退款时见:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_4

    展开全文
  • 我们是小程序中嵌入支付功能的,最开始用的是APP支付一直提示“支付场景非法”,换成JSAPI支付后才成功调出支付确认框并成功支付。 如果是公众号支付、扫码支付和H5支付还需要配置支付域名或回调链接,请参考:...

    合单支付

    合单支付是指可以在一个订单中包含多个商家的多个商品,一次性支付。

    • 关于JSAPI、APP、小程序等支付类型的区别:https://pay.weixin.qq.com/wiki/doc/api/sl.html
      我们是在小程序中嵌入支付功能的,最开始用的是APP支付一直提示“支付场景非法”,换成JSAPI支付后才成功调出支付确认框并成功支付。
      在这里插入图片描述

    • 如果是公众号支付、扫码支付和H5支付还需要配置支付域名回调链接,请参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3
      在这里插入图片描述

    • 在申请开通电商收付通时如果选择的是平台代扣手续费,那么建议在正式支付分账前向手续费账户充值至少100块钱,否则可能会导致分账失败;

    • 回调通知地址必须为域名并且为https协议,微信会以POST方式访问URL,以json格式通过body携带数据;

    预支付

    此处的测试方法只设置了一个子单,即只在一家店铺下了一个商品的订单;

        /**
         * 预支付
         */
        @Test
        public void prepay() {
            JSONObject reqJsonObject = new JSONObject();
            //合单商户appid
            reqJsonObject.put("combine_appid", WxPayConfig.merchantAppId);
            //合单商户
            reqJsonObject.put("combine_mchid", WxPayConfig.merchantId);
            //合单商户订单号
            reqJsonObject.put("combine_out_trade_no", "202005260952_test001");
            //回调地址
            reqJsonObject.put("notify_url", WxPayConfig.callback_notify_pay_address);
    
            //支付者
            JSONObject combine_payer_info = new JSONObject();
            combine_payer_info.put("openid", "oaKTs4vq93MDDmCFKQO123456789");
            reqJsonObject.put("combine_payer_info", combine_payer_info);
    
            //子单信息数组
            JSONArray sub_orders = new JSONArray();
            //子单信息
            JSONObject sub_order = new JSONObject();
            //子单商户号,必须与发起方appid有绑定关系
            sub_order.put("mchid", WxPayConfig.merchantId);
            //附加数据,在查询API和支付通知中原样返回
            sub_order.put("attach", "订单号为202005260952_test001");
            //子单商户订单号
            sub_order.put("out_trade_no", "202005260952_test001");
            //二级商户号
            sub_order.put("sub_mchid", WxPayConfig.testMerchantId);
            //商品描述
            sub_order.put("description", "高端茶叶500g装");
    
            //子单信息-订单金额
            JSONObject amount = new JSONObject();
            //标价金额,子单金额,单位为分
            amount.put("total_amount", 100);
            //标价币种
            amount.put("currency", WxPayConfig.currency_cny);
            sub_order.put("amount", amount);
            //子单信息-结算信息
            JSONObject settle_info = new JSONObject();
            //是否指定分账,true:是,false:否
            settle_info.put("profit_sharing", true);
            sub_order.put("settle_info", settle_info);
            sub_orders.set(0, sub_order);
            reqJsonObject.put("sub_orders", sub_orders);
    
            System.out.println("请求的body:" + reqJsonObject + "\n\n");
    
            String headerToken = WxPayUtils.getHeaderAuthorization("POST",
                    HttpUrl.parse(WxPayConfig.transactions_prepay_app_url), reqJsonObject.toJSONString());
            System.out.println("请求接口携带的 header:  \n" + headerToken + "\n\n");
    
            Map<String, String> headersMap = new HashMap<>();
            headersMap.put("User-Agent", WxPayConfig.userAgent);
            headersMap.put("Accept", "application/json");
            headersMap.put("Authorization", headerToken);
            headersMap.put("Wechatpay-Serial", WxPayConfig.api_v3_cert_serial_no);
    
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqJsonObject.toJSONString());
            ResponseAndStatusAndHeaders response = ClientUtil.getAndPostJson("POST", WxPayConfig.transactions_prepay_app_url, requestBody, headersMap);
            if (response.getStatus() != Status.SUCCESS || response.getResponseData() == null) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "合单下单接口请求错误,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + reqJsonObject + "\n\n");
                return;
            }
    
            System.out.println(response);
    
            JSONObject jsonObject = JSON.parseObject(response.getResponseData().toString());
            String prepay_id = jsonObject.get("prepay_id").toString();
            System.out.println("合单下单成功,预支付id为:" + prepay_id);
            //{"prepay_id":"up_wx26112728792815875842ded51824410800"}
        }
    

    调起支付

    后端处理好数据获得到预支付id后,需要将各种支付参数进行签名计算后的值返回给前端,由小程序方调起支付框(也就是输入支付密码的界面)。

        /**
         * 继续支付
         * @param requestJsonStr 接受的参数
         * @return 操作结果
         */
        @PostMapping("/continuePay")
        public ResultBO continuePay(@RequestBody String requestJsonStr) {
            JSONObject requestJson = JSONObject.parseObject(requestJsonStr);
            String orderNo = requestJson.getString("orderNo");
    
            //是否为有效订单
            MallOrderDO mallOrder = mallOrderService.getByOrderNo(orderNo);
            if (mallOrder == null) {
                return Results.result(HttpStatusEnum.PARAMTER_ERROE, "订单不存在");
            }
            if (mallOrder.getOrderStatus() != 1 || StrUtil.isBlank(mallOrder.getWxPrepayId())) {
                return Results.result(HttpStatusEnum.PARAMTER_ERROE, "该订单已经支付过了,请勿重复支付");
            }
    
            JSONObject payObject = WxPayUtils.getPayObject(mallOrder.getWxPrepayId());
    
            JSONObject data = new JSONObject();
            data.put("payObject", payObject);
            return Results.success(HttpStatusEnum.SUCCESS, data);
        }
    

    支付回调通知

    1. 微信回调通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m
    2. 回调处理必须校验签名,避免出现恶意调用攻击。
    3. 使用APIv3密钥对回调数据中的ciphertext进行AEAD_AES_256_GCM算法解密,得到原文。
    4. 回调处理必须检查订单状态,避免重复处理。
    5. 处理回调通知后做好日志记录,当回调正常接受返回的HTTP状态码为200或204,当回调处理失败返回的HTTP状态码应为500
        /**
         * 微信支付回调通知
         */
        @PostMapping("payCallBack")
        public JSONObject callBackNotify(@RequestBody String requestJsonStr, @RequestHeader HttpHeaders headers, HttpServletResponse response) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "微信支付结果通知接受成功,header为:" + headers + "\n body为:" + requestJsonStr);
    
            //返回通知的应答报文,code(32):SUCCESS为清算机构接收成功;message(64):错误原因
            JSONObject responseJson = new JSONObject();
            responseJson.put("code", "FAIL");
            //支付通知http应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    
            if (!headers.containsKey("Wechatpay-Serial") || !headers.containsKey("Wechatpay-Timestamp")
                    || !headers.containsKey("Wechatpay-Nonce") || !headers.containsKey("Wechatpay-Signature")) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "回调请求header缺失");
                responseJson.put("message", "回调请求header缺失");
                return responseJson;
            }
    
            String WechatpaySerial = headers.getFirst("Wechatpay-Serial");//平台证书序列号
            String WechatpayTimestamp = headers.getFirst("Wechatpay-Timestamp");//应答时间戳
            String WechatpayNonce = headers.getFirst("Wechatpay-Nonce");//应答随机串
            String WechatpaySignature = headers.getFirst("Wechatpay-Signature"); //应答签名
            if (!WechatpaySerial.equals(WxPayConfig.api_v3_cert_serial_no)) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "回调请求证书序列化不一致");
                responseJson.put("message", "回调请求证书序列化不一致");
                return responseJson;
            }
    
            //获取签名串,验签
            String srcData = WechatpayTimestamp + "\n" + WechatpayNonce + "\n" + requestJsonStr + "\n";
            if (!WxPayUtils.verify(srcData, WechatpaySignature)) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "验签失败");
                responseJson.put("message", "验签失败");
                return responseJson;
            }
    
            JSONObject requestJson = JSONObject.parseObject(requestJsonStr);
            //通知的类型,支付成功通知的类型为 TRANSACTION.SUCCESS
            String event_type = requestJson.get("event_type").toString();
            //通知数据
            JSONObject resource = JSONObject.parseObject(requestJson.get("resource").toString());
            //数据密文,Base64编码后的开启/停用结果数据密文
            String ciphertext = resource.get("ciphertext").toString();
            String associated_data = resource.get("associated_data").toString();
            String nonce = resource.get("nonce").toString();
    
            //对密文串进行解密
            String verify = WxPayUtils.getNotifyData(associated_data, nonce, ciphertext);
            JSONObject paySuccess = JSONObject.parseObject(verify);
            JSONArray sub_orders = JSON.parseArray(paySuccess.get("sub_orders").toString());
            JSONObject sub_order = JSONObject.parseObject(sub_orders.get(0).toString());
            //微信子单订单号
            String wxOrderNo = sub_order.get("transaction_id").toString();
            if (StrUtil.isBlank(wxOrderNo)) {
                responseJson.put("message", "微信支付成功,未接受到微信订单号");
                return responseJson;
            }
            //合单商户订单号
            String orderNo = paySuccess.get("combine_out_trade_no").toString();
            if (StrUtil.isBlank(orderNo)) {
                responseJson.put("message", "微信支付成功,未接受到合单商户订单号");
                return responseJson;
            }
    
            MallOrderDO mallOrder = mallOrderService.getByOrderNo(orderNo);
            if (mallOrder == null) {
                responseJson.put("message", "操作失败,未查询到合单商户订单号");
                return responseJson;
            }
    
            //支付失败
            if (!event_type.equals("TRANSACTION.SUCCESS")) {
                boolean result = mallOrderService.payFail(orderNo, wxOrderNo);
                if (result) {
                    LogUtil.printErrorLog(LogUtil.log_front_wxpay + "支付结果通知:支付失败,处理成功。订单号为:" + orderNo);
                    response.setStatus(HttpServletResponse.SC_OK);
                    responseJson.put("code", "SUCCESS");
                    responseJson.put("message", "微信支付失败,商户处理成功");
                } else {
                    LogUtil.printErrorLog(LogUtil.log_front_wxpay + "支付结果通知:支付失败,处理失败。订单号为:" + orderNo);
                    responseJson.put("message", "微信支付失败,商户处理失败");
                }
                return responseJson;
            }
    
            //支付成功
            boolean result = mallOrderService.paySuccess(orderNo, wxOrderNo);
            if (result) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "支付结果通知:支付成功,处理成功。订单号为:" + orderNo);
                response.setStatus(HttpServletResponse.SC_OK);
                responseJson.put("code", "SUCCESS");
                responseJson.put("message", "微信支付成功,商户处理成功");
            } else {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "支付结果通知:支付成功,处理失败。订单号为:" + orderNo);
                responseJson.put("message", "微信支付成功,商户处理失败");
            }
            return responseJson;
        }
    

    查询合单订单

    • 我们系统设定用户下订单后一定时间内(24h)未付款会自动取消订单,为防止状态不同步,在正式取消订单前调用合单查询接口,确认最终支付状态。
    • 当超时(4h)未接受到支付结果通知时,手动调用查询接口确认最终支付状态。
    
        /**
         * 合单查询订单
         * @param orderNo 订单号
         * @return 支付是否成功
         */
        @Override
        public Map<String, String> queryOrder(String orderNo) {
            Map<String, String> resultMap = new HashMap<>();
    
            Map<String, String> headersMap = WxPayUtils.getHeaderMap("GET", WxPayConfig.transactions_order_query_url + orderNo, "");
            ResponseAndStatusAndHeaders response = ClientUtil.getAndPostJson("GET", WxPayConfig.transactions_order_query_url + orderNo, null, headersMap);
            if (response.getStatus() != Status.SUCCESS || response.getResponseData() == null) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "合单查询订单接口请求错误,返回信息为:\n" + response.toString() + ",请求的参数:\n" + orderNo);
                return null;
            }
    
            JSONObject jsonObject = JSON.parseObject(response.getResponseData().toString());
            /*{
                "combine_appid": "wx4fcb17899329a2a1",
                "combine_mchid": "1586786671",
                "combine_out_trade_no": "20200528807139",
                "combine_payer_info": {
                    "openid": "oaKTs4vq93MDDmCFKQO123456789"
                },
                "scene_info": {
                    "device_id": ""
                },
                "sub_orders": [{
                    "amount": {
                        "payer_amount": 100,
                        "payer_currency": "CNY",
                        "total_amount": 100
                    },
                    "attach": "商户平台订单号为20200528807139",
                    "bank_type": "CFT",
                    "mchid": "1586786671",
                    "out_trade_no": "20200528807139",
                    "sub_mchid": "1596741381",
                    "success_time": "2020-05-28T22:11:13+08:00",
                    "trade_state": "SUCCESS",
                    "trade_type": "JSAPI",
                    "transaction_id": "4325300104202005287616306099"
                }]
            }*/
    
            JSONArray subOrders = JSON.parseArray(jsonObject.get("sub_orders").toString());
            JSONObject subOrder = JSON.parseObject(subOrders.get(0).toString());
            //交易状态,SUCCESS:支付成功
            //REFUND:转入退款
            //NOTPAY:未支付
            //CLOSED:已关闭
            //USERPAYING:用户支付中
            //PAYERROR:支付失败(其他原因,如银行返回失败)
            String trade_state = subOrder.getString("trade_state");
            String transaction_id = subOrder.getString("transaction_id");
    
            resultMap.put("trade_state", trade_state);
            resultMap.put("transaction_id", transaction_id);
            return resultMap;
        }
    

    参考链接

    微信电商收付通支付接口文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/combine/chapter3_1.shtml
    微信API-v3回调报文解密文档:https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/zheng-shu-he-hui-tiao-bao-wen-jie-mi

    展开全文
  • 最近研究php微信支付开发,从微信官方下载了微信支付的demo后,测试时总是弹出NaN:Undefined这样的错误提示。不过这个并不影响支付的操作,支付成功后依然可以正常获取到支付状态,并进行跳转、输出等操作。 微信...

    最近研究php微信支付开发,从微信官方下载了微信支付的demo后,测试时总是弹出NaN:Undefined这样的错误提示。不过这个并不影响支付的操作,支付成功后依然可以正常获取到支付状态,并进行跳转、输出等操作。

    微信支付demo官方下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1(含php、java、.net C#三个版本)

    具体表现为:

    1.下单的时候,并没有弹出NaN:undefined。
    2.进入到支付页面,在点击支付按钮前,就会弹出NaN:undefined。
    3.但是不影响继续支付。点击去支付BTN,还是可以调出支付窗口。

    如果点的快,就会先拉起支付界面,等支付完成返回刚才页面的时候,才会看到弹出的”NaN:undefined”,等点击确定该弹窗消失后,才会进行设定的支付成功后的php操作,如跳转、输出等。

    支付前界面:

    wxpaynan支付成功界面:wxpayok

    谢比特猜想,是不是和微信基础接口一样,有个debug:true这种调试开关,直接关掉就没有了?查了一遍,并没有找到这种。网上找了一圈,发现出现NaN:undefined通常是由于JS中出现的字符型和数字型变量未正确转换导致的。NaN是 Not A Number的意思,所以我们需要在JS中排查所有可能的数字变量,看它是不是定义为字符串了?

    notanumber

    最终找到了这里,最简单的方法就是把alert这一行注释掉,可恶的NaN:Undefined错误提示就不会再出现了!

    转载于:https://www.cnblogs.com/SofuBlue/p/11466750.html

    展开全文
  • 那些看起来非常复杂的事情,往往都可以分解为若干简单的小元素。学会化繁为简,这是程序猿的基本素质。
  • 其实答案呼之欲出啦,百分之九十都是支付签名出错 上面是我之前写的java 代码,我之前 pay.put(&...但是后来前台 HTML 画面取的时候 javax.el.ELException: Failed to parse the expression [${pay.package}...
  • 历时数周或数月开发出来了应用或游戏。可为什么体验不流畅?怎么能查出当中的纰漏?这些须要调试诊断工具从旁协助。调试是开发过程中不可缺少的重要一环。本文会列举几个比較有效的调试诊断工具,能够帮助你寻根究底...
  • 物以类聚,人以群分。游戏世界更是如此,合理的规划类的关系,对开发质量有很大的帮助。
  • 没有注册类 (异常来自 HRESULT:0x80040154 (REGDB_E_CLASSNOTREG)) 解决方法: 出现这个问题主要是因为32位操作系统和64位操作系统存在兼容性问题。解决方案: 1、鼠标右击解决方案,点击属性按钮调出属性窗口... ...
  • 我的页面做的比较大,页面滚到下方时,再点击按钮,页面刷新时,总是回到顶端,所以还要滚动鼠标,下来才能看到结果。 我想知道有没有方法,能点击刷新后,还显示之前滚动的位置。不用AJAX能实现吗?...
  • .NET Core开发日志——从搭建开发环境开始 原文:.NET Core开发日志——从搭建开发环境开始.NET Core自2016年推出1.0版本开始,到目前已是2.1版本,其roadmap计划里明年更会推出3.0版本,发展不可不...
  • Window Navigator 示例代码: <div id="example"></div> <script> var txt = ''; txt = "<p>Browser CodeName: " + navigator.appCodeName + "</p>";...Br...
  • .NET Core跨平台开发

    2019-08-20 14:48:34
    对于.NET开源计划想必关注的人已经跃跃欲试了,但是真正将其用于开发的目前来说不多。毕竟截至本文发布时.NET Core才发布到1.0RC2版本。正式版预计还有一段时间。况且大多数人都是持观望态度,就算开发仍然用的还是...
  • 调用手机相机拍照或者是调用手机相册选择照片,这个功能手机端页面或者webApp应该是常用到的,就拿个人或会员资料录入那块来说就已经是经常会碰到的, 每当看到这块功能的时候,前端的小伙伴就得去找各种各样的...
  • 一、 小程序用户重新授权案例 做连锁店小程序开发时, 需要用户授权, ...小程序开发中是经常遇到的, 类似经常用到的还有用户信息授权,图片或视频保存到相册授权。 小程序openSetting授权
  • 这个微信对接类似,比微信还简单一点,如果你对接过微信,相信这个很简单。 采用本地映射外部链接方式(ngrok工具) 1、第一步写客户端代码 采用SpringMVC+Spring框架 [html] view plai
  • Winform里面,很多控件元素都是标准的,如图标、按钮、工具栏等等,所以一般设计标准的Winform界面比较快捷,但是往往这样的界面相对单调一些,特别界面控件比较少的情况下,我们往往需要加入一些图片、背景什么...
  • 运动视觉系统

    2019-07-02 20:10:14
    前言:本软件是基于固高运动控制卡开发的集成运动控制,Io,视觉于一体的软件,同时支持在线编辑cnc功能,客户可以根据现场的动作流程,自行编写运动,视觉cnc,以解决运动视觉开发耗时,耗费人力缺点。 同时通过...
1 2 3 4 5 6
收藏数 112
精华内容 44