botp调用下推服务保存附件面板
1 业务场景
背景介绍:调用botp下推服务,拿到下推结果之后,下推结果中包含了生成的附件面板信息,但保存目标单附件面板信息,附件面板属于控件,不属于字段类型,需要调用方在保存目标单之后,再去保存附件面板信息。
2 下推服务地址
服务类:kd.bos.servicehelper.botp.ConvertServiceHelper
方法:push
3 下推服务参数
请求参数
参数 | 描述 | 类型 | 是否必填 |
appId | 需要鉴权的应用 | String | 否 |
sourceEntityNumber | 源单单据标识 | String | 是 |
targetEntityNumber | 目标单单据标识 | String | 是 |
ruleId | 指定转换规则id | String | 否 |
buildConvReport | 是否输出报告(true输出,false不输出) | Boolean | 否 |
customParams | 自定义参数,可以在整个下推流程中获取 | Map<String,String> | 否 |
defOrgId | 设置下推默认设置的主组织 | Long | 否 |
ruleIds | 限定可用的转换规则范围,如果为空,则即时到数据库取所有可用的转换规则进行下推 | Set<String> | 否 |
hasRight | 下推时是否不需要验权,默认为不验权(兼容大部分插件代码自动下推),(true不鉴权,false鉴权) | Boolean | 否 |
autoSave | 是否下推自动保存,在转换规则和参数都启用的情况下才有效(true并且转换规则开启自动保存才会自动保存,false则不会自动保存) | Boolean | 否 |
返回参数:
参数 | 描述 | 类型 | 是否为空 |
sourceEntityNumber | 源单单据标识 | String | 否 |
targetEntityNumber | 目标单单据标识 | String | 否 |
targetBillFormId | 下推成功后,打开目标单使用的布局 | String | 否 |
targetMobFormId | 移动端下推成功后,打开目标单使用的移动端布局 | String | 否 |
success | 是否下推成功(true成功false失败) | Boolean | 否 |
message | 提示消息 | String | 是 |
billReports | 源单转换报告,主要包含转换失败的行报告,转换成功的行,自动略过 | List<SourceBillReport> | 是 |
cachePageIds | 下推成功后,生成的数据包,是放在Redis缓存中的,以pageId为标识存取,(下推自动保存时该值为空) | List<String> | 是 |
cacheTargetObjStr | 下推生成的目标单,序列化后的字符串内容(下推自动保存时该值为空) | Map<String, String> | 是 |
dataMutexSrcBillIds | 申请网控成功的源单:需要在保存目标单后及时释放网控 | Set<String> | 是 |
targetBillIds | 下推大单并保存,保存成功,输出目标单内码(下推自动保存时才有值) | Set<Object> | 是 |
startTime | 下推引擎,开始执行时间 | Date | 否 |
finishedTime | 下推引擎,完成执行时间 | Date | 否 |
4代码示例
// 创建下推参数
PushArgs pushArgs = new PushArgs();
// 必填,源单标识
pushArgs.setSourceEntityNumber(sourceBill);
// 必填,目标单标识
pushArgs.setTargetEntityNumber(targetBill);
// 可选,传入true,不检查目标单新增权
pushArgs.setHasRight(false);
// 可选,传入目标单验权使用的应用编码
pushArgs.setAppId("");
// 可选,传入目标单主组织默认值
pushArgs.setDefOrgId(orgId);
//可选,转换规则id
pushArgs.setRuleId(ruleId);
// 可选,是否输出详细错误报告
pushArgs.setBuildConvReport(true);
// 必填,设置需要下推的单据,或分录行
List<ListSelectedRow> selectedRows = new ArrayList<>();
//第一行
ListSelectedRow row1 = new ListSelectedRow();
//必填,设置源单单据id
row1.setPrimaryKeyValue(sourceBillId1);
//可选,设置源单分录标识
row1.setEntryEntityKey("entryentry");
//可选,设置源单分录id
row1.setEntryPrimaryKeyValue(entryId1);
//第二行
ListSelectedRow row2 = new ListSelectedRow();
//必填,设置源单单据id
row2.setPrimaryKeyValue(sourceBillId2);
//可选,设置源单分录标识
row2.setEntryEntityKey("entryentry");
//可选,设置源单分录id
row2.setEntryPrimaryKeyValue(entryId2);
selectedRows .add(row1);
selectedRows .add(row2);
// 必选,设置需要下推的源单及分录内码
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(targetBill);
List<DynamicObject> targetBillObjs = pushResult.loadTargetDataObjects(new IRefrencedataProvider() {
@Override
public void fillReferenceData(Object[] objs, IDataEntityType dType) {
BusinessDataReader.loadRefence(objs, dType);
}
}, targetMainType);
//保存目标单
OperationResult billSaveResult = OperationServiceHelper.executeOperate("save", targetBill, targetBillObjs.toArray(new DynamicObject[0]), OperateOption.create());
//保存附件面板信息
saveAttachmentPanelInfos(targetMainType,billSaveResult.getSuccessPkIds(),pushResult);
}
//保存附件面板信息
private void saveAttachmentPanelInfos(MainEntityType targetEntityType, List<Object> successPkIds, ConvertOperationResult pushResult) {
Map<Object, Map<String, List<AttachmentItemInfo>>> sourceAttachmentPanelInfos = pushResult.getBillAttachmentPanelInfos();
Set<Object> successPkset = new HashSet<>(successPkIds);
for(Map.Entry<Object, Map<String, List<AttachmentItemInfo>>> billAttachmentIndex : sourceAttachmentPanelInfos.entrySet()) {
Long targetPk = Long.parseLong(billAttachmentIndex.getKey().toString());
Map<String, List<AttachmentItemInfo>> billAttachmentItemInfoList = billAttachmentIndex.getValue();
if(!successPkset.contains(targetPk)){
// 失败的单,对应附件信息置为null
sourceAttachmentPanelInfos.remove(targetPk);
continue;
}
// 成功的单,无附件信息就不持久化
if(billAttachmentItemInfoList == null || billAttachmentItemInfoList.isEmpty()) {
continue;
}
persistAttachments(targetEntityType, targetPk, billAttachmentItemInfoList);
}
/**
* 构造附件持久化结构,并调用工具类持久化
* @param targetPk
* @param billAttachItemInfos
* @return 持久化的结构对象
*/
private void persistAttachments(MainEntityType targetEntityType, Object targetPk, Map<String, List<AttachmentItemInfo>> billAttachItemInfos) {
AttachmentInfoPackage pkg = new AttachmentInfoPackage();
pkg.setAppId(targetEntityType.getAppId());
pkg.setFormId(targetEntityType.getName());
pkg.setPkId(targetPk);
pkg.setAttachmentInfo(billAttachItemInfos);
pkg.persist(); // 持久化完成后会清除临时附件标记
}