.NET MVC 支付寶支付(即時到帳)

已經很久沒有搞過.NET了,朋友有一個網站 ,須要接入支付寶功能,從新對接了一下。web

一、開發前,須要一個企業支付寶帳號登陸,獲取 PID和 配置密鑰json

官方文檔:https://docs.open.alipay.com/62/104743/app

二、下載官方的服務端代碼異步

官方下載地址:https://docs.open.alipay.com/270/106291/xss

這裏要注意一下,官方的服務端代碼,是沒有工程文件的,須要在vs2013中,打開-網站,加載整個文件。配置pid和ras密鑰,是能夠跑起來的,效果還不錯,支付和退款的功能都有了。ide

三、官方給過來的是webform的代碼,改爲MVC也很簡單,代碼以下post

支付和回調通知:網站

namespace YinCai.Web.Controllers
{
    public class AlipayController : BaseController
    {
        //
        // GET: /Alipay/
        public ActionResult Pay(int Id)
        {
            ScOrder orderModel = BLLSession.IScOrderService.GetOne(m => m.OrderID == Id);

            DefaultAopClient client = new DefaultAopClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", "1.0", AlipayConfig.sign_type, AlipayConfig.alipay_public_key, AlipayConfig.charset, false);

            // 外部訂單號,商戶網站訂單系統中惟一的訂單號
            string out_trade_no = orderModel.OrderNo.ToString();

            // 訂單名稱
            string subject = orderModel.OrderName;

            // 付款金額
            string total_amout = orderModel.PayPrice.ToString();

            // 商品描述
            string body = "";

            // 組裝業務參數model
            AlipayTradePagePayModel model = new AlipayTradePagePayModel();
            model.Body = body;
            model.Subject = subject;
            model.TotalAmount = total_amout;
            model.OutTradeNo = out_trade_no;
            model.ProductCode = "FAST_INSTANT_TRADE_PAY";

            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
            // 設置同步回調地址
            request.SetReturnUrl(Common.ConfigHelper.AlipayReturnUrl);
            // 設置異步通知接收地址
            request.SetNotifyUrl(Common.ConfigHelper.AlipayNotifyUrl);
            // 將業務model載入到request
            request.SetBizModel(model);

            AlipayTradePagePayResponse response = null;
            try
            {
                response = client.pageExecute(request, null, "post");
                string rep = response.Body.Replace("<input", "<input type='hidden'");
                return Content(rep);
            }
            catch (Exception exp)
            {
                Common.LogHelper.WriteLog(exp, "支付寶跳轉失敗!");
                throw exp;
            }
        }

        // 支付寶異步通知
        // gmt_create=2019-09-01+14%3a12%3a35&charset=UTF-8&gmt_payment=2019-09-01+14%3a12%3a38&notify_time=2019-09-01+14%3a12%3a39&subject=1&sign=XNAQMiLoXKxUoZEfiSkNxmiBJDnw5xszNiFuu20XQzmnLbwuwDXVFsaYaR8OtV6qD%2bsymeZjSfm0%2fvAY1q7V2QiyTtMqnvBG23nbeklLxGvY2GKOKnULI8M7Wl9dJs70bbMsENhEY1ATOLpqven2dcJJkLIwIHec%2fKgU4EdrEbR7nNaa89m3iDkO6wd3uKyrBvhfE208kPbJc62AGPa46V1HvzmtL66kbgPVBG9K7yI5En%2ba1y6fMs%2fmOJecrNt%2bozXcw0Bkw2P47a9A5drkH1wakkiK3a4SOsJekb7mr1jtphSLIaq5SoImwZsFLtnM6Hjrl8lhUTjl9jQrwPAFzw%3d%3d&buyer_id=2088302047105765&invoice_amount=0.01&version=1.0&notify_id=2019090100222141238005760509611566&fund_bill_list=%5b%7b%22amount%22%3a%220.01%22%2c%22fundChannel%22%3a%22ALIPAYACCOUNT%22%7d%5d&notify_type=trade_status_sync&out_trade_no=2019090110003&total_amount=0.01&trade_status=TRADE_SUCCESS&trade_no=2019090122001405760595489512&auth_app_id=2019082266394313&receipt_amount=0.01&point_amount=0.00&buyer_pay_amount=0.01&app_id=2019082266394313&sign_type=RSA2&seller_id=2088631096812893
        public ActionResult Notify()
        {
            Common.LogHelper.WriteInfoLog("支付寶回調通知---" + Request.Form.ToString());
            /* 實際驗證過程建議商戶添加如下校驗。
            一、商戶須要驗證該通知數據中的out_trade_no是否爲商戶系統中建立的訂單號,
            二、判斷total_amount是否確實爲該訂單的實際金額(即商戶訂單建立時的金額),
            三、校驗通知中的seller_id(或者seller_email) 是否爲out_trade_no這筆單據的對應的操做方(有的時候,一個商戶可能有多個seller_id/seller_email)
            四、驗證app_id是否爲該商戶自己。
            */
            long orderno = long.Parse(Request["out_trade_no"]);
            string appId = Request["app_id"];
            //string seller_id = Request.Form["seller_id"];
            string totalAmount = Request["total_amount"];
            ScOrder orderModel = BLLSession.IScOrderService.GetOne(m => m.OrderNo == orderno);
            if (orderModel == null || appId != AlipayConfig.app_id || orderModel.PayPrice != decimal.Parse(totalAmount))
            {
                Common.LogHelper.WriteLog("支付寶回調信息異常" + Request.Form.ToString());
                return Content("fail"); ;
            }

            Dictionary<string, string> sArray = GetRequestPost();
            if (sArray.Count != 0)
            {
                bool flag = AlipaySignature.RSACheckV1(sArray, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type, false);
                if (flag)
                {
                    //交易狀態
                    //判斷該筆訂單是否在商戶網站中已經作過處理
                    //若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
                    //請務必判斷請求時的total_amount與通知時獲取的total_fee爲一致的
                    //若是有作過處理,不執行商戶的業務程序

                    //注意:
                    //退款日期超過可退款期限後(如三個月可退款),支付寶系統發送該交易狀態通知
                    string trade_status = Request["trade_status"];
                    orderModel.PayNotifyTime = DateTime.Now;
                    BLLSession.IScOrderService.ModifyModel(orderModel);

                    Common.LogHelper.WriteInfoLog("支付寶驗籤成功,支付成功---" + orderno);
                    return Content("success");
                }
                else
                {
                    //Response.Write("fail");
                    Common.LogHelper.WriteLog("支付寶回調通知驗籤失敗---" + Request.Form.ToString());
                    return Content("fail");
                }
            }
            return Content("fail");
        }

        // 支付寶同步通知,支付成功頁 ReturnUrl
        // /alipay/PaySuccess/2019090110021?charset=UTF-8&out_trade_no=2019090110021&method=alipay.trade.page.pay.return&total_amount=0.01&sign=fUsyiAQiFSpHOmBn%2Bd0QZbdfdGyXtfIHYeZziKIpJGJpa38L7Jx1C4jnaCRuYuqTnMvawwg0ExqXpT6T88BPTdjK5Rcm9tL6zL8U8N%2B7lHEMyPMT2LaiuFAGzmnlSZyVJleGdUEzgvQZ3jbX9OdZEpLFOVyRnj8Ax%2B%2BlW5M9oInyncCg6VBw2%2BbDG5m8epPyBFUIBWxQINcyKrCDbDFwVIxGjji%2FW11adC7il8earoOB4gXKArxVB7SVYZcHXjiONZJEXyRMMuscD4ZV%2FPwH3Wtf5BUv%2BHtHqJWr8a5u9ijZCI7GzZwUdDYKnOamqp7HMFychsrUgAAcVPfdjAxe%2Bg%3D%3D&trade_no=2019090122001405760597459839&auth_app_id=2019082266394313&version=1.0&app_id=2019082266394313&sign_type=RSA2&seller_id=2088631096812893&timestamp=2019-09-01+18%3A18%3A20
        public ActionResult PaySuccess()
        {
            Common.LogHelper.WriteLog("支付寶同步驗證參數----" + Request.RawUrl);
            long orderno = long.Parse(Request["out_trade_no"]);
            string appId = Request["app_id"];
            string totalAmount = Request["total_amount"];
            ScOrder orderModel = BLLSession.IScOrderService.GetOne(m => m.OrderNo == orderno);
            if (orderModel == null || appId != AlipayConfig.app_id || orderModel.PayPrice != decimal.Parse(totalAmount))
            {
                Common.LogHelper.WriteLog("支付寶同步驗證異常----" + Request.RawUrl);
                return RedirectToAction("payfail","alipay"); 
            }

            /* 實際驗證過程建議商戶添加如下校驗。
                一、商戶須要驗證該通知數據中的out_trade_no是否爲商戶系統中建立的訂單號,
                二、判斷total_amount是否確實爲該訂單的實際金額(即商戶訂單建立時的金額),
                三、校驗通知中的seller_id(或者seller_email) 是否爲out_trade_no這筆單據的對應的操做方(有的時候,一個商戶可能有多個seller_id/seller_email)
                四、驗證app_id是否爲該商戶自己。
            */
            Dictionary<string, string> sArray = GetRequestGet();
            if (sArray.Count != 0)
            {
                bool flag = AlipaySignature.RSACheckV1(sArray, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type, false);
                if (flag)
                {
                    string trade_no = Request["trade_no"];
                    orderModel.OrderStatus = (int)OrderStateEnum.Paid;
                    orderModel.PayType = (int)PayTypeEnum.Alipay;
                    orderModel.PayTime = DateTime.Now;
                    orderModel.PayTradeNo = trade_no;
                    BLLSession.IScOrderService.ModifyModel(orderModel);
                }
                else
                {
                    Common.LogHelper.WriteLog("支付寶同步驗證失敗----" + Request.RawUrl);
                    return RedirectToAction("payfail", "alipay"); 
                }
            }

            return View(orderModel);
        }

        public ActionResult PayFail() 
        {
            return View();
        }


        #region --參數獲取組裝
        // get 方式組裝回調參數
        public Dictionary<string, string> GetRequestGet()
        {
            int i = 0;
            Dictionary<string, string> sArray = new Dictionary<string, string>();
            NameValueCollection coll;
            //coll = Request.Form;
            coll = Request.QueryString;
            String[] requestItem = coll.AllKeys;
            for (i = 0; i < requestItem.Length; i++)
            {
                sArray.Add(requestItem[i], Request.QueryString[requestItem[i]]);
            }
            return sArray;
        }

        // post 方式組裝回調參數
        public Dictionary<string, string> GetRequestPost()
        {
            int i = 0;
            Dictionary<string, string> sArray = new Dictionary<string, string>();
            NameValueCollection coll;
            //coll = Request.Form;
            coll = Request.Form;
            String[] requestItem = coll.AllKeys;
            for (i = 0; i < requestItem.Length; i++)
            {
                sArray.Add(requestItem[i], Request.Form[requestItem[i]]);
            }
            return sArray;
        }
        #endregion
    }
}
View Code

退款:ui

        // 退款成功返回
        //{"alipay_trade_refund_response":{"code":"10000","msg":"Success","buyer_logon_id":"jys***@163.com","buyer_user_id":"2088302047105765","fund_change":"Y","gmt_refund_pay":"2019-09-01 16:08:02","out_trade_no":"2019090110004","refund_fee":"0.01","send_back_fee":"0.00","trade_no":"2019090122001405760597435123"},"sign":"IL+00djGKL/7UBxQS9oTPwKySlzHrnZLtzsqbH1ZkyAgv8E2Hl+PZZtbVAnH7+7XtpfLDxwY+4EyN0EmL75reU3fiBmpmL9JROsCQy2hQG4WmeSB2GKg2kFyAgmOh7uoYbKW/HWV35NfxdpoCZNdGyYWWhxIz0qui2xIH3u46WPBN5Yk5uMmhNNzUP8pW18XxssI7htqD3ey7qagntwPFTlL5JeUmz8Fbusk+xQJ3p6wj58IHetm2Mio1KDSEZblE/2+T7ZkgrBrQqw77Y4DpCi8m98MFMdAMCQ/3qiWH65H4cPPXXrQ2pprVLA6m8DjmPhzsuYk7noyHYJo4uMFwg=="}
        [HttpPost]
        public ActionResult Refund(int Id)
        {
            ScOrder orderModel = BLLSession.IScOrderService.GetOne(m=>m.OrderID == Id);
            if (orderModel == null)
            {
                return JsonMsgErr("退款出錯拉");
            }

            DefaultAopClient client = new DefaultAopClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", "1.0", AlipayConfig.sign_type, AlipayConfig.alipay_public_key, AlipayConfig.charset, false);

            // 商戶訂單號,和交易號不能同時爲空
            string out_trade_no = orderModel.OrderNo.ToString();

            // 支付寶交易號,和商戶訂單號不能同時爲空
            string trade_no = orderModel.PayTradeNo;

            // 退款金額,不能大於訂單總金額
            string refund_amount = orderModel.PayPrice.ToString();

            // 退款緣由
            string refund_reason = "正常退款";

            // 退款單號,同一筆屢次退款須要保證惟一,部分退款該參數必填。
            string out_request_no = orderModel.OrderNo.ToString();

            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.OutTradeNo = out_trade_no;
            model.TradeNo = trade_no;
            model.RefundAmount = refund_amount;
            model.RefundReason = refund_reason;
            model.OutRequestNo = out_request_no;

            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            request.SetBizModel(model);

            AlipayTradeRefundResponse response = null;
            try
            {
                response = client.Execute(request);
                Common.LogHelper.WriteInfoLog("支付寶退款成功---" + response.Body);

                RefundModel refundModel = JsonConvert.DeserializeObject<RefundModel>(response.Body);
                string code = refundModel.alipay_trade_refund_response.code;
                // 能夠重複退款,因此不須要判斷fund_change
                string fund_change = refundModel.alipay_trade_refund_response.fund_change; 
                if (code == "10000") 
                {
                    orderModel.RefundTime = DateTime.Now;
                    orderModel.RefundReason = "正常退款";
                    orderModel.OrderStatus = (int)OrderStateEnum.Refund;
                    BLLSession.IScOrderService.ModifyModel(orderModel);
                   return JsonMsgOk("退款成功");
                }
            }
            catch (Exception exp)
            {
                throw exp;
            }

            return JsonMsgOk("退款失敗");
        }
View Code
相關文章
相關標籤/搜索