本文介绍了Business Object Transform Platform(BOTP)的数据转换平台,并以具体场景为例,阐述了如何在BOTP应用中通过开发代码解决业务问题。场景是后台自动下推需求,即源单审核通过后自动生成下游单据。通常可通过配置实现,但在特殊情况下需自行开发。文章详细讲解了调用单据转换服务实现下推并保存目标单,以及后续的提交、审核操作。还提供了相关知识点和示例代码,展示了如何通过封装下推参数、调用下推引擎、判断结果及执行后续操作的过程。读者需掌握Java语言,熟悉单据和操作插件开发,了解BOTP业务。
BOTP是Business Object TransformPlatform的缩写,是基于业务对象(Business Object)技术的数据转换平台。
本文以具体场景入手,介绍如何通过开发来解决BOTP应用中遇到的业务问题。
本文的读者是业务开发、二次开发人员,需要掌握java语言,熟悉单据、操作插件开发,了解BOTP业务。
场景:后台自动下推
需求背景
源单需要在审核通过后自动生成下游单据。
这个需求,正常情况下,可以通过配置实现,无需开发代码,配置方法: 修改源单的审核操作,配置操作服务,添加自动下推服务。
某些特殊情况,无法通过配置实现自动下推,那么就得自行开发代码,调用单据转换服务,实现下推。
本章介绍如何调用下推服务,下推并保存目标单,然后获取下推生成的目标单,执行提交、审核操作;
案例设计
假设有源单,标识为demo_bill1;有两条数据,内码为10001、10002;
需要自动生成目标单,标识demo_bill2;
源单和目标单之间,已经建立并启用了转换规则,关联主实体设为单据体1(entryentity),并配置好了字段映射关系。
相关知识点
实现上述需求,需要用到如下类:
PushArg:下推参数,允许指定好源单、目标单标识,源单需要下推的数据行,以及下推时采用的转换规则等;
ConvertServiceHelper:单据转换帮助类,提供push,pushAndSave方法实现下推;
ConvertOperateResult:下推服务返回的结果,包含生成的目标单数据包,或目标单内码,以及下推失败的错误信息;
OperateionServiceHelper:操作服务帮助类,可以完成目标单的提交、审核等操作;
示例代码
示例代码逻辑思路:
包装下推参数PushArgs
调用下推引擎,下推并保存目标单,获取下推结果
判断下推结果
调用提交操作服务,提交目标单;获取提交结果
判断提交结果
示例代码(仅用于演示如何调用下推、保存、提交等服务,未实际跑通)
package kd.bos.plugin.sample.bill.billconvert.bizcase; import java.util.ArrayList; import java.util.List; import kd.bos.data.BusinessDataReader; import kd.bos.dataentity.OperateOption; import kd.bos.dataentity.entity.DynamicObject; import kd.bos.dataentity.metadata.IDataEntityType; import kd.bos.entity.EntityMetadataCache; import kd.bos.entity.MainEntityType; import kd.bos.entity.botp.runtime.ConvertOperationResult; import kd.bos.entity.botp.runtime.PushArgs; import kd.bos.entity.botp.runtime.SourceBillReport; import kd.bos.entity.datamodel.IRefrencedataProvider; import kd.bos.entity.datamodel.ListSelectedRow; import kd.bos.entity.operate.OperateOptionConst; import kd.bos.entity.operate.result.IOperateInfo; import kd.bos.entity.operate.result.OperationResult; import kd.bos.exception.KDBizException; import kd.bos.servicehelper.botp.ConvertServiceHelper; import kd.bos.servicehelper.operation.OperationServiceHelper; import kd.bos.servicehelper.operation.SaveServiceHelper; /** * 示例代码:自动生成目标单 * * @author rd_johnnyding * */ public class AutoPushSample { private final static String DEMO_BILL1 = "demo_bill1"; private final static String DEMO_BILL2 = "demo_bill2"; /** * 演示自动生成并提交目标单 */ @SuppressWarnings("unused") public void autoPushAndSubmit() { // 创建下推参数,把源单demo_bill1的两张单据10001, 10002,下推生成目标单demo_bill2 PushArgs pushArgs = new PushArgs(); pushArgs.setSourceEntityNumber(DEMO_BILL1); // 必选,源单标识 pushArgs.setTargetEntityNumber(DEMO_BILL2); // 必选,目标单标识 pushArgs.setHasRight(false); // 可选,传入true,不检查目标单新增权 pushArgs.setAppId(""); // 可选,传入目标单验权使用的应用编码 pushArgs.setDefOrgId(0L); // 可选,传入目标单主组织默认值 pushArgs.setRuleId(""); // 可选,传入本次下推使用的转换规则id;传入空值,由系统自动寻找合适的转换规则 pushArgs.setBuildConvReport(true); // 是否输出详细错误报告 // 设置需要下推的单据,或分录行 List<ListSelectedRow> selectedRows = new ArrayList<>(); ListSelectedRow srcBill1 = new ListSelectedRow(10001L); srcBill1.setEntryEntityKey(""); // 可选,如按分录行下推必填:填单据体标识如entryentity srcBill1.setEntryPrimaryKeyValue(0L); // 可选,如按分录行下推必填:填分录行内码如10001 selectedRows.add(srcBill1); ListSelectedRow srcBill2 = new ListSelectedRow(10002L); selectedRows.add(srcBill2); pushArgs.setSelectedRows(selectedRows); // 必选,设置需要下推的源单及分录内码 // 调用下推引擎,下推目标单 ConvertOperationResult pushResult = ConvertServiceHelper.push(pushArgs); // 判断下推是否成功,如果失败,提炼失败消息输出 if (!pushResult.isSuccess()) { String errMessage = pushResult.getMessage(); // 错误摘要 for(SourceBillReport billReport : pushResult.getBillReports()) { // 演示如何提取各单错误报告 if (!billReport.isSuccess()) { String billMessage = billReport.getFailMessage(); } } throw new KDBizException("下推失败:" + errMessage); } // 获取生成的目标单数据包 MainEntityType targetMainType = EntityMetadataCache.getDataEntityType(DEMO_BILL2); List<DynamicObject> targetBillObjs = pushResult.loadTargetDataObjects(new IRefrencedataProvider() { @Override public void fillReferenceData(Object[] objs, IDataEntityType dType) { BusinessDataReader.loadRefence(objs, dType); } }, targetMainType); // 设置保存参数,调用目标单保存服务,保存目标单(保存时自动反写源单) OperateOption saveOption = OperateOption.create(); saveOption.setVariableValue(OperateOptionConst.IGNOREWARN, String.valueOf(true)); // 不执行警告级别校验器 saveOption.setVariableValue(OperateOptionConst.IGNOREINTERACTION, String.valueOf(true)); // 不显示交互提示,自动执行到底 saveOption.setVariableValue(OperateOptionConst.STRICTVALIDATION, String.valueOf(true)); // 全部校验通过才保存 OperationResult saveResult = SaveServiceHelper.saveOperate( DEMO_BILL2, targetBillObjs.toArray(new DynamicObject[0]), saveOption); // 判断保存结果 if (!saveResult.isSuccess()) { String errMessage = saveResult.getMessage(); // 错误摘要 // 演示提取保存详细错误 for(IOperateInfo errInfo: saveResult.getAllErrorOrValidateInfo()) { String detailMessage = errInfo.getMessage(); } throw new KDBizException("保存失败:" + errMessage); } // 设置提交操作,调用目标单提交服务 OperateOption submitOption = OperateOption.create(); submitOption.setVariableValue(OperateOptionConst.IGNOREWARN, String.valueOf(true)); // 不执行警告级别校验器 submitOption.setVariableValue(OperateOptionConst.IGNOREINTERACTION, String.valueOf(true)); // 不显示交互提示,自动执行到底 submitOption.setVariableValue(OperateOptionConst.STRICTVALIDATION, String.valueOf(true)); // 全部校验通过才保存 OperationResult submitResult = OperationServiceHelper.executeOperate( "submit", DEMO_BILL2, saveResult.getSuccessPkIds().toArray(), submitOption); // 判断提交结果 if (!submitResult.isSuccess()) { String errMessage = submitResult.getMessage(); // 错误摘要 // 演示提取提交详细错误 for(IOperateInfo errInfo: submitResult.getAllErrorOrValidateInfo()) { String detailMessage = errInfo.getMessage(); } throw new KDBizException("提交失败:" + errMessage); } } }
推荐阅读