本文分享了如何通过反编译API接口源码获取未设置项目公式的财务报表平台数据的方法。作者首先研究并解决了这一难题,然后通过Python编写了解决方案的核心代码,并详细介绍了如何通过Python脚本获取和解析报表JSON数据,以及如何将这些数据转换为DataTable对象的过程。此外,还提醒了新版补丁可能影响方案执行,并提供了代码调整建议。
独版文章!!!
最近一直在研究如何获取财务报表平台的数据,对于设置了项目公式的报表可以通过查询数据库获取:
(参考此帖:财务报表报表项目数据存取),
但是没有设置项目公式的报表无法直接获取,经过不断的研究和反编译代码,终于皇天不负有心人,研究出了方案。
写下此文做个总结和分享,在此也感谢在这个问题上给我提供帮助和思路的小伙伴们,下面开始正文...
【温馨提示】:新版补丁(V7.7 PT-146881)提供了报表API工具,这个工具似乎不支持自定义报表。
此方案也是基于反编译这个API接口源码研究出来的,我没有升级到这个版本也可以使用(我的版本是V7.6.0.202103) ,如需要借鉴我这个解决方案,如出现低版本不支持的问题,自行升级。
本案例采用Python编写(网页复制代码会有缩进问题,自行调整),如需编写.NET插件,自行转换即可。
以下分享解决方案核心代码:
首先需要在本身插件环境的基础上,添加关键引用;
clr.AddReference('Kingdee.BOS.KDSReportEntity')#相当于添加.NET库文件引用
clr.AddReference('Kingdee.BOS.App.KDSService')
clr.AddReference('Newtonsoft.Json')
from Kingdee.BOS.JSON import *#相当于添加.NET插件中的引用命名空间:Using Kingdee.BOS.JSON;
from Kingdee.BOS.App.KDSService import *
from Kingdee.BOS.KDSReportEntity.Entity import *
from Newtonsoft.Json.Linq import *
#读取指定rptId的报表数据成JSON格式
def getRptData(rptId):
rptIds = List[Guid]();
testGuid=Guid(rptId);#报表ID,可查询数据库表:T_KDS_RPT 获取
rptIds.Add(testGuid);
kDSReportInfoService =KDSReportInfoService();
KDSCtx=KDSContext();
KDSCtx.SubSystemName = "CR";
#根据报表ID获取报表详情列表,返回值为列表。如果传入多个ID,则可一次性取出多个报表数据
reportDetail = kDSReportInfoService.GetReportDetail(this.Context, KDSCtx, rptIds, True);
for current in reportDetail:
#读取报表JSON格式数据,到此已经完成报表数据读取,报表JSON格式比较复杂,下面核心就是解析JSON了
#建议将JSON先打印出来,复制到格式化工具中查看分析结构,再进行解析
contents = current.GetJSON().ToJSONString();
convertRptJson(contents);#解析报表JSON
#----- C#代码写法可参考如下截图:
3.在此分享一下我解析JSON的过程(convertRptJson方法实现)
#解析报表数据JSON
def convertRptJson(contents):
orgSQL=("""/*dialect*/select org.FNUMBER,orgL.FNAME,right(org.FNUMBER,2) orgNo
from T_ORG_organizations org
inner Join T_ORG_organizations_L orgL on org.FORGID=orgL.FORGID and orgL.FLocalEId=2052
where len(org.FNUMBER)=5 """);
ds = DBServiceHelper.ExecuteDataSet(this.Context,orgSQL);
tab = ds.Tables[0];
orgDIC={};#本案例是通过组织编码后2位与报表页签名称前2位作为组织对应关系,所以先构建了一个组织编码字典
for org in tab.Rows:
orgNo=str(org["orgNo"]);
orgNum=str(org["FNUMBER"]);
orgDIC[orgNo]=orgNum;
dataObj=JObject.Parse(contents);#将报表JSON字符串转换成JSON对象
itemList=JArray.Parse(dataObj["items"].ToString());#读取报表主体内容数据
if(itemList.Count<=0):
return;
rpt=itemList[0];
rptData=rpt["data"];#报表关键数据包
sheetDIC={};#通过字典记录每个Sheet页签名称(key)与页签序号(value)的对应关系,用来对应前面的组织编码
sheets=JArray.Parse(rptData["sheets"].ToString());#读取报表中的Sheet列表,与数据库表t_KDS_Sheet对应
#注意:JSON里面是根据页签的序号来对应每个页签的数据包的,需要借助这个关系来快速定位我们想要查询的报表页签
sheetDatas=JArray.Parse(rptData["data"].ToString());#所有页签的数据包(数组),与Sheet列表序号相对应。
sheetIndex=0;
for sheet in sheets:
sheetName=("{0}").format(sheet);
orgNo=sheetName[0:2];
if(orgDIC.has_key(orgNo)):#我这里只将组织编码对应得上的页签存入了Sheet字典
sheetName=orgDIC[orgNo];#在字段中将页签名称转换成组织编码,以此记录每个组织编码对应哪个页签序号
sheetDIC[sheetName]=sheetIndex;
sheetIndex=sheetIndex+1;
#循环记录下来的页签字典,依次解析每一个页签的报表数据
for orgNum in sheetDIC.keys():#我这里已经将关键字转换成了组织编码
dataIndex=int(sheetDIC[orgNum]);#页签序号
currentOrgData=sheetDatas[dataIndex];#当前页签的数据包,这是最复杂的JSON部分,也是我们最终的目标数据
ExcelTAB=createTempTab(currentOrgData);#将页签JSON数据转换成了DataTable对象,还原成二维表
4.分享一下报表页签数据解析成DataTable的过程和代码(createTempTab方法实现)
#页签JSON数据中(sheetData),实际上是记录了每一个页签中的单元格,构成的一个数组
#单元格cell也是一个数组,包含4个元素,依次如下:
#[ 0.行序号(从0开始),1.列序号(从0开始),2.单元格内容值,3.单元格公式(无公式为空) ]
#注意!!!
#如有合并单元格,则JSON中会认为该数据在合并单元格的第1行和第1列,后面的单元格会跳过不会出现,参考下图:
#如果有数据和公式都为空的单元格,则JSON会自动跳过,不会出现
#=====根据Sheet的JSON数据,构建成DataTable====================================
def createTempTab(sheetData):
ExcelTAB=DataTable();#实例化一个DataTable对象
rowsDIC={};#记录已经出现过的行号
columnsDIC={};#记录已经出现过的列号
for cell in sheetData:#循环页签数据单元格
x=int(cell[0]);#当前单元格行序号
y=int(cell[1]);#当前单元格列序号
value=cell[2];#当前单元格的内容值
if(columnsDIC.has_key(y)==False):#该列序号第一次出现,新增一列
ExcelTAB.Columns.Add(str(y), Type.GetType("System.String"));
columnsDIC[y]=y;#记录下来已经出现过
newRow=None;#构建数据行
if(rowsDIC.has_key(x)):
newRow=ExcelTAB.Rows[x];#前面应出现过的行,直接读取DataTable中的数据行
else:#该行序号第一次出现,新增一行
newRow = ExcelTAB.NewRow();
rowsDIC[x]=x;#记录该行已经出现过
ExcelTAB.Rows.Add(newRow);#将新的数据行添加到DataTable
newRow[str(y)]=("{0}").format(value);#对DataTable对应的单元格赋值
return ExcelTAB;
====至此,核心代码分享结束===================================
推荐阅读