一.前言

今天,我们转战用友系列的第一个产品---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. 为何 UNIX 时间 0, 有时显示是1970年1月1日,有时显示是1969年12月31日

    by Rachael Arnold http://www.rachaelarnold.com/dev/archive/why-is-date-returning-wrong Demystifying ...

  2. Java第一阶段作业总结

    目录 0.前言 1.作业过程总结 2.OO设计心得 3.测试的理解与实践 4.课程收获 5.对课程的建议 前言 本次博客针对第一阶段的三次作业发表总结,作业要求主要是初学者对于Java的基本语法.用法 ...

  3. Mybatis 使用 SQL 递归获取单表中的树结构

    xml 代码 <resultMap type="xxx.xxx.xxx.xxx.实体类" id="xxxListTree"> <result ...

  4. Linux改中文乱码显示

    Linux改中文乱码显示                可以使用locale命令,查看当前系统默认采用的字符集# locale在RedHat/CentOS系统下,记录系统默认使用语言的文件是/etc/ ...

  5. CF1324 --- Maximum White Subtree

    CF1324 --- Maximum White Subtree 题干 You are given a tree consisting of \(n\) vertices. A tree is a c ...

  6. 标准库模块time,datetime

    在Python中,通常有这几种方式来表示时间: 1)时间戳 2)格式化的时间字符串 3)元组(struct_time)共九个元素. 由于Python的time模块实现主要调用C库,所以各个平台可能有所 ...

  7. 边缘控制平面Ambassador全解读

    Ambassador是由Datawire开源的一个API网关项目,主要在Kubernetes的容器编排框架中使用.Ambassador本质上是一个通过配置边缘/API来管理Envoy数据面板的控制面板 ...

  8. Redis(一):数据结构与对象

    前言 本书是Redis设计与实现的读书笔记,旨在对Redis底层的数据结构及实现有一定了解.本书所有的代码基于Redis 3.0. 简单动态字符串 SDS Redis没有直接使用C语言中的字符串,而是 ...

  9. Codeforces Round #509 (Div. 2) A. Heist 贪心

    There was an electronic store heist last night. All keyboards which were in the store yesterday were ...

  10. 在Jetson TX2上安装caffe和PyCaffe

    caffe是Nvidia TensorRT最支持的深度学习框架,因此在Jetson TX2上安装caffe很有必要.顺便说一句,下面的安装是支持python3的. 先决条件 在Jetson TX2上完 ...