本文介绍了在业务单据(如采购申请单)生成凭证时,实时反写单据上“是否已生成凭证”及凭证号字段的实现方案。首先,通过编写一个反写插件,继承并实现相关方法以指定数据库路由、获取凭证启用/禁用状态及需反写的字段名。然后,注册该插件至系统配置中,使其与单据审核后的凭证生成操作关联。最后,扩展了插件的writeBack方法,以在生成或删除凭证时,将凭证状态及凭证号实时反写回采购申请单上,实现单据与凭证信息的同步更新。
一、需求背景
在业务单据生成凭证的时候需要实时反写业务单据是否生成了凭证,这里以采购申请单生成凭证时实时反写采购申请单上的“是否已生成凭证号”字段为是;或者反写凭证号字段到单据上(采购申请单是业务无关的单据,仅仅是为了说明案例使用)
二、实现方案
1、编写反写插件
(1)反写插件继承 bos-ext-fi 下面的 kd.bos.ext.fi.ai.AbstractDapWriteBackImpl实现以下四个方法
public class DapconfigDemoPlugin extends AbstractDapWriteBackImpl { @Override protected DBRoute getDBRoute() { //用DBRoute对应具体的物理库,由mc的数据中心管理进行配置。 //secd是采购申请单物理表所在的库名,扩展开发库 DBRoute DBR = DBRoute.of("secd"); return DBR; } @Override//删除凭证写入的值这里是复选框- 布尔false protected Object getVchDisableStatus() { Boolean disRchValue=false; return disRchValue; } @Override//生成凭证时写入的值,这里是复选框- 布尔 true。 protected Object getVchEnableStatus() { Boolean rchValue=true; return rchValue; } @Override//要反写的字段的字段名-是否已反写凭证 protected String getVchStatusField() { String vchField="fk_sunp_ifvoucher"; return vchField; } }
(2)mc分库标识
2、插件注册
开发平台搜索“dap配置”或者ai_dapconfig
配置上面二开实现的反写插件,关联操作audit指单据审核之后才能进行凭证生成的操作
3、扩展-凭证号反写:
实现完上面1-2的操作之后,AbstractDapWriteBackImpl的writeBack方法会被调用执行,而writeBack会调用到我们二开重写的方法getVchStatusField()和getVchEnableStatus():DB.execute(getDBRoute(), "update "+mt.getAlias()+" set "+getVchStatusField()+" = ? where fid in ("+StringUtils.join(cache.toArray(), ',')+")", new Object[]{getVchEnableStatus()});
本案例二开重写的四个方法,只能实时反写修改采购申请单上面某个字段的值=某个常量,以此来判断采购申请单是否已生成了凭证,如果需要对应反写凭证号回采购申请单,可以重写writeBack方法:实现生成凭证时反写采购申请单上的凭证号字段,删除凭证时删除采购申请单上的凭证号
①operation:执行的操作,生成凭证、删除凭证等
②billEntityNumber:执行生成凭证的单据的单据标识,这里是采购申请单的单据标识
③billToVch:单据编号和凭证号的映射信息
public void writeBack(VoucherOperation operation, String billEntityNumber, Map<Long, Voucher> billToVch)
如果实现了凭证号反写,根据采购申请单上是否反写了凭证号就可以判断是否生成了凭证号,就没必要再在getVchStatusField()和getVchEnableStatus()方法中设置反写是否已生成凭证号的字段了。(这里为了看效果,都实现了)
@Override public void writeBack(VoucherOperation operation, String billEntityNumber, Map<Long, Voucher> billToVch) { MainEntityType mt = EntityMetadataCache.getDataEntityType(billEntityNumber); Set<Long> keySet = billToVch.keySet(); if (VoucherOperation.Create.equals(operation)) { //#开始执行生成凭证反写:" Object vchStatusField = getVchEnableStatus(); List<Object[]> params = new ArrayList<>(); for (Long me : keySet) { //#生成凭证的单据ID Voucher voucher=billToVch.get(me);//凭证 String voucherNo = voucher.getVoucherNo(); //这里处理的是一个单据只有一个凭证的时候,如果是多个凭证,可以先获取已经生成的凭证号,再拼接上字符串。 Object[] param = new Object[] { vchStatusField,voucherNo, me };// params.add(param); if (params.size() >= 10000) { //#开始执行生成凭证反写SQL DB.executeBatch(getDBRoute(), "update " + mt.getAlias() + " set " + getVchStatusField() + " = ? , "+voucherNoFile+" = ? where fid = ?", params); //#结束执行生成凭证反写SQL params.clear(); } } //#最后#开始执行生成凭证反写SQL if (params.size() > 0) { DB.executeBatch(getDBRoute(), "update " + mt.getAlias() + " set " + getVchStatusField() + " = ? , "+voucherNoFile+" = ? where fid = ?", params); } //#最后#结束执行生成凭证反写SQL } else if (VoucherOperation.Delete.equals(operation)) { //#开始执行删除凭证反写 Object vchDisableStatus = getVchDisableStatus(); List<Object[]> params = new ArrayList<>(); for (Long me : keySet) { log.info("AbstractDapWriteBackImpl#删除凭证的单据ID:" + me); //这里处理的是一个单据只有一个凭证的时候,如果是多个凭证,可以先获取已经生成的凭证号,再去掉本凭证之后的凭证号 Object[] param = new Object[] {vchDisableStatus, "",me };// getVchDisableStatus params.add(param); if (params.size() >= 10000) { //#开始执行删除凭证反写SQL DB.executeBatch(getDBRoute(), "update " + mt.getAlias() + " set " + getVchStatusField() + " = ? , "+voucherNoFile+" = ? where fid = ?", params); params.clear(); //#结束执行删除凭证反写SQL } } //#最后#开始执行删除凭证反写SQL if (params.size() > 0) { DB.executeBatch(getDBRoute(), "update " + mt.getAlias() + " set " + getVchStatusField() + " = ? , "+voucherNoFile+" = ? where fid = ?", params); } //#最后#结束执行删除凭证反写SQL } }
三、实现效果
1、点击生成凭证,会弹出生成的凭证,退出凭证,刷新采购申请单,可以看到“是否已生成凭证已被反写修改为“是”;凭证号已被反写回采购申请单上。
DapconfigDemoPlugin.zip(1.60KB)
sunp_reqbill_demo.zip(4.89KB)
推荐阅读