本文以采购申请单为例,介绍了如何通过自定义插件实现将同一申请人的单据合并打印在一张纸上,包括金额合并计算并以中文大写形式打印,以及单据体信息的展示。详细说明了思路、方案、实现过程和注意事项,包括重写`customPrintDataEntities`方法处理数据包,分单据头和单据体分别处理,并给出了示例代码和关键步骤的说明。最后,还提及了开发环境版本、注意事项、新功能的支持情况,以及参考资料和操作指导。
关键词:套打/打印
一、需求
以采购申请单为例,把同一个申请人的单据合并打印在一张纸上,并将单据体中的金额合并计算后以中文大写金额打印在头上,在数据表格(单据体)中展示单据编号、单据状态、物料名称、申请数量、单价、金额等信息。
二、思路与方案
打印单据列表界面勾选的数据时,因数据可能会有多条,故需在插件中处理数据包将多条数据业务数据合并成一条。但在处理数据包时,平台底层是按单据头、单据体分开处理的,故我们也可在打印插件中按此思路来进行二开。
三、实现过程
1. 以采购申请单为例,设计其打印页面,其设计器界面如下图所示。
2. 重写 customPrintDataEntities(CustomPrintDataEntitiesArgs) 方法,干预打印的取数逻辑。其中,分单据头、单据体分别处理数据包。
@Override public void customPrintDataEntities(CustomPrintDataEntitiesArgs e) { // 列表中选中的数据 List<DynamicObject> selectedBillDataList = e.getDataEntities(); if (StringUtils.isBlank(selectedBillDataList)) { return; } // 新数据包 List<DynamicObject> newDataEntityList = null; // 数据源处理 if (StringUtils.equalsIgnoreCase(KEY_BILL, e.getDataSourceName())) { newDataEntityList = this.newDataEntityHeaderPack(selectedBillDataList, e.getPkIds(), e.getCustomFields()); } else if (StringUtils.equalsIgnoreCase(KEY_ENTRYENTITY, e.getDataSourceName())) { newDataEntityList = this.newDataEntityEntryPack(selectedBillDataList, e.getPkIds(), e.getCustomFields()); } // 将新数据包设置回去 if (!newDataEntityList.isEmpty()) { e.setDataEntities(newDataEntityList); } super.customPrintDataEntities(e); } /** * 生成新的待打印数据的单据头部分 * @param selectedBillDataList 单据列表界面选中的数据包 * @param selectedBillPkIds 单据列表界面选中的单据的主键ID * @param customFieldSet 自定义字段 * @return */ private List<DynamicObject> newDataEntityHeaderPack(List<DynamicObject> selectedBillDataList, List<Object> selectedBillPkIds, Set<String> customFieldSet) { List<DynamicObject> newDataEntityList = new ArrayList<DynamicObject>(); String selectFields = "kdec_applier, kdec_entryentity.kdec_amount"; QFilter filter = new QFilter("id", QCP.in, selectedBillPkIds); DataSet selectedBillDataSet = QueryServiceHelper.queryDataSet(getClass().getName(), KEY_BILL, selectFields, filter.toArray(), null); // 根据申请人分组后对金额汇总求和 selectedBillDataSet = selectedBillDataSet.groupBy(new String[] { "kdec_applier" }).sum("kdec_entryentity.kdec_amount").finish(); selectedBillDataSet = selectedBillDataSet.select("kdec_applier", "kdec_entryentity.kdec_amount kdec_totalamount"); for (Row row : selectedBillDataSet) { // 重新构造待打印数据的单据头部分数据(添加字段:总金额 & 总金额(大写)) DynamicObject newbillObj = null; for (DynamicObject tempObj : selectedBillDataList) { if (StringUtils.equalsIgnoreCase(row.getString("kdec_applier"), tempObj.getDynamicObject("kdec_applier").getPkValue().toString())) { newbillObj = (DynamicObject) (new CloneUtils(false, false)).clone(this.getNewEntityTypeFunc1(tempObj, customFieldSet), tempObj); // 克隆生成的新数据包,其中的基础资料类型字段,即使前后所有属性均一致,也需重新赋值,否则打印页面该字段为空! newbillObj.set("kdec_applier", tempObj.getDynamicObject("kdec_applier")); newbillObj.set("kdec_applyorg", tempObj.getDynamicObject("kdec_applyorg")); BigDecimal totalAmount = row.getBigDecimal("kdec_totalamount"); newbillObj.set("kdec_totalamount", totalAmount); newbillObj.set("kdec_totalamount_capital", MoneyConvertUtil.toChinese(totalAmount.toString())); break; } } newDataEntityList.add(newbillObj); } return newDataEntityList; } /** * 生成新的待打印数据的单据体部分 * @param selectedBillDataList 单据列表界面选中的数据包 * @param selectedBillPkIds 单据列表界面选中的单据的主键ID * @param customFieldSet 自定义字段 * @return */ private List<DynamicObject> newDataEntityEntryPack(List<DynamicObject> selectedBillDataList, List<Object> selectedBillPkIds, Set<String> customFieldSet) { List<DynamicObject> newDataEntityList = new ArrayList<DynamicObject>(); // 查询当前数据源(单据体)数据的申请人字段信息 String selectFields = "id, billno, kdec_applier, kdec_applyorg, kdec_currency, billstatus, " + "kdec_entryentity.kdec_materiel, kdec_entryentity.kdec_unit, kdec_entryentity.kdec_applyqty, " + "kdec_entryentity.kdec_price, kdec_entryentity.kdec_amount"; QFilter filter = new QFilter("kdec_entryentity.id", QCP.equals, selectedBillDataList.get(0).getPkValue()); DynamicObject selectedBillDataObj = BusinessDataServiceHelper.loadSingle(KEY_BILL, selectFields, filter.toArray()); if (selectedBillDataObj == null) { return newDataEntityList; } // 查询列表中选中的同一申请人的所有单据数据 QFilter qFilter1 = new QFilter("id", QCP.in, selectedBillPkIds); QFilter qFilter2 = new QFilter("kdec_applier", QCP.equals, selectedBillDataObj.getDynamicObject("kdec_applier").getPkValue().toString()); DynamicObject[] selectedBillDataArr = BusinessDataServiceHelper.load(KEY_BILL, selectFields, new QFilter[] { qFilter1, qFilter2 }); // 将所选单据的单据体数据合并到一起打印 for (DynamicObject billObj : selectedBillDataArr) { DynamicObjectCollection entryEntityColl = billObj.getDynamicObjectCollection(KEY_ENTRYENTITY); // 注册属性(单据编号 & 单据状态) for (DynamicObject entryEntity : entryEntityColl) { // 复制生成新的数据包--注:CloneUtils中的参数可以自行设置 DynamicObject newObj = (DynamicObject) (new CloneUtils(false, false)).clone(this.getNewEntityTypeFunc2(entryEntity, customFieldSet), entryEntity); newObj.set("kdec_billno", billObj.get("billno")); // 将数据库中单据状态的值转换成对应的中文名称 String billstatusVal = billObj.getString("billstatus"); MainEntityType entityType = MetadataServiceHelper.getDataEntityType(KEY_BILL); BillStatusProp billStatusProp = (BillStatusProp) entityType.findProperty("billstatus"); List<ValueMapItem> items = billStatusProp.getComboItems(); for (ValueMapItem item : items) { if (StringUtils.equalsIgnoreCase(billstatusVal, item.getValue())) { newObj.set("kdec_billstatus", item.getName()); break; } } // 克隆生成的新数据包,其中的基础资料类型字段,即使前后所有属性均一致,也需重新赋值,否则打印页面该字段为空! newObj.set("kdec_materiel", entryEntity.getDynamicObject("kdec_materiel")); newDataEntityList.add(newObj); } } return newDataEntityList; }
四、效果图
五、开发环境版本
旧版打印功能
六、注意事项
1. 套打/打印页面设计器上字段的单元格类型为:自定义,则必须配置其数据源属性。否则在套打/打印插件中的customPrintDataEntities 事件通过 e.getCustomFields() 获取到的自定义字段集合为空!
2. 克隆生成的新数据包,其中的基础资料类型字段,即使前后所有属性均一致,也需重新赋值,否则打印页面该字段为空!
3. 新版打印功能已支持列表打印功能,无需二开,详情请参阅 所见即所得之列表打印。
4. 附件包中含有样例的页面元数据和Java插件源码。各位小伙伴通过在mc中升级补丁的方式导入元数据,在本地开发工具中导入Java插件,重启服务后即可复现样例效果。
七、参考资料
知识 —— 产品目录 —— 系统服务云 —— 配置工具 —— 维护打印模板 & 打印方案 & 管理打印字体
勾选单据列表多条业务数据后合并打印.rar(31.76KB)
推荐阅读