BOTP场景:搜索下游行原创
3人赞赏了该文章
694次浏览
编辑于2021年04月06日 08:39:07
需求背景
业务代码在对上游单据进行处理时,需要找到下游单据,以及各行之间的对应关系,以确定业务流走到了什么程度,据此进行后续逻辑的处理。
本章介绍如何使用平台提供的服务接口,搜索下游单据,并找到每条源单行和目标单行之间的对应关系。
案例设计
假设源头核心单据是demo_botp1,需要寻找下游单据demo_botp2:
demo_botp1 可能直接下推生成 demo_botp2,也可能先下推生成其它单据,然后再由其它单据下推生成demo_botp2;
现在需要从demo_botp1,找到demo_botp2,并找到每条源单行和下游目标单行之间的对应关系;
相关知识点
BFRowLinkDownNode:行关系追溯树,以上游单据分录行作为根节点,逐层往下发散,记录其逐层下推生成的下游单据分录行。通过逐层往下的方式,可以找到分录行全链条的全部下游单据行,包括的直接下游行、跨级下游行;
示例代码
案例实现思路:
开发单据demo_botp1的反审核操作插件,派生自AbstractOperationServicePlugIn;
重写beforeExecuteOperationTransaction方法,搜索下游单据demo_botp2分录行;
调用BFTrackerServiceHelper服务方法,传入本单(源单)主实体编码和单据内码,搜索本单全部分录行的下游行追溯树;
从下游行追溯树上,为当前单据每条分录行,寻找对应的下游目标单据分录行,把行内码对应关系,存储在字典中备用;
不涉及找到目标单分录行之后的业务逻辑;
package kd.bos.plugin.sample.bill.billconvert.bizcase; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import kd.bos.entity.EntityMetadataCache; import kd.bos.entity.ExtendedDataEntity; import kd.bos.entity.botp.runtime.BFRowLinkDownNode; import kd.bos.entity.botp.runtime.TableDefine; import kd.bos.entity.plugin.AbstractOperationServicePlugIn; import kd.bos.entity.plugin.args.BeforeOperationArgs; import kd.bos.servicehelper.botp.BFTrackerServiceHelper; /** * 示例:从源头单据,寻找其下游单据,以及各行之间的对应关系 * * @author rd_johnnyding * */ public class FindTargetRowOpPlugin extends AbstractOperationServicePlugIn { /** * 开启事务保护前,触发本事件:对数据进行检查、整理 */ @Override public void beforeExecuteOperationTransaction(BeforeOperationArgs e) { if (e.getValidExtDataEntities().isEmpty()) { return; } // 获取当前单据(上游单据)的主实体编码、单据内码 String sourceEntityNumber = this.billEntityType.getName(); String sourceEntryKey = "entryentity"; TableDefine sourceEntryTable = EntityMetadataCache.loadTableDefine(sourceEntityNumber, sourceEntryKey); Set<Object> sourceBillIds = new HashSet<>(); for(ExtendedDataEntity dataEntity : e.getValidExtDataEntities()) { sourceBillIds.add(dataEntity.getBillPkId()); } // 取出下游目标单主表的表格定义、单据体的表格定义 String targetEntityNumber = "demo_botp2"; String targetEntryKey = "entryentity"; TableDefine targetMainTable = EntityMetadataCache.loadTableDefine(targetEntityNumber, targetEntityNumber); TableDefine targetEntryTable = EntityMetadataCache.loadTableDefine(targetEntityNumber, targetEntryKey); // 调用平台的服务,获取下游单据追溯树:可以从追溯树上,追查每条分录行的流向 List<BFRowLinkDownNode> linkDownNodes = BFTrackerServiceHelper.loadLinkDownNodes( sourceEntityNumber, // 上游单据主实体编码 "", // 可选参数,如果需要按分录行追溯,此参数传入单据体名称,否则按整单追溯 sourceBillIds.toArray(new Long[0])); // 如果按分录行追溯,此参数传入分录行内码;按整单追溯,此参数传入单据内码 // 定义一个字典,记录上游单据行,关联的全部下游目标单分录行内码:1对多,1条源单行,可能会被拆分为多条下游单分录行 Map<Long, Set<Long>> rowId_targetRowIds = new HashMap<Long, Set<Long>>(); // 遍历行追溯树,逐条源单行分析,找出其对应的下游目标单据分录行 for(BFRowLinkDownNode linkDownNode : linkDownNodes) { if (Long.compare(sourceEntryTable.getTableId(), linkDownNode.getRowId().getTableId()) != 0) { // 当前源单的其他单据体行,略过不处理 continue; } // 获取当前单据的行内码 Long sourceRowId = linkDownNode.getRowId().getEntryId(); // 在字典中,为当前单据的行,创建一个记录 if (!rowId_targetRowIds.containsKey(sourceRowId)) { rowId_targetRowIds.put(sourceRowId, new HashSet<>()); } // 传入需要找的下游目标单主表的tableId,进行全链条搜索 List<BFRowLinkDownNode> targetRowNodes = linkDownNode.findTargetNodes(targetMainTable.getTableId()); // 把搜索到的下游目标单分录行内码添加到字典,和源单行关联起来 for(BFRowLinkDownNode targetRowNode : targetRowNodes) { if (Long.compare(targetEntryTable.getTableId(), targetRowNode.getRowId().getTableId()) != 0) { // 是下游目标单其他单据体分录行,略过不处理 continue; } Long targetRowId = targetRowNode.getRowId().getEntryId(); rowId_targetRowIds.get(sourceRowId).add(targetRowId); } } if (!rowId_targetRowIds.isEmpty()) { // TODO 至此,每条源单分录行,对应的下游目标单分录行,都已经找到,可以进行后续处理 } } }
推荐阅读