一.前言

今天,我们转战用友系列的第一个产品---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参数。

 if (!APIConfig.AuthorizeParameters.ContainsKey("appkey")
|| !APIConfig.AuthorizeParameters.ContainsKey("orgid")
|| !APIConfig.AuthorizeParameters.ContainsKey("appsecret")
|| !APIConfig.AuthorizeParameters.ContainsKey("secerturl"))
{
throw new Exception("鉴权参数不完整");
}
var request = new AccessTokenRequest();
Dictionary<string, object> parm = new Dictionary<string, object>();
string appkey = APIConfig.AuthorizeParameters["appkey"];
string orgid = APIConfig.AuthorizeParameters["orgid"];
string appsecret = APIConfig.AuthorizeParameters["appsecret"];
string secetrurl = APIConfig.AuthorizeParameters["secerturl"];

parm.Add("appkey", appkey);
parm.Add("orgid", orgid);
parm.Add("appsecret", appsecret);

JsonSerializer jsonSerializer = new JsonSerializer();
string datas = jsonSerializer.Serialize(parm);
try
{
var signClass = new TokenManage();
string signvalue = signClass.CreateSignedToken(datas, secetrurl);
string authStr = @"{""appKey"":""" + appkey + @""",""authInfo"":""" + signvalue + @""",""orgId"":" + orgid + @"}";
string encode = Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(authStr));
Dictionary<string, string> parms = new Dictionary<string, string>();
parms.Add("Authorization", encode);
request.SetHeaderParameters(parms);
var response = Excute(request);
return response;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}

当你处理完第一步,调试接口正常返回

 {"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,详细代码如下

    var signClass = new TokenManage();
var request = new GetTokenByPwdRequest();
string appkey = APIConfig.AuthorizeParameters["appkey"];
string appsecret = APIConfig.AuthorizeParameters["appsecret"];
string secetrurl = APIConfig.AuthorizeParameters["secerturl"];
string userName = APIConfig.AuthorizeParameters["userName"];
string password = APIConfig.AuthorizeParameters["password"];
string EncodePassword = signClass.GetMd5(password);
string accNum = APIConfig.AuthorizeParameters["accNum"];

Dictionary<string, object> parm = new Dictionary<string, object>();
parm.Add("appkey", appkey);
parm.Add("orgid", "");
parm.Add("appsecret", appsecret);

JsonSerializer jsonSerializer = new JsonSerializer();
string datas = jsonSerializer.Serialize(parm);
try
{
string signvalue = signClass.CreateSignedToken(datas, secetrurl);
string authStr = @"{""appKey"":""" + appkey + @""",""authInfo"":""" + signvalue + @""",""orgId"":""""}";
string encode = Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(authStr));
Dictionary<string, string> parms = new Dictionary<string, string>();
parms.Add("Authorization", encode);
request.SetHeaderParameters(parms);

Dictionary<string, object> postParms = new Dictionary<string, object>();
var args = new PwdEntity() { userName = userName, password = EncodePassword, accNum = accNum };
var argsJson = jsonSerializer.Serialize(args);
postParms.Add("_args", argsJson);
request.SetPostParameters(postParms);

var response = Excute(request);
return response;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
} 

两种方式都处理完毕了,我们就可以愉快的使用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 凭证相关操作

凭证创建请求实体:

 {
"dto": {
"ExternalCode": "", //外部编码-唯一码,长度小于50
"DocType": {
"Code": "记" // 凭证类别编码
},
"AttachedVoucherNum": "",// 附单据数
"Memo": "无", // 备注 长度小于50
"VoucherDate": "2014-09-30",// 凭证日期
"Entrys": [{
"Summary": "提现", // 凭证摘要
"Account": {
"Code": "" // 科目档案
},
"Currency": {
"Code": "RMB" // 币别
},
"AmountCr": "" //贷方金额
},
{
"Summary": "提现",
"Account": {
"Code": ""
},
"Currency": {
"Code": "RMB"
},
"AmountDr": "", // 借方金额
"AuxInfos": [{ // 辅助核算信息
"AuxAccDepartment": { // 部门核算
"Code": ""
},
"AuxAccInventory": { // 存货核算
"Code": ""
},
"AuxAccProject": { // 项目核算
"Code": ""
},
"AuxAccPerson": { // 人员核算
"Code": ""
},
"AuxAccCustomer": { //往来单位核算
"Code": ""
}
}]
}
]
}
}

URL: TPlus/api/v1/doc/Create || TPlus/api/v2/doc/Create

构造好对应的凭证实体即可正常传输凭证了。

凭证查询:官网给的示例是传入一个dtos的数组,但是在实际的开发过程中,真正传入一个起始期间,一个截止时间时,并没有正确的返回对应的数据,所以我到现在也没搞明白这个起始和截止时间该咋用,如果有知道的小伙伴,还请帮忙解答。

三.结束语

其实,真正对于T+的业务调用并没有花费很多时间,因为前面的坑已经踩完了,后面基本上也没啥了,就是我很纳闷的是,每个接口的返回值格式是不固定的,这个就很令人费解啊。咱也搞不懂到底为啥这样定义。倒是前面处理签名算法和dll不兼容的问题前前后后大约搞了一个星期才完整解决,这个很是让人头大。

曾经在T+的开发群了看到这样一句话,每个开发都是一个实施。也确实是这样一种情况,你对接的每个API接口,不可能总会有人给你解答问题,这时候你只能靠自己去摸索,去猜,当然了大部分的开发文档还是很规范的。其实做对接的做多了,你会遇到不同形式的API接口,每家厂商都有自己独特的开发标准,我们能做的就是遵循这套标准,不然如何对接,如何正确处理我们的工作。

最后的最后,希望我们做API对接或者说是做开发的,要保持一颗良好的心态去面对问题,要相信问题总是会被解决的,只是时间早晚。而且要找对方法,比如社区,或者对应的交流群等等,会有很多大佬帮你解答疑惑,祝你在开发的道路上勇往直前的。

我是程序猿贝塔,一个分享自己对接过财务系统API经历和生活感悟的程序员。

.NetCore对接各大财务软件凭证API——用友系列(1)的更多相关文章

  1. .NetCore对接各大财务软件凭证API——用友系列(2)

    一. 前言 今天我们继续来分析用友系列的第二个产品--U8Cloud2.5 ,apilink方式的API.官网的API文档地址如下:U8API文档 因为我们主要是凭证对接,所以使用到的模块有总账.基础 ...

  2. .NetCore对接各大财务软件凭证API——用友系列(3)

    一. 前言 由于前段时间项目比较集中,所以停更了好久,终于来到我们用友的系列产品3---U8Cloud2.7了. 一,2.7和2.5的api方式有什么区别? 1.2.7版本以后可以直接使用u8c登入地 ...

  3. .NetCore对接各大财务软件凭证API——金蝶系列(1)

    哈喽,又和大家见面了,虽然看文章的小伙伴不多,但是我相信总有一天,自己写的这些文章或多或少会对其他人有些帮助,让他们在相关的业务开发下能少走些弯路,那我的目的就达到了,好了,今天就正式开始我们的系列了 ...

  4. winform怎么实现财务上凭证录入和打印

    序言 现如今存在的财务软件层出不穷,怎么样让自己的业务系统与财务系统相结合,往往是很多公司头痛的问题.大多数公司也没有这个能力都去开发一套属于自己的财务软件,所以只有对接像金蝶用友这类的财务软件,花费 ...

  5. 常用财务软件:用友,金蝶,新中大,速达,管家婆,金算盘,远方,远光,金钥匙,润衡,浪潮,上海博科,易商,任我行,千方百剂,智管,小蜜蜂,SAP,ORACLE,SSA,QAD,MAPICS,JDE。

    常用财务软件:用友,金蝶,新中大,速达,管家婆,金算盘,远方,远光,金钥匙,润衡,浪潮,上海博科,易商,任我行,千方百剂,智管,小蜜蜂,SAP,ORACLE,SSA,QAD,MAPICS,JDE. 申 ...

  6. CentOS6安装各种大数据软件 第九章:Hue大数据可视化工具安装和配置

    相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...

  7. Qt加载网页(加载浏览器插件)和制作托盘后台运行(南信大财务报账看号)

    程序模块要添加QNetWork和QWebKit模块: nuistfinancevideo.h文件: #ifndef NUISTFINANCEVIDEO_H #define NUISTFINANCEVI ...

  8. 为大数据软件准备JAVA、Python环境

    环境:SUSE 11 64位 安装JAVA JDK 1.确定版本.一般都是安装最新的JDK(Java SE Development Kit).个别软件和系统需要特定版本的JDK,根据实际需要下载. 2 ...

  9. CentOS6安装各种大数据软件 第四章:Hadoop分布式集群配置

    相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...

随机推荐

  1. TIME_WAIT的危害与避免

    time-wait的产生: 在TCP连接中四次挥手关闭连接时,主动关闭连接的一方(上图中时Client)会在发送最后一条ACK报文后维持一段时长2MSL(MSL指的是数据包在网络中的最大生存时间)的等 ...

  2. opencv-0-项目启程

    opencv-0-项目启程 opencvC++QT 开始 无数次说要开始 opencv 的系列, 但是都由于各种原因没有坚持下去, 这次我做最后一次尝试, 也做最后一次坚持, 如果不做下去, 我就再也 ...

  3. zabbix自动监控钉钉报警

    钉钉报警 一:设置钉钉机器人  二:zabbix服务器server端配置 1.修改zabbix_server.conf文件 [root@server ~]# vim /usr/local/zabbix ...

  4. 【Linux常见命令】head命令

    head - output the first part of files 读取文件的前n行,默认前10行 语法: head [OPTION]... [FILE]... 参数: -n 数字 显示前n行 ...

  5. APP路由还能这样玩

    本文主要讲述一种设计思路,组件化架构市面上已经有很多大厂成熟的方案,但是在组件化过程中,偶尔会遇到2个独立业务子模块间没有相互引用,也需要能直接调用对方的功能,因此我想到通过方法路由来解决,如果还有疑 ...

  6. CF思维联系– CodeForces -CodeForces - 992C Nastya and a Wardrobe(欧拉降幂+快速幂)

    Nastya received a gift on New Year - a magic wardrobe. It is magic because in the end of each month ...

  7. 图论--2-SAT--HDU/HDOJ 4115 Eliminate the Conflict

    Problem Description Conflicts are everywhere in the world, from the young to the elderly, from famil ...

  8. CF786B Legacy(线段树优化建边)

    模板题CF786B Legacy 先说算法 如果需要有n个点需要建图 给m个需要建边的信息,从单点(或区间内所有点)向一区间所有点连边 如果暴力建图复杂度\(mn^2\) 以单点连向区间为例,在n个点 ...

  9. mysql查询表内所有字段名和备注

    select distinct column_name as 字段名,column_comment as 字段备注 from information_schema.columns where tabl ...

  10. FPGA实现-shift_ram_3x3矩阵

    shift_ram_3x3-FPGA实现 实现的方法为方法二,可以参考上一节关于中值滤波的介绍 shift_ram核介绍 https://www.cnblogs.com/ninghechuan/p/6 ...