BOTP场景:搜索下游行原创
金蝶云社区-MiLai
MiLai
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 至此,每条源单分录行,对应的下游目标单分录行,都已经找到,可以进行后续处理
        }
    }
}


赞 3