企業微信支付的發送紅包及相關介面使用

来源:https://www.cnblogs.com/wuhuacong/archive/2019/02/25/10431609.html
-Advertisement-
Play Games

企業微信的支付自從企業號變化為企業微信後,增加了一些支付介面以及對很多介面進行了調整,企業微信的支付處理也是變化了不少,往往有時候碰到不少坑,一步一個腳印趟過來的;企業微信支付是需要結合微信商戶後臺進行處理,有時候也需要設置好商戶平臺的相關處理,才能進行發送紅包、支付到個人等等支付處理。本篇隨筆介紹... ...


企業微信的支付自從企業號變化為企業微信後,增加了一些支付介面以及對很多介面進行了調整,企業微信的支付處理也是變化了不少,往往有時候碰到不少坑,一步一個腳印趟過來的;企業微信支付是需要結合微信商戶後臺進行處理,有時候也需要設置好商戶平臺的相關處理,才能進行發送紅包、支付到個人等等支付處理。本篇隨筆介紹在企業微信的支付處理中的發送紅包的操作相關內容。

1、企業微信的支付介面

我們查看企業微信API的目錄,可以看到企業微信支付的相關介紹,如下所示。

 

1)常見錯誤處理

企業微信支付,經常見到的錯誤信息,就是簽名錯誤這個操作,這個很多人出招,解決方法各種各樣,其實很多可能是不符合的,這樣排查問題起來就很吃力。

這裡需要遵循官方的解析進行排查,特別對參數的順序和數量進行核對,註意不要增加多一個參數,否則都容易出現簽名錯誤。

我就是在官方需要參數都有了,列印輸出的格式也沒問題,就是不小心多了一個參數(還是升級前有的一個),導致錯誤很難排查,弄得很頭大。

一般來說發送企業紅包,很容易發生簽名錯誤的情況,請檢查以下內容
 1、企業微信的CorpID/CorpSecret
 2、企業微信的支付Secret和商戶的API支付秘鑰
 3、參數不能多也不能少(重要),如很多時候由於版本原因這裡不小心多了一個total_num導致簽名錯誤
 4、商戶平臺的證書和密碼是否正確

另外,除了這些問題外,重要的問題就是簽名的處理了,微信支付除了有一個常規的簽名sign參數外,還增加了一個workwx_sign的參數,兩者的規則是不同的。

workwx_sign參數在前,使用系統給出的計算方式計算後,然後在計算sign參數,sign參數的計算是包含本身之外的所有參數進行計算,包括了workwx_sign參數。

2)簽名參數處理

對於企業微信的簽名workwx_sign參數,不要將參數全部參與計算簽名,否則會返回微信簽名錯誤!

發紅包api固定如下幾個欄位參與簽名:
act_name
mch_billno
mch_id
nonce_str
re_openid
total_amount
wxappid

付款api固定如下幾個欄位參與簽名:
amount
appid
desc
mch_id
nonce_str
openid
partner_trade_no
ww_msg_type

計算企業微信簽名的字元串最後拼的secret是企業微信管理端支付應用頁面的secret,如下圖所示。

示例:請求內容:
act_name XXX
mch_billno 11111234567890
mch_id 10000098
nonce_str qFKEgfig76DF9912fewmkp
re_openid oxTWIuGaIt6gTKsQRLau2M0yL16E
total_amount 100
wxappid wx123456789

第一步: 對參數按照key=value的格式,並按照參數名ASCII字典序排序如下
stringA=”act_name=XXX&mch_billno=11111234567890&mch_id=10000098&nonce_str=qFKEgfig76DF9912fewmkp&re_openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&total_amount=100&wxappid=wx123456789
第二步:拼接企業微信支付應用secret(參見企業微信管理端支付應用頁面):
stringSignTemp=”stringA&secret=192006250b4c09247ec02edce69f6a2d”
sign=MD5(stringSignTemp).toUpperCase()

 

2、企業微信發送紅包

測試企業微信發送紅包和直接支付的介面,響應效果如下所示

在企業微信中,常用到的企業微信的userid,不過發送紅包則需要把userid轉換為微信的openid進行使用,轉換函數根據UserID 換取用戶的OpenId 如下。

一般封裝一個函數來使用即可。

        private string GetOpenId(string userid)
        {
            //根據UserID 換取用戶的OpenId
            ICorpBasicApi basicAPi = new CorpBasicApi();
            return basicAPi.ConvertToOpenId(this.token, userid);
        }

發送企業紅包調用如下代碼所示

//構建發送紅包的參數信息
SendRedPackJson packJson = new SendRedPackJson()
{ 
    act_name = "恭喜發財",
    client_ip = NetworkUtil.GetIPAddress(),
    remark = "企業紅包",
    wishing = "企業紅包",
    total_amount = 100,
    total_num = 1,
    re_openid = openid //發送給用戶的OpenID
};

//調用發送企業紅包介面發送
var result = hbApi.SendWorkRedPack(packJson);

函數SendWorkRedPack的實現內容如下所示。

        /// <summary>
        /// 發放企業紅包。需要商戶證書
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public SendRedPackResult SendWorkRedPack(SendRedPackJson json)
        {
            CheckAccount();//檢查AccountInfo的對象屬性值

            //加入常規的參數
            WxPayData data = new WxPayData();
            data.SetValue("nonce_str", data.GenerateNonceStr());//隨機字元串
            //商戶訂單號(每個訂單號必須唯一) 組成:mch_id+yyyymmdd+10位一天內不能重覆的數字。
            //介面根據商戶訂單號支持重入,如出現超時可再調用。
            data.SetValue("mch_billno", data.GenerateOutTradeNo(AccountInfo.MchID));
            data.SetValue("mch_id", AccountInfo.MchID);//商戶號
            data.SetValue("wxappid", AccountInfo.AppID);//公眾賬號appid

            data.SetValue("sender_name", AccountInfo.Name);//紅包發送者名稱
            //發送者頭像,此id為微信預設的頭像(如果想自定義頭像,請參見第三部分)
            data.SetValue("sender_header_media_id", "1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0"); 

            //以企業應用的名義發紅包,企業應用id,整型,
            //可在企業微信管理端應用的設置頁面查看。與sender_name互斥,二者只能填一個。
            //data.SetValue("agentid", "3010046");//    企業應用id

            //發放紅包使用場景,紅包金額大於200時必傳 
            if (!string.IsNullOrEmpty(json.scene_id))
            {
                data.SetValue("scene_id", json.scene_id);
            }
            
            data.SetValue("re_openid", json.re_openid);//接受紅包的用戶.用戶在wxappid下的openid。
            data.SetValue("total_amount", json.total_amount);//金額
            data.SetValue("wishing", json.wishing);//紅包祝福語
            data.SetValue("act_name", json.act_name);//項目名稱
            data.SetValue("remark", json.remark);//備註

            data.SetValue("workwx_sign", data.MakeWorkWxSign(AccountInfo.CorpPaySecret));//企業微信簽名
            data.SetValue("sign", data.MakeSign(AccountInfo.PayAPIKey));

            //發送企業紅包,很容易發生簽名錯誤的情況,請檢查以下內容
            //1、企業微信的CorpID/CorpSecret
            //2、企業微信的支付Secret和商戶的API支付秘鑰
            //3、參數不能多也不能少(重要),很多時候由於版本原因這裡不小心多了一個total_num導致簽名錯誤
            //4、商戶平臺的證書和密碼是否正確

            var url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendworkwxredpack";
            return Helper.GetPayResultWithCert<SendRedPackResult>(data, url, AccountInfo.CertPath, AccountInfo.CertPassword);
        }

其實以上很多參數大家應該都很瞭解,相對於來說MakeWorkWxSign 和 MakeSign 就是這裡的關鍵處理,而前者正是很多人沒有處理好的問題所在。

下麵把相關函數貼出來,方便對照瞭解下吧,其實下麵這些函數是放在WxPayData類裡面,統一管理處理對應的簽名的。

        /// <summary>
        /// 拼接用來簽名的幾個參數,發送紅包和付款的簽名欄位不同
        /// </summary>
        /// <param name="isRedPack">是否為發送紅包操作,或者是付款操作,兩者需要簽名的欄位不同</param>
        /// <returns></returns>
        private string ToWorkWxUrl(bool isRedPack)
        {
            List<string> paramRedPack = new List<string>() { "act_name", "mch_billno", "mch_id", "nonce_str", "re_openid", "total_amount", "wxappid" };
            List<string> paramPay = new List<string>() { "amount", "appid", "desc", "mch_id", "nonce_str", "openid", "partner_trade_no", "ww_msg_type" };

            string buff = "";
            foreach (KeyValuePair<string, object> pair in Values)
            {
                if (pair.Value != null && pair.Value.ToString() != "")
                {
                    if (isRedPack)
                    {
                        //發送紅包的簽名欄位
                        if (paramRedPack.Contains(pair.Key))
                        {

                            buff += pair.Key + "=" + pair.Value + "&";
                        }
                    }
                    else
                    {
                        //付款的簽名欄位
                        if (paramPay.Contains(pair.Key))
                        {
                            buff += pair.Key + "=" + pair.Value + "&";
                        }
                    }
                }
            }
            buff = buff.Trim('&');
            return buff;
        }

        /// <summary>
        /// 生成企業微信簽名
        /// </summary>
        /// <param name="corpPaySecret">企業支付的Secret</param>
        /// <param name="isRedPack">是否為發送紅包操作,或者是付款操作,兩者需要簽名的欄位不同</param>
        /// <returns></returns>
        public string MakeWorkWxSign(string corpPaySecret, bool isRedPack = true)
        {
            //轉url格式
            string str = ToWorkWxUrl(isRedPack);
            //在string後加入secret
            str += "&secret=" + corpPaySecret;
            //MD5加密
            var md5 = MD5.Create();
            var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
            var sb = new StringBuilder();
            foreach (byte b in bs)
            {
                sb.Append(b.ToString("x2"));
            }
            //所有字元轉為大寫
            return sb.ToString().ToUpper();
        }
        /// <summary>
        /// 生成簽名,詳見簽名生成演算法
        /// </summary>
        /// <returns>簽名, sign欄位不參加簽名</returns>
        public string MakeSign(string payAPIKey)
        {
            //轉url格式
            string str = ToUrl();
            //在string後加入API KEY
            str += "&key=" + payAPIKey;
            //MD5加密
            var md5 = MD5.Create();
            var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
            var sb = new StringBuilder();
            foreach (byte b in bs)
            {
                sb.Append(b.ToString("x2"));
            }
            //所有字元轉為大寫
            var result = sb.ToString().ToUpper();
            return result;
        }

 

3、企業微信直接支付的介面

對照這些官方資料,我們可以編寫對應的介面API來處理。

        /// <summary>
        /// 企業付款(請求需要雙向證書)
        /// 企業付款業務是基於微信支付商戶平臺的資金管理能力,為了協助商戶方便地實現企業向個人付款,
        /// 針對部分有開發能力的商戶,提供通過API完成企業付款的功能。 比如目前的保險行業向客戶退保、給付、理賠。
        /// 企業付款將使用商戶的可用餘額,需確保可用餘額充足。查看可用餘額、充值、提現請登錄商戶平臺“資金管理”進行操作。https://pay.weixin.qq.com/ 
        /// 註意:與商戶微信支付收款資金並非同一賬戶,需要單獨充值。
        /// </summary>
        /// <param name="json">企業支付數據</param>
        /// <returns></returns>
        public CorpPayResult CorpPay(CorpPayJson json)
        {
            CheckAccount();//檢查AccountInfo的對象屬性值

            WxPayData data = new WxPayData();
            data.SetValue("mch_appid", AccountInfo.AppID);//公眾賬號appid, 註意是mch_appid,而非wxappid
            data.SetValue("mchid", AccountInfo.MchID);//商戶號, 註意是mchid而非mch_id
            data.SetValue("nonce_str", data.GenerateNonceStr());//隨機字元串
            data.SetValue("spbill_create_ip", NetworkUtil.GetIPAddress());//終端ip      
            data.SetValue("partner_trade_no", data.GenerateOutTradeNo(AccountInfo.MchID));//隨機字元串

            data.SetValue("device_info", json.device_info);//終端ip            
            data.SetValue("openid", json.openid);
            data.SetValue("check_name", json.check_name);
            data.SetValue("re_user_name", json.re_user_name);
            data.SetValue("amount", json.amount);
            data.SetValue("desc", json.desc);

            data.SetValue("sign", data.MakeSign(AccountInfo.PayAPIKey));//最後生成簽名

            var url = string.Format("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
            return Helper.GetPayResultWithCert<CorpPayResult>(data, url, AccountInfo.CertPath, AccountInfo.CertPassword);
        }

其中裡面的很多參數的處理是和前面支付差不多的,因此不再贅述

調用的處理代碼如下所示

            //構建處理信息
            CorpPayJson json = new CorpPayJson()
            {
                amount = 100,
                check_name = PayCheckName.FORCE_CHECK.ToString(),
                desc = "測試退款",
                openid = openid,
                device_info = "",
                re_user_name = "伍華聰",
                spbill_create_ip = NetworkUtil.GetIPAddress()
            };
            //直接付款到員工賬號
            var result = api.CorpPay(json);

 

最新的第一條就是直接付款的信息提示。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • [TOC] 一、為什麼要重載賦值運算符 ​ 在前面的內容中講解 "拷貝構造函數調用的時機" 時說明瞭初始化和賦值的區別:在定義的同時進行賦值叫做 ,定義完成以後再賦值(不管在定義的時候有沒有賦值)就叫做 。初始化只能有一次,賦值可以有多次。 ​ 當以拷貝的方式初始化一個對象時,會調用拷貝構造函數;當 ...
  • 今天真的是累哭了,周一課從早八點半一直上到晚九點半,整個人要虛脫的感覺,因為時間不太夠鴨所以就回頭看看找了一些比較有知識點的題來總結總結分析一下,明天有空了就開始繼續打題,嘻嘻嘻。 今日興趣電影: 《超能查派》 這是一部關於未來人工智慧的一個故事,感覺特別有思維開拓性,一個程式員寫出了真正的AI智能 ...
  • 代碼基本結構 url.py: views.py: 說明: 1)在authenticate方法的返回值是一個元組,元組中第一個元素是用戶名,第二個元素是認證數據token。這個返回值會在我們的視圖類中通 過request.user 和 request.auth獲取到。具體為什麼是這兩個值,會在後面的源 ...
  • [TOC] 近期廣泛閱讀券商關於 巨集觀高頻數據 的研報,發現了兩點不足: 就研究手段而言,比較粗放,普遍停留在僅僅比較數據相關係數的層面; 就理論高度而言,很少探討數據背後的因果關聯。 不過有些理念先進的券商團隊已經開始從 產業鏈傳導 的角度試圖細緻的描述數據間的關聯,這正好契合了下麵這篇文章的核心 ...
  • 「HW面試題」 【題目】 給定一個整數數組,如何快速地求出該數組中第k小的數。假如數組為[4,0,1,0,2,3],那麼第三小的元素是1 【題目分析】 這道題涉及整數列表排序問題,直接使用sort方法按照ASCII碼排序即可 【解答】 1 #!/Users/minutesheep/.pyenv/sh ...
  • 第5章 字元串及正則表達式 5.1 字元串常用操作 在Python開發過程中,為了實現某項功能,經常需要對某些字元串進行特殊處理,如拼接字元串、截取字元串、格式化字元串等。下麵將對Python中常用的字元串操作方法進行介紹。 5.1.1 拼接字元串 使用“+” 運算符可完成對多個字元串的拼接,“+” ...
  • Spark RPC 框架的運行時序是怎樣的呢?讓我們深入到它的源碼裡面去看看~~ ...
  • 實例中,可以通過person中的不同類型的對象來實現不同的方法。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...