本文回顾了Python插件开发的前几篇内容,并重点介绍了单据转换插件的开发。单据转换是业务流程中的重要环节,通过插件可以控制单据的转换过程,调整生成的下游数据包。文章详细阐述了单据转换的两种类型(下推和选单)及其实现逻辑,并介绍了单据转换插件的注册、事件处理流程以及常用事件的处理方法。通过示例代码展示了如何在Python中实现单据转换插件,并提供了应用案例和事件处理示例。最后,感谢读者的关注与支持,并预告了下一篇关于插件常用工具类的分享。
往期回顾:
【Python插件入门】第1篇:Python插件入门讲解
【Python插件入门】第2篇:基本开发过程介绍
【Python插件入门】第3篇:插件中如何进行数据操作
【Python插件入门】第4篇:单据表单插件
【Python插件入门】第5篇:单据列表插件
【Python插件入门】第6篇:操作服务插件
【Python插件入门】第7篇:简单账表服务插件
【Python插件入门】第8篇:账表表单插件
前面的篇章讲解了各种类型的插件,这些插件都是在单个业务对象中触发使用,我们同时也了解了对单据数据的操作方法,是不是对这个系统的功能背后的实现逻辑有了更深的理解呢,当不同的业务对象"串联起来"就构成了系统中各种丰富的功能,形成了系统的业务流程,在"串联"各种单据的过程中,必不可少的就是"单据转换",他是业务流程连接过程中的一个重要枢纽,对于单据转换的过程 ,系统也支持了通过插件对这个过程进行干预,今天我们就来看一看如何用Python开发单据转换插件。
一、单据转换概述
单据转换,是指把上游所选单据,按照转换规则,自动生成下游单据数据包的过程;不对下游单据进行保存、提交、审核等处理。
单据转换插件,能够介入到单据转换的各个关键时刻,对转换行为进行控制,从而调整所生成的下游数据包;
单据转换按照发起方不同,可分为下推、选单;
下推是指在上游单据列表,把所选单据,生成下游单据数据包,并展示出来;
选单是指在下游单据新增界面,弹出上游单据列表,选择源单返回,然后根据转换规则把源单数据填写到下游单据新增界面上;
选单实际上分为两个独立的过程,一个是选单前过程,根据转换规则,生成源单数据筛选条件,传给源单列表。因此源单列表上显示的,都是允许下推的数据;另外一个就是选单过程,把用户选择返回的源单数据,迁移到目标单据上;
下推与选单,采用相同单据转换规则,进行数据迁移;也采用相同的单据转换插件,但触发的事件略有差异,编写单据转换插件时,需要兼顾这些差异;
二、单据转换规则简介
以下知识结构截图摘取自@eris 老师分享的学习资料,在此感谢老师的用心制作!
也强烈推荐大家看看老师的讲解文章和课程!金蝶云星空BOS专题中级课-业务流程
单据转换的核心是单据转换规则,基于单据转换规则才会有单据转换插件。单据转换规则配置可以实现我们常见的单据流转需求,我们先来简单回顾一下单据转换规则。
单据关联配置:要实现关键关联,需要先在下游单据中设置单据关联配置。
单据转换规则说明
单据转换规则策略要点
可以触发单据转换规则的操作
三、单据转换插件介绍
C#开发时,单据转换插件的基类是AbstractConvertPlugIn。Python插件在单据转换规则-插件策略中注册即可。
单据转换插件开始支持Python插件的版本是PT-146836 [7.5.1.202005],高于此版本,应该都是可以使用的。
单据转换插件是依赖于单据转换规则来触发的,在单据转换从选择单据、指定单据类型、分组合并、过滤携带数据等整个转换过程都提供了插件干预方法,应对一些复杂的单据转换场景需求。所以只要触发了单据转换规则,就可以触发单据转换插件执行过程。
单据下推执行过程
单据选单执行过程
单据转换插件一览图(含事件执行顺序)
选单时,单据转换插件事件执行顺序:与下推有小部分差异
这里要说明的是,下推、选单前、选单过程,采用的插件是同一个。 从事件的覆盖度来看,下推过程触发的事件是最全面的,针对下推过程编写的插件,选单过程被自动覆盖。也就是说通常情况下,在不对选单界面做特殊干预的情况下,按照下推的运行过程来开发一个单据转换插件,对选单操作也是通用的。
四、单据转换插件常用事件
前面的截图中已经将单据转换插件执行过程讲得比较清晰了,总的来说单据转换插件也是按照一条"流水线"执行的,我们只需要在需要干预的环节,去实现对应的事件,加入我们的代码逻辑就可以了。
我们再整体看一下下推运行时序
新建一个单据转换插件,以采购申请下推采购订单为例
下面看看单据转换插件中的一些常用事件
#解析字段映射关系,并构建查询参数。
#这里可以加入你想要的额外的字段
def OnQueryBuilderParemeter(e):
#插件常用全局属性,顺带介绍一下,不一定在此事件中使用 #*************************************************************************************************************
#this.OperationNumber;#操作编码,如下推,选单操作等,值分别为Push,Draw,
#paraDIC=this.Option.GetVariables();#获取自定义参数集,字典类型,例如是否整单下推、是否需要校验下游单据新增权限、WebAPI调下推时传入的自定义参数等等
#if(paraDIC.ContainsKey("参数标识")==True):#判断是否含有某个参数
# paraValue=paraDIC["参数标识"];#取出参数标识
#***********************************************************************************************************
#e.SourceBusinessInfo;#上游单据的元数据信息,可从这里获取一些上游单据的关键信息
# secFormId=e.SourceBusinessInfo.GetForm().Id;#上游单据FormId
billNo=SelectorItemInfo("FBillNo");#加入单据转化规则中没有配置的,但需要额外加载的字段
e.SelectItems.Add(billNo);
#解析过滤策略中配置的条件,可以在这里加自定义的下推过滤条件
#此事件开始前,刚完成选单条件策略中的过滤条件的解析
#e.FilterPolicySQL来自于:【选单条件策略中设置的过滤条件(JsonSetting)】+【选单条件策略中的附加条件(CustFilter)】+【按目标组织基础资料属性过滤的条件(TargetOrgBDFilterList)】
#此事件结束后,e.FilterPolicySQL将使用AND操作符合并到QueryBuilderParemeter.FilterClauseWihtKey,后续作用于选单列表取数
def OnParseFilter(e):
filterStr=" FBillNo LIKE 'CGSQ%' ";
e.FilterPolicySQL=StringUtils.JoinFilterString(e.FilterPolicySQL,filterStr);#追加过滤条件,默认用AND连接
e.PlugFilterDesc = "单据编号必须包含【CGSQ】";#过滤条件描述信息,下推不满足时,会提示出来。
#选单时才有,解析字段映射关系中配置的过滤选项:过滤/仅追加
#此事件开始前,刚完成用于选单列表取数的QueryBuilderParemeter的构建,e.FilterOptionsSQL来自于QueryBuilderParemeter.FilterClauseWihtKey
def OnParseFilterOptions(e):
#e.TargetData;#目标单的数据包
#e.SourceBusinessInfo;#源单元数据信息
#e.TargetBusinessInfo;#目标单元数据信息
filterStr=" FReqQty > 10 ";
e.FilterOptionsSQL = StringUtils.JoinFilterString(e.FilterOptionsSQL,filterStr);#追加选单过滤条件
#获取到源单数据之后触发,(下推执行)
#可以在此事件中修改源单下推的数据包,不会真实修改源单,只会影响下推的携带值
#例如,可以动态修改源单分单依据字段的值,以此实现动态分单策略
def OnGetSourceData(e):
#e.SourceBusinessInfo;#源单元数据信息
srcData=e.SourceData;#源单数据,本次下推的所有数据行,DynamicObjectCollection类型
#可循环从数据包集合中取数,只能取到参与转换规则中配置的字段和OnQueryBuilderParemeter额外加入的字段
for row in srcData:
srcId=row["Id"];#源单Id
srcEntryId=str(dr["FEntity_FEntryID"]);#源单分录内码:单据体标识_FEntryId
#获取到源单数据之后触发,(选单执行)
#与OnGetSourceData类似,只不过一个是在下推执行,一个是选单执行
def OnGetDrawSourceData(e):
#e.SourceBusinessInfo;#源单元数据信息
srcData=e.SourceData;#源单数据,本次下推的所有数据行,DynamicObjectCollection类型
#可循环从数据包集合中取数,只能取到参与转换规则中配置的字段和OnQueryBuilderParemeter额外加入的字段
for row in srcData:
srcId=row["Id"];#源单Id
srcEntryId=str(dr["FEntity_FEntryID"]);#源单分录内码:单据体标识_FEntryId
#执行分组前触发,可以在此增加自定义的分组字段
def OnBeforeGroupBy(e):
srcData= e.SourceData;#源单数据
HeadGroupKey = e.HeadGroupKey;#分单依据
e.HeadGroupKey =("{0},{1}").format(e.HeadGroupKey,"FXXX");#追加分组字段
EntryGroupKey=e.EntryGroupKey;#单据体分组合并字段
e.EntryGroupKey =("{0},{1}").format(e.EntryGroupKey,"FEXXX");#追加单据体分组合并字段
SubEntryGroupKey=e.SubEntryGroupKey;#子单据体分组字段
e.SubEntryGroupKey =("{0},{1}").format(e.SubEntryGroupKey,"FEXXX");#追加单据体分组字段
#下推执行,根据分组策略创建目标单,此时还没根据字段映射赋值目标单的字段,这个事件用得不多
#也没有创建关联数据包,接近一个"空白"的下游单据,当然有默认值的字段还是有值
def OnCreateTarget(e):
headEntity=e.TargetExtendedDataEntities.FindByEntityKey("FBillHead");#分组之后创建的所有目标单集合
for entity in headEntity:
billObj=entity.DataEntity;#下游单据的完整数据包,可以通过实体数据包操作方式处理下游单据字段
#选单执行,与OnCreateTarget类似,此时获取到了选单返回的数据,但是还没赋值到下游单据的字段上
def OnCreateDrawTarget(e):
headEntity=e.TargetExtendedDataEntities.FindByEntityKey("FBillHead");#获取根据分组创建好的目标单
#目标单赋值之前触发,主要用启动字段赋值事件OnFieldMapping,用于监听字段映射赋值过程,用得很少
def OnBeforeFieldMapping(e):
e.FireFieldMappingEvent=True;#启动字段赋值
#字段赋值事件,每个数据包,每个字段都会触发,易影响性能,慎用!
def OnFieldMapping(e):
headEntity=e.TargetExtendedDataEntities.FindByEntityKey("FBillHead");#下游单据数据集
fldKey=e.TargetField.Key.ToUpperInvariant();#赋值字段标识大写
#字段映射所有字段赋值完成之后触发,用得很少
def OnAfterFieldMapping(e):
headEntity=e.TargetExtendedDataEntities.FindByEntityKey("FBillHead");#下游单据数据集
#创建关联关系之前触发,可以取消创建,用得很少
def OnCreateLink(e):
headEntity=e.TargetExtendedDataEntities.FindByEntityKey("FBillHead");#下游单据数据集
#e.Cancel=True;#取消创建
#单据关联关系创建之后触发,表单服务策略执行之前
#如果需要干预下游单据,再执行表单服务策略,可以在此事件中对下游单据进行处理
#例如,要通过插件修改采购订单单价,之后系统自动执行表单服务策略计算金额
def OnAfterCreateLink(e):
headEntity = e.Result.FindByEntityKey("FBillHead");#由于可能分单,所以可能有多个下游单据,是一个集合
for entity in headEntity:#循环处理
billObj=entity.DataEntity;#下游单据的完整数据包,可以通过实体数据包操作方式处理下游单据字段
#获取到服务策略之前触发,可在此事件中加入自定义的表单服务或者移除服务,用得少
def OnGetConvertBusinessService(e):
FormSvcList=e.FormBusinessServices;#表单服务集合
#单据转换执行完成之后执行,在表单服务策略执行完成之后
#可以获取到下推完成之后,还未保存的下游单据,对下游单据数据包做最后的处理
#应用案例:单据转换插件提示消息
def AfterConvert(e):
#整个单据转换执行完毕后的下游单据数据集合,相当于用户看到的推出来的下游单据,但是还没保存
headEntity = e.Result.FindByEntityKey("FBillHead");#由于可能分单,所以可能有多个下游单据,是一个集合
for entity in headEntity:#循环处理
billObj=entity.DataEntity;
相关应用案例参考推荐:
显示单据转换操作页面事件OnShowConvertOpForm
单据转换插件,动态表单插件,表单插件,服务插件,多单据体应用
......
==========================本篇正文结束=====================================
截止到这一篇,Python插件开发各插件类型,已经介绍完了,感谢大家一如既往的关注与支持!
插件示例代码已经上传附件,老规矩,大家按需下载!
大家持续关注,点赞、评论、收藏,您的点赞、评论就是我前进的动力。
下一篇:【Python插件入门】第10篇(完结篇):插件常用工具类分享
Python单据转换插件示例.rar(3.12KB)
发布于 金蝶云星空BOS开发交流圈 社群
推荐阅读