asp.net mvc 接入最新支付宝支付+退款

asp.net mvc 接入最新支付宝支付+退款 alipay-sdk-NET-20170615110549

 

第1步:

https://openhome.alipay.com/developmentDocument.htm

 

 第2步:下载sdk和demo

https://docs.open.alipay.com/270/106291/

 

 https://docs.open.alipay.com/54/103419

 

 第3步:将SDK放到解决方案下并在解决方案下打开下载下来的SDK项目

 

第4步:新建项目,项目中新建一个类存放支付宝配置相关信息

 

登录支付宝进入开发者中心

https://openhome.alipay.com/platform/appDaily.htm?tab=info

 

复制代码
    public class AlipayConfigHelper
    {
        //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//支付宝网关地址 // -----开发环境地址----- //public static string serviceUrl = "https://openfile.alipay.com/chat/multimedia.do"; // -----沙箱地址----- public static string serviceUrl = "https://openapi.alipaydev.com/gateway.do"; // -----线上地址----- //public static string serviceUrl = "https://openapi.alipay.com/gateway.do"; //应用ID,以2088开头由16位纯数字组成的字符串 public static string appId = "2016080500169628"; //开发者私钥,由开发者自己生成 public static string privateKey = @"******"; //支付宝的公钥,由支付宝生成 public static string alipayPublicKey = @"*****";

//服务器异步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 //public static string notify_url = "http://" + System.Web.HttpContext.Current.Request.Url.Host + ":" + System.Web.HttpContext.Current.Request.Url.Port + "/College/NotifyUrl"; public static string notify_url = "http://ryan.wicp.net/College/NotifyUrl"; //页面跳转同步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 //public static string return_url = "http://" + System.Web.HttpContext.Current.Request.Url.Host + ":" + System.Web.HttpContext.Current.Request.Url.Port + "/College/ReturnUrl"; public static string return_url = "http://ryan.wicp.net/College/ReturnUrl"; //参数返回格式,只支持json public static string format = "json"; // 调用的接口版本,固定为:1.0 public static string version = "1.0"; // 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 public static string signType = "RSA2"; // 字符编码格式 目前支持utf-8 public static string charset = "utf-8"; // false 表示不从文件加载密钥 public static bool keyFromFile = false; //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ }
复制代码

第5步:控制器处理

 

(1)初始化配置文件信息

 

复制代码
        #region  初始化配置文件信息
        private IAopClient GetAlipayClient()
        {
            //支付宝网关地址 
            string serviceUrl = AlipayConfigHelper.serviceUrl;
            //应用ID,以2088开头由16位纯数字组成的字符串
            string appId = AlipayConfigHelper.appId; 
            //商户私钥
            string privateKey = AlipayConfigHelper.privateKey;
            //支付宝的公钥
            string alipayPublicKey = AlipayConfigHelper.alipayPublicKey; 

            string format = AlipayConfigHelper.format;
            string version = AlipayConfigHelper.version;
            string signType = AlipayConfigHelper.signType;
            string charset = AlipayConfigHelper.charset;
            bool keyFromFile = false;

            IAopClient client = new DefaultAopClient(serviceUrl, appId, privateKey, format, version, signType, alipayPublicKey, charset, keyFromFile);

            return client;
        }
        #endregion
复制代码

 

(2)调用SDK生成支付表单

 

复制代码
        #region 调用SDK生成支付表单
        public ActionResult CreatePayForm()
        {
            try
            {
                IAopClient client = GetAlipayClient();
                AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); 

                //在公共参数中设置回跳和通知地址
                request.SetReturnUrl(AlipayConfigHelper.return_url);
                request.SetNotifyUrl(AlipayConfigHelper.notify_url);
                var RRR=Request["orderNo"].ToString();
                //获取订单信息
                DataTable dr = collegeService.GetOrderInfo(RRR).Tables[0]; 

                //方法1:
                AlipayTradePayModel model = new AlipayTradePayModel(); 
                //填充业务参数
                model.Body = "商学院报名";                    //订单描述
                model.Subject = "商学院报名";                 //订单标题
                model.OutTradeNo = Request["orderNo"];        //商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
                model.TotalAmount = (Convert.ToInt32(dr.Rows[0]["Amount"])*1.0/100).ToString();           //订单总金额,单位为元,精确到小数点后两位
                model.ProductCode = "FAST_INSTANT_TRADE_PAY"; //销售产品码,商家和支付宝签约的产品码 (如 FAST_INSTANT_TRADE_PAY)
                request.SetBizModel(model); 

                //方法2:
                /**************************************************
                string Body = "商学院报名";
                string Subject = "商学院报名";
                string OutTradeNo = Request["orderNo"];
                string TotalAmount = Request["amount"];
                string ProductCode = "FAST_INSTANT_TRADE_PAY";
                request.BizContent = "{" +
                    "    \"body\":\""+ Body + "\"," +
                    "    \"subject\":\""+ Subject + "\"," +
                    "    \"out_trade_no\":\""+ OutTradeNo + "\"," +
                    "    \"total_amount\":"+ TotalAmount + "," +
                    "    \"product_code\":\""+ ProductCode + "\"" +
                    "  }";
                *********************************************************/
 

                //调用SDK生成表单
                AlipayTradePagePayResponse response = client.pageExecute(request);
                string form = response.Body;
                //Response.Write(form);
                return Content(form);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        #endregion
复制代码

 

(3)面跳转同步通知页面

 

复制代码
        #region 页面跳转同步通知页面
        /// <summary>
        /// 功能:页面跳转同步通知页面
        /// </summary>
        public ActionResult ReturnUrl()
        {
            // http://localhost:10231/College/ReturnUrl?
            // total_amount =0.01
            // ×tamp=2017-07-24+17%3A57%3A08
            // &sign=********
            // &trade_no=2017072421001004930200313969
            // &sign_type=RSA2
            // &auth_app_id=2016080500169628
            // &charset=utf-8
            // &seller_id=2088102169996595
            // &method=alipay.trade.page.pay.return
            // &app_id=2016080500169628
            // &out_trade_no=GM201707241756580000000001
            // &version=1.0 
//将同步通知中收到的所有参数都存放到map中 IDictionary<string, string> map = GetRequestGet(); if (map.Count > 0) //判断是否有带返回参数 { try { //支付宝的公钥 string alipayPublicKey = AlipayConfigHelper.alipayPublicKey; string signType = AlipayConfigHelper.signType; string charset = AlipayConfigHelper.charset; bool keyFromFile = false; // 获取支付宝GET过来反馈信息 bool verify_result = AlipaySignature.RSACheckV1(map, alipayPublicKey, charset, signType, keyFromFile); if (verify_result) { // 验证成功 Response.Redirect("/College/Index?id=1"); return Content("ok"); } else { return Content("验证失败"); } } catch (Exception e) { throw new Exception(e.Message); } } else { return Content("无返回参数"); } } /// <summary> /// 获取支付宝GET过来通知消息,并以“参数名=参数值”的形式组成数组 /// </summary> /// <returns>request回来的信息组成的数组</returns> public IDictionary<string, string> GetRequestGet() { int i = 0; IDictionary<string, string> sArray = new Dictionary<string, string>(); NameValueCollection coll; //Load Form variables into NameValueCollection variable. coll = Request.QueryString; // Get names of all forms into a string array. String[] requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) { sArray.Add(requestItem[i], Request.QueryString[requestItem[i]]); } return sArray; } #endregion
复制代码

 

(4)服务器异步通知页面

 

复制代码
        #region 服务器异步通知页面
        /// <summary>
        /// 功能:服务器异步通知页面
        /// 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格
        /// 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。
        /// 该页面调试工具请使用写文本函数logResult。
        /// 如果没有收到该页面返回的 success 信息,支付宝会在24小时内按一定的时间策略重发通知
        /// GmkCollege
        /// </summary>
        public void NotifyUrl()
        {
            // 获取支付宝Post过来反馈信息
            IDictionary<string, string> map = GetRequestPost();
            if (map.Count > 0) //判断是否有带返回参数
            {
                try
                {
                    //支付宝的公钥
                    string alipayPublicKey = AlipayConfigHelper.alipayPublicKey;
                    string signType = AlipayConfigHelper.signType;
                    string charset = AlipayConfigHelper.charset;
                    bool keyFromFile = false;                     

                    bool verify_result = AlipaySignature.RSACheckV1(map, alipayPublicKey, charset, signType, keyFromFile);
                    // 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
                    if (verify_result)
                    {
                        //商户订单号
                        string out_trade_no = map["out_trade_no"];
                        //支付宝交易号
                        string trade_no = map["trade_no"];
                        //交易创建时间
                        string gmt_create = map["gmt_create"];
                        //交易付款时间
                        string gmt_payment = map["gmt_payment"];
                        //通知时间
                        string notify_time = map["notify_time"];
                        //通知类型  trade_status_sync
                        string notify_type = map["notify_type"];
                        //通知校验ID
                        string notify_id = map["notify_id"]; 
                        //开发者的app_id
                        string app_id = map["app_id"];
                        //卖家支付宝用户号
                        string seller_id = map["seller_id"];
                        //买家支付宝用户号
                        string buyer_id = map["buyer_id"];
                        //实收金额
                        string receipt_amount = map["receipt_amount"];  
                        //交易状态
                        //交易状态TRADE_FINISHED的通知触发条件是商户签约的产品不支持退款功能的前提下,买家付款成功;
                        //或者,商户签约的产品支持退款功能的前提下,交易已经成功并且已经超过可退款期限
                        //状态TRADE_SUCCESS的通知触发条件是商户签约的产品支持退款功能的前提下,买家付款成功
                        if (map["trade_status"] == "TRADE_FINISHED" || map["trade_status"] == "TRADE_SUCCESS")
                        {         
                            //判断该笔订单是否在商户网站中已经做过处理
                            DataTable dd=collegeService.OrderPayNot(out_trade_no).Tables[0];
                            if (Convert.ToInt32(dd.Rows[0]["Status"]) == 0)
                            {
                                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                                #region 将数据提添加到集合中
                                Dictionary<string, string> myDic = new Dictionary<string, string>();
                                myDic.Add("PayTradeNo", trade_no);
                                myDic.Add("Status", "1");
                                myDic.Add("Type", "0");
                                myDic.Add("PayTime", gmt_payment);
                                myDic.Add("BuyerId", buyer_id);
                                myDic.Add("OrderNo", out_trade_no);
                                #endregion 

                                #region 添加数据到数据库 
                                bool res = collegeService.AddPayInfo(myDic);
                                if (res == false)
                                {
                                    Response.Write("添加支付信息失败!");
                                }
                                #endregion

                                Response.Write("success");  //请不要修改或删除
                            }
                        }
                    }
                    // 验签失败则记录异常日志,并在response中返回failure.
                    else
                    {            
                        Response.Write("验证失败");
                    }
                }
                catch (Exception e)
                {
                    throw new Exception(e.Message);
                }
            }
            else
            {
                Response.Write("无返回参数");
            }
        }

        /// <summary>
        /// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
        /// </summary>
        /// <returns>request回来的信息组成的数组</returns>
        public IDictionary<string, string> GetRequestPost()
        {
            int i = 0;
            IDictionary<string, string> sArray = new Dictionary<string, string>();
            NameValueCollection coll;
            //Load Form variables into NameValueCollection variable.
            coll = Request.Form;

            // Get names of all forms into a string array.
            String[] requestItem = coll.AllKeys;

            for (i = 0; i < requestItem.Length; i++)
            {
                sArray.Add(requestItem[i], Request.Form[requestItem[i]]);
            }
            return sArray;
        }
        #endregion
复制代码

 

(5)退款

 

复制代码
        #region 退款
        /// <summary>
        /// 支付宝退款
        /// </summary>
        /// <returns></returns>
        public string Refund(string OrderNo)
        {
            //查询要退款的订单信息
            DataTable dt = collegeService.GetOrderInfo(OrderNo).Tables[0];
            IAopClient client = GetAlipayClient();
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradePayModel model = new AlipayTradePayModel();
            //填充业务参数  
            request.BizContent = "{" +
            "    \"out_trade_no\":\"" + dt.Rows[0]["OrderNo"] + "\"," +
            "    \"trade_no\":\"" + dt.Rows[0]["TradeNo"] + "\"," +
            "    \"refund_amount\":" + ((int)dt.Rows[0]["Amount"] * 1.0 / 100) + "," +
            "    \"refund_reason\":\"正常退款\"," +
            "    \"operator_id\":\"OP001\"," +
            "    \"store_id\":\"NJ_S_001\"," +
            "    \"terminal_id\":\"NJ_T_001\"" +
            "  }";

            AlipayTradeRefundResponse response = client.Execute(request);
            string Info = response.Body;
            //{ "alipay_trade_refund_response":{
            //"code":"10000",
//"msg":"Success", //"buyer_logon_id":"xso***@sandbox.com", //"buyer_user_id":"2088102172262939",
//"fund_change":"Y", //"gmt_refund_pay":"2017-07-31 15:28:08",
//"open_id":"20881027348761637209827442915993", //"out_trade_no":"GM201707311527020000000001", //"refund_fee":"33.33", //"send_back_fee":"0.00", //"trade_no":"2017073121001004930200315623"}, //"sign":"**********"} if (response.Code == "10000") { int RefundAmount =Convert.ToInt32(Convert.ToDecimal(response.RefundFee)*100); DateTime RefundTime =Convert.ToDateTime(response.GmtRefundPay); int Status = 2; //已退 bool res=collegeService.UpdateRefundInfo(OrderNo,RefundAmount, RefundTime, Status); return JsonHelper.DataJson(0, "退款成功!"); } else { return JsonHelper.DataJson(1, "退款失败!"); } } #endregion
复制代码

 

第6步:新建支付订单确认页面

  

复制代码
<div class="zhezhaoceng dd" style="display: none">
    <div class="duihuakuang ee" style="display: none">
        <div class="success-alert ">
            <p>支付核实:</p>
        </div>
        <form method="post" id="OrderForm">
            <div>
                <input type="hidden" name="OrderNo" id="orderNo" value="" />
                <input type="hidden" name="Amount" id="amount" value="" />
                <div>
                    <p>商学院报名</p>
                    <p>订单号:<span id="OrderNo"></span></p>
                    <p>支付金额:<font color="red"><b><span id="Currency">¥</span><span id="Amount"></span></b></font></p>
                </div>
                <div>
                    <input class="submit next-btn" type="button" value="立即支付" onclick="go_pay()" />
                </div>
            </div>
        </form>
    </div>   
</div>   

<div class="pay_method" style="display: none">
  <div class="pay-alert ">
    <p>支付方式</p>
    <p><span id="pay_button"></span></p>
  </div>
</div>

复制代码

第7步:js处理

 

复制代码
function go_pay() {
    $("#OrderForm").ajaxSubmit({
        url: "/College/CreatePayForm",
        type: "post",
        success: function (data) {
            $(".detail-message8").css({ "display": "none" });
            $(".dd").css({ "display": "none" });
            $(".ee").css({ "display": "none" });
            $(".pay_method").css({ "display": "none" });
            $("#pay_button").html(data);
        }
    });
}
复制代码

 

第8步:花生壳

由于支付宝异步回调测试需要将网站发布到公网,所以需要将本地域名映射到公网

(1)登录

http://hsk.oray.com/

用户名:************

密  码:*********

(2)实名认证

https://console.oray.com/

 

 (3)添加映射

https://b.oray.com/forward/

 

(4)访问将localhost换成zouke1220.oicp.net进行访问

http://zouke1220.oicp.net/College/Index

 

点击“报名”

 

点击“下一步”

复制代码
function next_step() {
    $("#formID").ajaxSubmit({
        url: "/College/ValidateUserInfo",
        type: "post",
        success: function (data) {
            if (data == "ok") {
                $(".detail-message8").css({ "display": "none" });
                $(".detail-message6").css({ "display": "none" });
                $(".detail-message7").css({ "display": "block" });
            } else {
                alert(data);
                return false;
            }           
        }
    });
}
复制代码

 

 

点击“同意”

复制代码
function iAgree(){
    if ($("#checkedd").is(":checked")) {
        $(".detail-message6").css({ "display": "none" });
        $(".detail-message7").css({ "display": "none" });
        $(".detail-message8").css({ "display": "block" });
    } else {
        return false;
    }
}
复制代码

 

点击“去支付”跳到订单确认页

复制代码
function order_confirm() {
    $("#SignUpForm").ajaxSubmit({
        url: "/College/SignUp",
        type: "post",
        success: function (data) {
            var obj=eval('(' + data + ')'); //json转json对象
            if (obj.code == 0) {
                $(".dd").css({ "display": "block" });
                $(".ee").css({ "display": "block" });
                $("#OrderNo").html(obj.data.OrderNo);
                $("#Amount").html(obj.data.Amount);
                $("#orderNo").val(obj.data.OrderNo);
$("#amount").val(obj.data.Amount); } else { alert(obj.msg); return false; } } }); }
复制代码

 

点击“立即支付”

复制代码
function go_pay() {
    $("#OrderForm").ajaxSubmit({
        url: "/College/CreatePayForm",
        type: "post",
        success: function (data) {
            $(".detail-message8").css({ "display": "none" });
            $(".dd").css({ "display": "none" });
            $(".ee").css({ "display": "none" });
            $(".pay_method").css({ "display": "none" });
            $("#pay_button").html(data);
        }
    });
}
复制代码

 

点击“登录账户付款”

 

 点击“下一步”

 

点击“确认付款”

 

自动跳转到异步回调页面,将支付成功信息插入数据库

http://zouke1220.oicp.net/College/NotifyUrl

并跳转到同步通知页面显示支付成功页面

http://zouke1220.oicp.net/College/ReturnUrl

 

 

第9步:所有测试通过后将第4步配置信息换成正式环境的

 

注:部分页面还需要美化,完整版项目参见:http://www.gmkcn.com/

posted @ 2020-12-30 08:49  nkandkn  阅读(522)  评论(0编辑  收藏  举报