Core3.1 微信v3 JSAPI支付 退款

1、前言

上一篇寫了《Core3.1 微信v3 JSAPI支付》,這個屬於v3的接口規則,現在研究了下退款的接口我寫的時候它屬於v2接口規則文檔。但凡微信支付文檔裏面寫清楚點我也不會在這裏記錄一下。

2、乾貨

     接口文檔https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 現在看看是v3接口的了 我的天,他們在逗我玩一樣,v2的寫好了v3就放出來了。命途多舛啊。 v2請求的是xml文檔格式的,這裏又要溫習一下舊知識了。

     當時我記得清清楚楚 就說了請求要加簽名,證書雙向驗證。官網文檔沒有寫。Net的怎麼加載證書 就說了一句windows下面直接安裝證書就好了。結果 都是Bad Request 還是人工諮詢吧 到最後才把代碼找給我。我問人工客戶地址給我看看,他說沒有地址(肺都氣炸。。。)

3、代碼

這是封裝的一個請求 ,代碼加在上篇文章裏面的那個請求裏面

     /// <summary>
         ///postXML請求
        /// </summary>
        /// <param name="url">地址</param>
        /// <param name="requestString">參數(json格式)</param>
        /// <param name="path">p12文件路徑</param>
        /// <param name="certPwd">密碼</param>
        /// <returns>string</returns>
        public string PostXml(string url, string requestString,string path, string certPwd)
        {
            var handler = new HttpClientHandler
            {
                ClientCertificateOptions = ClientCertificateOption.Manual,
                SslProtocols = SslProtocols.Tls12,
                ServerCertificateCustomValidationCallback = (x, y, z, m) => true,
            };

            //var path = Path.Combine(AppContext.BaseDirectory, "cert\\iot3rd.p12");
            handler.ClientCertificates.Add(new X509Certificate2(path, certPwd));

            var client = new HttpClient(handler);

            var content = new StringContent(requestString);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            //GetAwaiter().GetResult();
            var httpResponseMessage = client.PostAsync(url, content).Result.Content.ReadAsStringAsync().Result;
            return httpResponseMessage;
        }

 

   最主要的就是加了認證文件,p12文件路徑跟密碼,一般密碼都是商戶號。這就是微信文檔說的雙向驗證

    拼接請求參數,官網文檔有驗證這個的。排序的話我自己手動固定排序的,就那幾個字段ABCDEFG都可以看到0.0。

 

 /// <summary>
        /// 退費需要的字符
        /// </summary>
        /// <param name="hospInfo"></param>
        /// <param name="regOrder"></param>
        /// <returns></returns>
        private string RequestRetreatParmar(Entity.Models.HospInfo hospInfo, RegOrder regOrder)
        {
            var guid = Guid.NewGuid().ToString("N").Substring(0, 30);
            var retreatNo = OrderHelper.GenerateNo("CFTF");
            int money = Convert.ToInt32(regOrder.OwnFee * 100);
            //簽名
            string message = $"appid={hospInfo.WxAppid}&mch_id={hospInfo.WxMchid}&nonce_str={guid}&out_refund_no={retreatNo}&refund_desc=客戶預約掛號退款&refund_fee={money}&total_fee={money}&transaction_id={regOrder.PlatformTradeId}&key={hospInfo.WxKey}";
            var signMd5 = SecurityHelper.MD5EncrytString(message).ToUpper();
            var dto = new
            {
                xml= new
                {
                    appid = hospInfo.WxAppid,
                    mch_id = hospInfo.WxMchid,
                    nonce_str = guid,
                    sign = signMd5,
                    transaction_id = regOrder.PlatformTradeId,
                    out_refund_no = retreatNo,
                    total_fee = money,
                    refund_fee = money,
                    refund_desc = "客戶預約掛號退款",
                }
            };
            var json = JsonConvert.SerializeObject(dto);
            
            return json;
        }

  我把這裏MD5加密的代碼也貼上

        /// md5加密
        /// </summary>
        /// <param name="inputString">字符串</param>
        /// <returns>加密過的字符串(不可以解密)</returns>
        public static string MD5EncrytString(string inputString)
        {
            MD5 md5 = System.Security.Cryptography.MD5.Create();
            byte[] buffer = Encoding.UTF8.GetBytes(inputString);
            byte[] md5Buffer = md5.ComputeHash(buffer);
            md5.Clear();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < md5Buffer.Length; i++)
            {
                sb.Append(md5Buffer[i].ToString("x2"));
            }
            return sb.ToString();
        }

 請求這裏,只要Return_code等於SUCCESS下面就可以做自己的業務邏輯了。裏面返回的字段肯定有一個是你自己寫了傳進去的。通過這個字段查詢數據庫完成自己的邏輯。

 //微信退費操作
                    var url = RequestUrl.PAYREFUND;
                    var json = RequestRetreatParmar(hospInfoMoidel, regOrderModel);
                    var xml = JsonConvert.DeserializeXmlNode(json);
                    var postData = xml.InnerXml;
                    var pathfile = _webHostEnvironment.WebRootPath + "/arsjkll/apiclient_cert.p12";
                    var wxPostResult = _httpClientFactoryHelper.PostXml(url, postData, pathfile, hospInfoMoidel.WxSslcertpassword);
                    SaveLog("WeChatTuiFei", wxPostResult);
                    var resultRep = wxPostResult.Replace("<![CDATA[", "").Replace("]]>", "");
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(resultRep);
                    string jsonText = JsonConvert.SerializeXmlNode(doc);
                    SaveLog("WeChatTuiFei", jsonText);
                    var resultModel = JsonConvert.DeserializeObject<RetreatNoResulDtoXml>(jsonText);
                    var resultModelXml = resultModel.Xml;
                    if (resultModelXml.Result_Code == "SUCCESS")
                    {
                        regOrderModel.RefundNo = resultModelXml.Out_Refund_No;
                        regOrderModel.RefundState = 1;
                        regOrderModel.RefundResult = resultModelXml.Return_Code;
                        regOrderModel.RefundTime = DateTime.Now;

                        payLogModel.RefundNo = resultModelXml.Out_Refund_No;
                        payLogModel.RefundState = 1;
                        payLogModel.RefundResult = resultModelXml.Return_Code;
                        payLogModel.RefundTime = DateTime.Now;
                        await _db.SaveChangesAsync();
                        return Result.ToSuccess(resultModel);
                    }
                    else
                        return Result.ToFail(resultModelXml.Return_Msg);

 

我這裏沒有用notify_url返回接口 直接得到結果。下面是接收的Dto

public class RetreatNoResulDtoXml
    {
        public RetreatNoResulDto Xml { get; set; }
    }
    /// <summary>
    /// 退號|退費結果
    /// </summary>
    public class RetreatNoResulDto
    {
        /// <summary>
        /// 返回狀態碼
        /// SUCCESS:退款申請接收成功,結果通過退款查詢接口查詢
        /// FAIL:提交業務失敗
        /// 此字段是通信標識,非交易標識,交易是否成功需要查看result_code來判斷
        /// 示例值:SUCCESS
        /// </summary>
        public string Return_Code { get; set; }
        /// <summary>
        /// 返回信息
        /// 返回信息,如非空,爲錯誤原因 
        /// 簽名失敗
        /// 參數格式校驗錯誤
        /// 示例值:簽名失敗
        /// </summary>
        public string Return_Msg { get; set; }

        //返回狀態碼(return_code)爲SUCCESS的時候,包含以下字段


        /// <summary>
        /// 業務結果
        /// SUCCESS/FAIL
        /// 示例值:SUCCESS
        /// </summary>
        public string Result_Code { get; set; }
        /// <summary>
        /// 錯誤代碼
        /// 示例值:SYSTEMERROR
        /// </summary>
        public string Err_Code { get; set; }
        /// <summary>
        /// 錯誤代碼描述
        /// 結果信息描述
        ///示例值:系統錯誤
        /// </summary>
        public string Err_Code_Des { get; set; }
        public string Appid { get; set; }
        public string Mch_Id { get; set; }
        public string Sub_Appid { get; set; }
        public string Sub_Mch_Id { get; set; }
        public string Nonce_Str { get; set; }
        /// <summary>
        /// 簽名
        /// </summary>
        public string Sign { get; set; }
        public string Transaction_Id { get; set; }
        public string Out_Trade_No { get; set; }
        public string Out_Refund_No { get; set; }
        public string Refund_Id { get; set; }
        public int Refund_Fee { get; set; }
        public int Settlement_Refund_Fee { get; set; }
        public int Total_Fee { get; set; }
        public int Settlement_Total_Fee { get; set; }
        public string Fee_Type { get; set; }
        public int Cash_Fee { get; set; }
       
    }

 

返回的結果我存了日誌  真不知道中間<![CDATA[SUCCESS]]> 這個花裏胡哨的是咋想的 我直接 全部替換 ""  了。

<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx6ed9112323b1f1d3e04]]></appid>
<mch_id><![CDATA[16045678769]]></mch_id>
<nonce_str><![CDATA[9xonPINPBGO4y8WW]]></nonce_str>
<sign><![CDATA[DABC2420B7B03FBA4D0027A9EBBF54D7]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<transaction_id><![CDATA[42000009嗚嗚嗚嗚276477024]]></transaction_id>
<out_trade_no><![CDATA[YYGH20210129164746001]]></out_trade_no>
<out_refund_no><![CDATA[CFTF20210129164806002]]></out_refund_no>
<refund_id><![CDATA[50300407262021012905921959108]]></refund_id>
<refund_channel><![CDATA[]]></refund_channel>
<refund_fee>440</refund_fee>
<coupon_refund_fee>0</coupon_refund_fee>
<total_fee>440</total_fee>
<cash_fee>440</cash_fee>
<coupon_refund_count>0</coupon_refund_count>
<cash_refund_fee>440</cash_refund_fee>
</xml>

4、總結

看着幾行代碼 還給我排隊等了好久終於問人工解決的,之前都沒說請求頭裏面加載用戶證書,可能是v3出來了沒太在意吧。後面看看 v3接口 看樣子應該跟統一下單一樣了吧只要調用請求那個方法就可以了! 

時間,抓起了就是黃金,虛度了就是流水;書,看了就是知識,沒看就是廢紙;理想,努力了才叫夢想,放棄了那只是妄想。努力,雖然未必會收穫,但放棄,就一定一無所獲。

本文地址:https://www.cnblogs.com/w5942066/p/14346015.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章