C#【微信】网页端支付流程(四)

版权声明: https://blog.csdn.net/liuchang19950703/article/details/81909310

后台配置接入微信支付回调:

附上微信接口API统一支付文档:

返回结果

字段名 变量名 必填 类型 示例值 描述
返回状态码 return_code String(16) SUCCESS

SUCCESS/FAIL

此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

返回信息 return_msg String(128) OK

当return_code为FAIL时返回信息为错误原因 ,例如

签名失败

参数格式校验错误

以下字段在return_code为SUCCESS的时候有返回

字段名 变量名 必填 类型 示例值 描述
公众账号ID appid String(32) wx8888888888888888 调用接口提交的公众账号ID
商户号 mch_id String(32) 1900000109 调用接口提交的商户号
设备号 device_info String(32) 013467007045764 自定义参数,可以为请求支付的终端设备号等
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 微信返回的随机字符串
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 微信返回的签名值,详见签名算法
业务结果 result_code String(16) SUCCESS SUCCESS/FAIL
错误代码 err_code String(32)   当result_code为FAIL时返回错误代码,详细参见下文错误列表
错误代码描述 err_code_des String(128)   当result_code为FAIL时返回错误描述,详细参见下文错误列表

以下字段在return_code 和result_code都为SUCCESS的时候有返回

字段名 变量名 必填 类型 示例值 描述
交易类型 trade_type String(16) JSAPI

JSAPI 公众号支付

NATIVE 扫码支付

APP APP支付

说明详见参数规定

预支付交易会话标识 prepay_id String(64) wx201410272009395522657a690389285100 微信生成的预支付会话标识,用于后续接口调用中使用,该值有效期为2小时
二维码链接 code_url String(64) URl:weixin://wxpay/s/An4baqw trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付

举例如下:

<xml>
   <return_code><![CDATA[SUCCESS]]></return_code>
   <return_msg><![CDATA[OK]]></return_msg>
   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
   <mch_id><![CDATA[10000100]]></mch_id>
   <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
   <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
   <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
   <result_code><![CDATA[SUCCESS]]></result_code>
   <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
   <trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

错误码

名称 描述 原因 解决方案
NOAUTH 商户无此接口权限 商户未开通此接口权限 请商户前往申请此接口权限
NOTENOUGH 余额不足 用户帐号余额不足 用户帐号余额不足,请用户充值或更换支付卡后再支付
ORDERPAID 商户订单已支付 商户订单已支付,无需重复操作 商户订单已支付,无需更多操作
ORDERCLOSED 订单已关闭 当前订单已关闭,无法支付 当前订单已关闭,请重新下单
SYSTEMERROR 系统错误 系统超时 系统异常,请用相同参数重新调用
APPID_NOT_EXIST APPID不存在 参数中缺少APPID 请检查APPID是否正确
MCHID_NOT_EXIST MCHID不存在 参数中缺少MCHID 请检查MCHID是否正确
APPID_MCHID_NOT_MATCH appid和mch_id不匹配 appid和mch_id不匹配 请确认appid和mch_id是否匹配
LACK_PARAMS 缺少参数 缺少必要的请求参数 请检查参数是否齐全
OUT_TRADE_NO_USED 商户订单号重复 同一笔交易不能多次提交 请核实商户订单号是否重复提交
SIGNERROR 签名错误 参数签名结果不正确 请检查签名参数和方法是否都符合签名算法要求
XML_FORMAT_ERROR XML格式错误 XML格式错误 请检查XML参数格式是否正确
REQUIRE_POST_METHOD 请使用post方法 未使用post传递参数  请检查请求参数是否通过post方法提交
POST_DATA_EMPTY post数据为空 post数据不能为空 请检查post数据是否为空
NOT_UTF8 编码格式错误 未使用指定编码格式 请使用UTF-8编码格式

一.后台回调类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Xml.Linq;
using ZhClass;
using Newtonsoft.Json;

namespace CS
{
    /// <summary>
    /// WXPay 的摘要说明
    /// </summary>
    public class WXPay
    {
        public WXPay() { }
        public string XML()
        {
            return string.Format(@"
<xml>
    <appid>{0}</appid>
    <mch_id>{1}</mch_id>
    <nonce_str>{2}</nonce_str>
    <body>{3}</body>
    <detail>{4}</detail>
    <out_trade_no>{5}</out_trade_no>
    <spbill_create_ip>{6}</spbill_create_ip>
    <total_fee>{7}</total_fee>
    <notify_url>{8}</notify_url>
    <trade_type>{9}</trade_type>
    <attach>{10}</attach>
    <sign>{11}</sign>
</xml>",
this.appid, this.mch_id, this.nonce_str, this.body, this.detail, this.out_trade_no, this.spbill_create_ip, this.total_fee, this.notify_url, this.trade_type, this.attach, this.Sign());
        }
        /// <summary>
        /// 公众账号ID(买家付款号)
        /// </summary>
        public string appid { get { return "wx7d9083d04*****"; } }
        /// <summary>
        /// 商户收款号
        /// </summary>
        public string mch_id { get { return "10058836"; } }
        /// <summary>
        /// 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
        /// </summary>
        public string key { get { return "hkfdfdjidosdsf8yfao9p****f"; } }
        /// <summary>
        /// 随机字符串
        /// </summary>
        public string nonce_str
        {
            get { return ZhClass.ZH.Randow(20); }
        }
        /// <summary>
        /// 交易类型
        /// </summary>
        public string trade_type
        {
            get { return "NATIVE"; }
        }
        /// <summary>
        /// 订单描述
        /// </summary>
        public string body { get; set; }
        /// <summary>
        /// 商品详情,订单名称
        /// </summary>
        public string detail { get; set; }
        /// <summary>
        /// 附加数据(商户携带订单的自定义数据)
        /// </summary>
        public string attach { get; set; }
        /// <summary>
        /// 商户订单号
        /// </summary>
        public string out_trade_no { get; set; }
        /// <summary>
        /// 终端IP
        /// </summary>
        public string spbill_create_ip
        {
            get { return ZhClass.ZH.RealIP; }
        }
        /// <summary>
        /// 总金额
        /// </summary>
        public int total_fee { get; set; }
        /// <summary>
        /// 通知地址,接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
        /// </summary>
        public string notify_url
        {
            get { return "http://*****y.com/WXPay_Notify.ashx"; }

        }
        //请求微信支付方法
        public string Pay()
        {
            return this.XML().Post("https://api.mch.weixin.qq.com/pay/unifiedorder");
        }
        /// <summary>
        /// 签名方法
        /// </summary>
        public string Sign()
        {
            Dictionary<string, string> m = new Dictionary<string, string>();
            try
            {
                Type type = typeof(WXPay);
                object obj = Activator.CreateInstance(type);
                type.GetProperties(BindingFlags.Public | BindingFlags.Instance).ForEach(t => m.Add(t.Name, t.GetValue(this, null).toString()));
                #region 测试专用
                ZH.SaveErr(string.Format("签名obj:{0}", JsonConvert.SerializeObject(obj)));
                #endregion
                m.Remove("key"); //这个已经内置了
                m.Remove("sign");
                return WXSign(m);
            }
            catch (Exception ex)
            {
                ZH.SaveErr(ex.ToString());
                return "";
            }
        }
        public string WXSign(Dictionary<string, string> m)
        {
            string stra = string.Join("&",
                    m.Where(t => !t.Value.IsNullOrEmpty()).OrderBy(t => t.Key).Select(t => string.Format("{0}={1}", t.Key, t.Value))
                );
            #region 测试专用
            ZH.SaveErr(string.Format("签名stra:{0}", stra.toString()));
            #endregion
            string strb = string.Format("{0}&key={1}", stra, this.key);
            return strb.Md5().ToUpper();
        }
    }
    /// <summary>
    /// 代替一般处理程序的类
    /// </summary>
    public class WXPay_Notify : IHttpHandler
    {
        //<xml>
        //<appid><![CDATA[wx5d8187c****]]></appid> --公众账号ID(买家付款号)
        //<attach><![CDATA[139294,2]]></attach>  --附加数据
        //<bank_type><![CDATA[COMM_DEBIT]]></bank_type> --银行类型
        //<cash_fee><![CDATA[200]]></cash_fee> --现金金额
        //<fee_type><![CDATA[CNY]]></fee_type> --标价币种
        //<is_subscribe><![CDATA[Y]]></is_subscribe> --是否关注公众账号
        //<mch_id><![CDATA[150****421]]></mch_id>  --微信支付分配的商户号(商户收款号)
        //<nonce_str><![CDATA[mU7SDeHzwy6iT7FSk5RZ]]></nonce_str> --随机字符串
        //<openid><![CDATA[oSD1J02Cdt_daqcj****7Nhg]]></openid> --用户在商户系统下的唯一标识
        //<out_trade_no><![CDATA[2018072*****5mU7SDeHzwy]]></out_trade_no> --商户订单流水号
        //<result_code><![CDATA[SUCCESS]]></result_code>   --业务结果:SUCCESS/FAIL
        //<return_code><![CDATA[SUCCESS]]></return_code>   --此字段是通信标识(SUCCESS/FAIL),非交易标识,交易是否成功需要查看trade_state来判断
        //<sign><![CDATA[33613BB305C792****63E02CD27F1]]></sign>  --签名,详见签名生成算法
        //<time_end><![CDATA[20180720115253]]></time_end>  --支付完成时间
        //<total_fee>200</total_fee>  --订单总金额
        //<trade_type><![CDATA[NATIVE]]></trade_type>   --交易类型  
        //<transaction_id><![CDATA[42000001162018****04937929]]></transaction_id>   --微信支付订单号
        //<trade_state_desc><![CDATA[支付失败,请重新下单支付]]></trade_state_desc>   --交易状态描述

        //</xml>
        //微信承认的返回的result : 
        //成功:
        //<xml>
        //<return_code><![CDATA[SUCCESS]]></return_code>
        //<return_msg><![CDATA[OK]]></return_msg>
        //</xml>
        //失败:
        // <xml>
        //<return_code><![CDATA[FAIL]]></return_code>
        //<return_msg><![CDATA[状态失败]]></return_msg>
        //</xml>

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            context.Response.AddHeader("Cache-Control", "no-cache");
            ExcuteResult result = new ExcuteResult();
            //商户订单号
            string out_trade_no = "";
            string uname = "";
            try
            {
                string notifyXml = context.Request.getPostData();
                //记录回调的信息
                ZH.SaveErr("微信支付异步回调通知信息:" + notifyXml);
                XElement xe = XElement.Parse(notifyXml);
                if (xe.Element("result_code").Value == "SUCCESS" && xe.Element("return_code").Value == "SUCCESS")
                {
                    //获取回调的信息,将信息存储到数据库
                    //注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
                    //特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。
                    //商户订单号
                    out_trade_no = xe.Element("out_trade_no") == null ? "" : xe.Element("out_trade_no").Value;
                    //微信订单号
                    string transaction_id = xe.Element("transaction_id") == null ? "" : xe.Element("transaction_id").Value;
                    //订单收款账号(卖家号)
                    string mch_id = xe.Element("mch_id") == null ? "" : xe.Element("mch_id").Value;
                    //订单付款账号(买家号)
                    string appid = xe.Element("appid") == null ? "" : xe.Element("appid").Value;
                    //订单总金额(传给微信和返回的金额都是 乘以100后的值)
                    decimal total_fee = xe.Element("total_fee") == null ? Convert.ToDecimal("0.00") :
                    Convert.ToDecimal(Math.Round((Convert.ToDouble(xe.Element("total_fee").Value)) / 100, 2));

                    #region 原先
                    //订单附加
                    string attach = xe.Element("attach") == null ? "" : xe.Element("attach").Value;

                    //订单交易支付时间
                    DateTime time_end = xe.Element("time_end") == null ? Convert.ToDateTime("1990-01-01") : DateTime.ParseExact(xe.Element("time_end").Value, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
                    //交易类型(0:支付宝 1:微信)
                    int order_pay_type = 1;
                    //订单详情
                    string order_detail = "";
                    //订单id
                    string order_id = "";
                    //订单名称
                    string order_name = "";
                    if (attach.Length > 0)
                    {
                        AlipayBody weiXinAttach = JsonConvert.DeserializeObject<AlipayBody>(attach);
                        uname = weiXinAttach.uname;
                        //order_detail = weiXinAttach.order_detail;
                        //order_id = weiXinAttach.order_id.toString();
                        //order_name = weiXinAttach.order_name.toString();
                    }
                    #endregion
                    
                    //mch_id(收款微信账号对应的微信唯一用户号)一致
                    if (mch_id != new WXPay().mch_id)
                    {
                        result.Result = false;
                        result.Msg = "mch_id(收款微信账号对应的微信唯一用户号)与请求时不一致";
                        ZH.SaveErr(new ErrorLog()
                        {
                            ErrorId = out_trade_no,
                            ErrorUser = uname,
                            ErrorTime = DateTime.Now,
                            ErrorClass = "WXPay.cs",
                            ErrorMethod = "ProcessRequest",
                            ErrorMsg = result.toJson()
                        }.toJson());
                        //记录异常状态
                        UpdateErrorStateByReturnSuccessAlipay(uname, out_trade_no, transaction_id, order_name, mch_id, appid, order_pay_type, total_fee, order_detail, time_end);
                        context.Response.Write(@" 
                        <xml>
                        < return_code >< ![CDATA[FAIL]] ></ return_code >
                        < return_msg > < ![CDATA[" + result.Msg + "]] ></ return_msg >" +
                        "</ xml > ");
                        context.ApplicationInstance.CompleteRequest();
                    }
                    //访问数据库,更新库存
                    var obj = DB.ExeSqlSaving("proc_order_validate_update_pay", "",
                    uname, out_trade_no, transaction_id, mch_id, appid, order_pay_type, total_fee, order_detail, time_end);
                    if (obj.Count != 4)
                    {
                        result.Result = false;
                        result.Msg = "存储过程的返回参数数量不对";
                        ZH.SaveErr(new ErrorLog()
                        {
                            ErrorId = out_trade_no,
                            ErrorUser = uname,
                            ErrorTime = DateTime.Now,
                            ErrorClass = "WXPay.cs",
                            ErrorMethod = "ProcessRequest",
                            ErrorMsg = result.toJson()
                        }.toJson());
                        context.Response.Write(@" 
                        <xml>
                        < return_code >< ![CDATA[FAIL]] ></ return_code >
                        < return_msg > < ![CDATA[" + result.Msg + "]] ></ return_msg >" +
                    "</ xml > ");
                        context.ApplicationInstance.CompleteRequest();
                    }
                    result.Result = obj[1].toString(0) == 0 ? false : true;
                    result.Msg = obj[2].toString();
                    //注意:这里需要特别注意 代理商分成的返回,如果代理商分成有错误记录即可,不需要回滚所有订单信息
                    string order_propor_money_msg = obj[3].ToString();
                    if (order_propor_money_msg.Trim().Length > 0)
                    {
                        result.Msg = order_propor_money_msg;
                    }
                    ZH.SaveErr(new ErrorLog()
                    {
                        ErrorId = out_trade_no,
                        ErrorUser = uname,
                        ErrorTime = DateTime.Now,
                        ErrorClass = "WXPay.cs",
                        ErrorMethod = "ProcessRequest",
                        ErrorMsg = result.toJson()
                    }.toJson());
                    if (!result.Result)
                    {
                        context.Response.Write(@" 
                        <xml>
                        < return_code >< ![CDATA[FAIL]] ></ return_code >
                        < return_msg > < ![CDATA[" + result.Msg + "]] ></ return_msg >" +
                    "</ xml > ");
                        context.ApplicationInstance.CompleteRequest();
                    }
                    //成功
                    context.Response.Write(@"
                        <xml>
                        <return_code><![CDATA[SUCCESS]]></return_code>
                        <return_msg><![CDATA[OK]]></return_msg>
                        </xml>");
                    context.ApplicationInstance.CompleteRequest();
                }
                else
                {
                    ZhClass.ZH.SaveErr(new ErrorLog()
                    {
                        ErrorId = out_trade_no,
                        ErrorUser = uname,
                        ErrorTime = DateTime.Now,
                        ErrorClass = "WXPay.cs",
                        ErrorMethod = "ProcessRequest",
                        ErrorMsg = "微信支付异步回调通知状态失败!"

                    }.toJson());
                    context.Response.Write(@"
                    <xml>
                    <return_code><![CDATA[FAIL]]></return_code>
                    <return_msg><![CDATA[微信支付异步回调通知状态失败]]></return_msg>
                    </xml>");
                    context.ApplicationInstance.CompleteRequest();
                }
            }
            catch (Exception ex)
            {
                ZhClass.ZH.SaveErr(new ErrorLog()
                {
                    ErrorId = out_trade_no,
                    ErrorUser = uname,
                    ErrorTime = DateTime.Now,
                    ErrorClass = "WXPay.cs",
                    ErrorMethod = "ProcessRequest",
                    ErrorMsg = ex.toString()

                }.toJson());
                context.Response.Write(@"
                <xml>
                <return_code><![CDATA[FAIL]]></return_code>
                <return_msg><![CDATA[ex异常]]></return_msg>
                </xml>");
                context.ApplicationInstance.CompleteRequest();
            }
        }
        public bool IsReusable { get { return false; } }

        /// <summary>
        /// 微信返回支付成功,记录订单异常
        /// </summary>
        /// <param name="uname"></param>
        /// <param name="order_flow_num"></param>
        /// <param name="order_pay_num"></param>
        /// <param name="order_subject"></param>
        /// <param name="order_seller_id"></param>
        /// <param name="order_buyer_id"></param>
        /// <param name="order_pay_type"></param>
        /// <param name="order_total_amount"></param>
        /// <param name="order_memo"></param>
        /// <param name="order_pay_time"></param>
        public void UpdateErrorStateByReturnSuccessAlipay(string uname, string order_flow_num, string order_pay_num, string order_subject,
            string order_seller_id, string order_buyer_id, int order_pay_type, decimal order_total_amount, string order_memo, DateTime order_pay_time)
        {
            ExcuteResult result = new ExcuteResult();
            var obj = DB.ExeSqlSaving("proc_update_order_state_by_error", "", uname, order_flow_num, order_pay_num, order_subject, order_seller_id, order_buyer_id,
                 order_pay_type, order_total_amount, order_memo, order_pay_time);
        }

    }



}

猜你喜欢

转载自blog.csdn.net/liuchang19950703/article/details/81909310