一.前言
今天,我們轉戰用友系列的第一個產品---T+/Tplus。前兩篇文章講解分享的都是金蝶的產品,因為本身公司牽涉的業務有限,后續有金蝶其他產品的API對接業務時,會繼續來分享經驗。
T+的API接口,哎,想起來都是心酸淚。關於該接口的對接開發經驗,我之前也簡單記錄了一些,傳送門 記錄用友T+接口對接的心酸歷程。今天我們就來詳細解析下這令人頭大的財務API接口。
二.API接口詳解
2.1接口定義和入參
根據開發者社區API文檔的描述我們可以看到,T+版本為12.3以上的API對接,都必須使用V2版本,那v2與v1版本的區別有哪些呢?主要有兩點:1. 請求認證方式,增加雲企業ID認證方式 ;2.v2版本支持異步請求。OK,因為我們對接的客戶財務環境為12.3,那么我們就來處理v2版本的OpenAPI,該版本的API引入了鑒權機制,簡單來說就是在請求頭增加了授權 Authorization 參數.
2.1.1 Authorization參數以及簽名處理
那么 Authorization 參數如何才能生成呢?可以看官網首頁的描述是 需要appkey、appsecert、私鑰的文件全路徑。那這三個參數又如何才能獲取呢?必須申請ISV認證,即注冊ISV,提交開發申請通過審核后,總部會將這三個參數一並發到注冊時預留的郵箱里。
2.1.2 OrgId方式的簽名算法處理
這里,我們在上一步已經拿到簽名所需的三個必要參數了,官網給了兩種請求Head的處理方式,一種使用OrgId,一種使用用戶名、密碼、賬套號,這兩種方式我們都會講到。先看第一種方式OrgId訪問。
OrgId的獲取方式,官網描述的也有
即必須開通雲企業才能看到
這樣,我們第一種使用OrgId認證方式的所需參數就已全部准備完畢了,接着往下看,首先需要對appKey、orgid、appsecret、私鑰全路徑做一個簽名1的算法加密,這個算法官網給我們提供的也有,這里僅提供C#版本的簽名算法1.接着做一個Base64位的加密即可得到Authorization參數。
1 if (!APIConfig.AuthorizeParameters.ContainsKey("appkey") 2 || !APIConfig.AuthorizeParameters.ContainsKey("orgid") 3 || !APIConfig.AuthorizeParameters.ContainsKey("appsecret") 4 || !APIConfig.AuthorizeParameters.ContainsKey("secerturl")) 5 { 6 throw new Exception("鑒權參數不完整"); 7 } 8 var request = new AccessTokenRequest(); 9 Dictionary<string, object> parm = new Dictionary<string, object>(); 10 string appkey = APIConfig.AuthorizeParameters["appkey"]; 11 string orgid = APIConfig.AuthorizeParameters["orgid"]; 12 string appsecret = APIConfig.AuthorizeParameters["appsecret"]; 13 string secetrurl = APIConfig.AuthorizeParameters["secerturl"]; 14 15 parm.Add("appkey", appkey); 16 parm.Add("orgid", orgid); 17 parm.Add("appsecret", appsecret); 18 19 JsonSerializer jsonSerializer = new JsonSerializer(); 20 string datas = jsonSerializer.Serialize(parm); 21 try 22 { 23 var signClass = new TokenManage(); 24 string signvalue = signClass.CreateSignedToken(datas, secetrurl); 25 string authStr = @"{""appKey"":""" + appkey + @""",""authInfo"":""" + signvalue + @""",""orgId"":" + orgid + @"}"; 26 string encode = Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(authStr)); 27 Dictionary<string, string> parms = new Dictionary<string, string>(); 28 parms.Add("Authorization", encode); 29 request.SetHeaderParameters(parms); 30 var response = Excute(request); 31 return response; 32 } 33 catch (Exception ex) 34 { 35 throw new Exception(ex.Message); 36 }
當你處理完第一步,調試接口正常返回
{"result":true,"access_token":"03e74889-1457-48cd-970a-ba3742ffcdea","sid":""}
先不要高興的太早了,我們還要根據這一步獲取到的Token做業務調用。如圖所示
官網也給的有測試的Demo供我們調用調試,這比較方便我們對問題作出反饋。 T+OpenAPI測試工具-包含v2版本-C#.zip. 然后大坑就來了...demo中的jose-jwt.dll是 .NET Framework的版本,但是我們的開發環境是.netCore2.2,很遺憾的是該dll在.netCore環境下不支持.詳細的解決過程很心酸,就不再多敘述,我在之前的文章里已詳細描述,這里我們只說最后的結果就是解決了不支持的問題。
2.1.3 用戶名密碼方式的簽名算法處理
這種方式的登錄相比第一種使用OrgId認證的方式有什么好處呢?我在實際的開發中得到了驗證,OrgId方式的認證在對那些沒有開通雲企業的客戶來說這種方式是行不通的,所以相比較來說,還是用戶名密碼的認證比較通用,只要客戶能提供給我們一個正常可登錄財務系統的用戶名和密碼,我們就可以使用該方式來進行接口的開發對接。下面具體來說一下,如何正確得到該方式的Authoirzation參數
這是第一步得到Token的方法,可以看到簽名方式和加密方式不變,變得是簽名方式的參數不同,orgId為空,在PostBody里要傳入用戶名、密碼和賬套號。
賬套號為中括號里的,比如上圖的021809... 不要傳名稱!不要傳名稱!不要傳名稱!接着獲取到Token后,我們就可以調用業務接口了,這里還是使用用戶名密碼的方式來調用。
增加了上一步獲取到的Token,詳細代碼如下
1 var signClass = new TokenManage(); 2 var request = new GetTokenByPwdRequest(); 3 string appkey = APIConfig.AuthorizeParameters["appkey"]; 4 string appsecret = APIConfig.AuthorizeParameters["appsecret"]; 5 string secetrurl = APIConfig.AuthorizeParameters["secerturl"]; 6 string userName = APIConfig.AuthorizeParameters["userName"]; 7 string password = APIConfig.AuthorizeParameters["password"]; 8 string EncodePassword = signClass.GetMd5(password); 9 string accNum = APIConfig.AuthorizeParameters["accNum"]; 10 11 Dictionary<string, object> parm = new Dictionary<string, object>(); 12 parm.Add("appkey", appkey); 13 parm.Add("orgid", ""); 14 parm.Add("appsecret", appsecret); 15 16 JsonSerializer jsonSerializer = new JsonSerializer(); 17 string datas = jsonSerializer.Serialize(parm); 18 try 19 { 20 string signvalue = signClass.CreateSignedToken(datas, secetrurl); 21 string authStr = @"{""appKey"":""" + appkey + @""",""authInfo"":""" + signvalue + @""",""orgId"":""""}"; 22 string encode = Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(authStr)); 23 Dictionary<string, string> parms = new Dictionary<string, string>(); 24 parms.Add("Authorization", encode); 25 request.SetHeaderParameters(parms); 26 27 Dictionary<string, object> postParms = new Dictionary<string, object>(); 28 var args = new PwdEntity() { userName = userName, password = EncodePassword, accNum = accNum }; 29 var argsJson = jsonSerializer.Serialize(args); 30 postParms.Add("_args", argsJson); 31 request.SetPostParameters(postParms); 32 33 var response = Excute(request); 34 return response; 35 } 36 catch (Exception ex) 37 { 38 throw new Exception(ex.Message); 39 }
兩種方式都處理完畢了,我們就可以愉快的使用API來做業務的處理啦。
2.2 業務接口調用
2.2.1 會計科目查詢
URL的話,v2版本的調用,我們只需將v1改為v2即可,若想一次性獲取到所有的會計科目,查詢條件傳空值即可,即如下:
{
dto:{
}
}
public QueryAccountResponse QueryAccountRequest() { var request = new QueryAccountRequest(); var parmsDic = new Dictionary<string, object>(); var parms = new QuertyEntity() { dto = new BasicDto { } }; parmsDic.Add("_args", JsonConvert.SerializeObject(parms)); request.SetPostParameters(parmsDic); return _Client.Excute(request); }
該方法可返回所有會計科目用作基礎檔案或者前端頁面展示使用。
2.2.2 憑證相關操作
憑證創建請求實體:
1 { 2 "dto": { 3 "ExternalCode": "1", //外部編碼-唯一碼,長度小於50 4 "DocType": { 5 "Code": "記" // 憑證類別編碼 6 }, 7 "AttachedVoucherNum": "2",// 附單據數 8 "Memo": "無", // 備注 長度小於50 9 "VoucherDate": "2014-09-30",// 憑證日期 10 "Entrys": [{ 11 "Summary": "提現", // 憑證摘要 12 "Account": { 13 "Code": "1001" // 科目檔案 14 }, 15 "Currency": { 16 "Code": "RMB" // 幣別 17 }, 18 "AmountCr": "100" //貸方金額 19 }, 20 { 21 "Summary": "提現", 22 "Account": { 23 "Code": "1002" 24 }, 25 "Currency": { 26 "Code": "RMB" 27 }, 28 "AmountDr": "100", // 借方金額 29 "AuxInfos": [{ // 輔助核算信息 30 "AuxAccDepartment": { // 部門核算 31 "Code": "001" 32 }, 33 "AuxAccInventory": { // 存貨核算 34 "Code": "001" 35 }, 36 "AuxAccProject": { // 項目核算 37 "Code": "001" 38 }, 39 "AuxAccPerson": { // 人員核算 40 "Code": "001" 41 }, 42 "AuxAccCustomer": { //往來單位核算 43 "Code": "001" 44 } 45 }] 46 } 47 ] 48 } 49 }
URL: TPlus/api/v1/doc/Create || TPlus/api/v2/doc/Create
構造好對應的憑證實體即可正常傳輸憑證了。
憑證查詢:官網給的示例是傳入一個dtos的數組,但是在實際的開發過程中,真正傳入一個起始期間,一個截止時間時,並沒有正確的返回對應的數據,所以我到現在也沒搞明白這個起始和截止時間該咋用,如果有知道的小伙伴,還請幫忙解答。
三.結束語
其實,真正對於T+的業務調用並沒有花費很多時間,因為前面的坑已經踩完了,后面基本上也沒啥了,就是我很納悶的是,每個接口的返回值格式是不固定的,這個就很令人費解啊。咱也搞不懂到底為啥這樣定義。倒是前面處理簽名算法和dll不兼容的問題前前后后大約搞了一個星期才完整解決,這個很是讓人頭大。
曾經在T+的開發群了看到這樣一句話,每個開發都是一個實施。也確實是這樣一種情況,你對接的每個API接口,不可能總會有人給你解答問題,這時候你只能靠自己去摸索,去猜,當然了大部分的開發文檔還是很規范的。其實做對接的做多了,你會遇到不同形式的API接口,每家廠商都有自己獨特的開發標准,我們能做的就是遵循這套標准,不然如何對接,如何正確處理我們的工作。
最后的最后,希望我們做API對接或者說是做開發的,要保持一顆良好的心態去面對問題,要相信問題總是會被解決的,只是時間早晚。而且要找對方法,比如社區,或者對應的交流群等等,會有很多大佬幫你解答疑惑,祝你在開發的道路上勇往直前的。
我是程序猿貝塔,一個分享自己對接過財務系統API經歷和生活感悟的程序員。