文本主要介绍了在采购申请单处理中,根据按钮是否绑定操作代码来实现不同的操作校验方案。对于未绑定操作代码的按钮(如查看库存),通过监听点击前事件(beforeClick或beforeItemClick)进行校验。而对于绑定了操作代码的按钮(如提交采购申请单),提供了多种校验方式,包括操作前事件(beforeDoOperation)、操作校验规则配置、以及通过服务插件自定义校验器(AbstractOperationServicePlugIn的onAddValidators方法)进行校验。文本还详细展示了如何通过编码实现这些校验逻辑,并给出了具体实现代码示例和效果图。
关键词:操作代码、服务插件自定义校验器、操作校验、前端按钮校验
一、需求背景
(1)需求一:新增的采购申请单提交的时候需要校验:采购方式为自费时,采购单价不能为空或小于等于0,其中提交绑定了操作代码submit。
图1
图2
(2)需求二:采购申请单的采购信息(单据体)上有一个按钮(查看库存),没有绑定操作代码,点击查看库存直接,需要校验是否选择了采购信息分录行,且分录行上的物料不为空
图3
二、实现方案
1、分析思路
业务校验主要看按钮是否绑定了操作代码以及是否是界面操作,还是后台操作
(1)如果没有绑定操作代码,只能通过beforeClick或beforeItemClick监听按钮的点击前事件进行校验
(2)如果按钮绑定了操作代码但是只在用户点击按钮的时候触发校验,那么可以通过以下四种方法实现校验
①beforeClick,beforeItemclick 按钮点击前事件
②操作类型为save、submit等实体操作(和数据库有数据交互的操作为实体操作)操作还可以通过校验规则配置实现校验
③beforeDoOperation操作前事件
④服务插件校验:继承操作服务类AbstractOperationServicePlugIn,添加自定义校验器onAddValidators
(3)如果通过后台代码而非界面操作触发的操作,则只只能通过以下方式实现业务校验
①服务校验插件,即继承操作服务类AbstractOperationServicePlugIn,添加自定义校验器onAddValidators
②操作类型为save、submit等个别操作还可以通过校验规则配置实现校验
2、实现方案
①beforeClick触发的是按钮控件的点击前事件,beforeItemClick触发的是工具栏按钮的点击前事件
②beforeDoOperation操作前事件对比于beforeClick、beforeItemClick点击前事件:beforeClick、 beforeItemClick可以触发无操作按钮的点击事件,beforeDoOperation可以传递一些给自定义操作参数给操作服务、操作插件;
③不要同时使用多种方式对同一个校验需求进行校验,一般能通过校验规则配置实现的就用校验规则,界面规则不能实现的一般都是用服务插件实现,因为每个绑定操作的校验都会走服务插件的校验。
另外,存在校验规则校验不通过,则不会再触发自定义校验器逻辑
图4
三、实现过程
1、无操作代码的按钮校验
以需求二为例,没有绑定操作代码,只能通过beforeClick或beforeItemClick监听按钮的点击前事件进行校验。因为需求二上面的查看库存是工具栏的按钮,需要需要通过监听beforeItemClick点击前事件
图5
(1)添加”查看库存”所在工具栏的监听
@Override public void registerListener(EventObject e) { //kded_lookstock添加单据体工具栏的监听 Toolbar tb = this.getView().getControl("kded_advcontoolbarap"); tb.addItemClickListener(this); }
(2)编写校验逻辑
@Override public void beforeItemClick(BeforeItemClickEvent evt) { EntryGrid entryGrid = this.getView().getControl("kded_entryentity"); //获取选中行 int[] selectRows = entryGrid.getSelectRows(); StringBuilder strbd = new StringBuilder(); for (int i = 0; i < selectRows.length; i++) { Object materie = this.getModel().getValue("kded_materielfield", selectRows[i]); if (materie == null) {//添加为空的行号 strbd.append(String.valueOf(selectRows[i]+1)); strbd.append("、"); } } if (strbd.length()>0) { strbd.deleteCharAt(strbd.length()-1); this.getView().showErrorNotification(String.format("第%s行物料值不能为空", strbd.toString())); evt.setCancel(true); } super.beforeItemClick(evt); }
(3)效果图
图6
2、有操作代码的按钮校验
以需求一为例介绍绑定了操作代码的校验方案,该场景有四种校验方式:
beforeClick,beforeItemclick 按钮点击前事件(该种方式的实现请参考“1、无操作代码的按钮校验”)
操作类型为save、submit等实体操作(和数据库有数据交互的操作为实体操作)操作还可以通过校验规则配置实现校验
beforeDoOperation操作前事件
服务插件校验:继承操作服务类AbstractOperationServicePlugIn,添加自定义校验器onAddValidators
2.1、操作校验规则
(1)以需求一为例:当采购方式为自费时,采购单价不能小于等于0,配置的校验规则如下,选中提交按钮-操作代码-选择操作-选中提交操作-修改-操作编辑-其他控制-校验规则-新增一个合法性校验,设置合法性校验规则如下
图7
2.2、beforeDoOperation事件的业务校验
(1)beforeDoOperation(BeforeDoOperationEventArgs args)事件界面操作事件,是用户点击保存、提交等执行报保存、提交绑定的操作之前触发的事件,我们可以在该事件中做相关的业务校验。以需求一为例:当采购方式为自费时,采购单价不能小于等于0,实现的校验逻辑如下
@Override public void beforeDoOperation(BeforeDoOperationEventArgs args) { if (args.getSource() instanceof Submit) { Submit opp = (Submit) args.getSource(); //获取采购申请单实体数据 DynamicObject dataEntity = this.getModel().getDataEntity(true); //获取采购信息单据体数据 DynamicObjectCollection dynamicObjectCollection = dataEntity.getDynamicObjectCollection("kded_entryentity"); StringBuilder strbd = new StringBuilder(); for (int i = 0; i < dynamicObjectCollection.size(); i++) { //各分录行数据 DynamicObject entryObj = dynamicObjectCollection.get(i); BigDecimal price = entryObj.getBigDecimal("kded_pricefield"); int reqWay = entryObj.getInt("kded_combofield"); //采购方式为自费时,采购单价不能小于0 if (reqWay==1&&price.compareTo(BigDecimal.ZERO)<1) { strbd.append(i+1); strbd.append("、"); } } if (strbd.length()>0) { strbd.deleteCharAt(strbd.length()-1); this.getView().showErrorNotification(String.format("第%s行采购方式为自费时,采购单价不能小于0", strbd.toString())); //取消提交操作 args.setCancel(true); } } super.beforeDoOperation(args); }
(2)效果图
图8
2.3、操作服务插件校验
(1)主要工具栏上的提交按钮绑定了提交操作,不管是用户点击提交的界面操作,还是通过OperateServiceHelper.executeOperate(“submit”, entityNumber, dataEntities, option)等方式后台调用的提交操作,都会触发提交操作服务插件的校验逻辑。以需求一为例:当采购方式为自费时,采购单价不能小于等于0,实现的校验逻辑如下
①添加服务插件类,继承于AbstractOperationServicePlugIn,添加自定义校验器ReqSubmitValidator()
public class ReqOppSubmitServicePlugin extends AbstractOperationServicePlugIn { /** * 插件需要在此事件,添加需要用到的字段; * 否则,操作引擎加载出的单据数据包,可能没有插件要用到的字段值,从而引发中断 */ @Override public void onPreparePropertys(PreparePropertysEventArgs e) { //加载“采购方式”字段 e.getFieldKeys().add("kded_combofield"); //加载“采购单价”字段 e.getFieldKeys().add("kded_pricefield"); } /** * 执行操作校验前,触发此事件 * @remark * 插件可以在此事件,调整预置的操作校验器;或者增加自定义操作校验器 */ @Override public void onAddValidators(AddValidatorsEventArgs e) { //添加自定义的校验器: e.addValidator(new ReqSubmitValidator()); } }
②实现自定义校验器逻辑,校验器类基类AbstractValidator,覆盖方法validate
public class ReqSubmitValidator extends AbstractValidator { @Override public void validate() { for (ExtendedDataEntity extendedDataEntity : this.getDataEntities()) { DynamicObject dataEntity = extendedDataEntity.getDataEntity(); DynamicObjectCollection entrys = dataEntity.getDynamicObjectCollection("kded_entryentity"); StringBuilder strbd = new StringBuilder(); for (int i = 0; i < entrys.size(); i++) { //各分录行数据 DynamicObject entryObj = entrys.get(i); BigDecimal price = entryObj.getBigDecimal("kded_pricefield"); int reqWay = entryObj.getInt("kded_combofield"); //采购方式为自费时,采购单价不能小于0 if (reqWay==1&&price.compareTo(BigDecimal.ZERO)<1) { strbd.append(i+1); strbd.append("、"); } } if (strbd.length()>0) { strbd.deleteCharAt(strbd.length()-1); //提示校验失败,终止提交操作 this.addErrorMessage(extendedDataEntity, String.format("第%s行采购方式为自费时,采购单价不能小于0!", strbd.toString())); }}}}
③注册提交操作的服务插件
图9
(2)效果图
图10
四、开发环境版本
COSMICV4.0.010.0
五、注意事项
案例补充:有个定时任务:采购申请单下推生成采购订单之后,定时任务自动提交暂存状态的采购订单。有个开发在beforeDoOperation中写了对采购订单的的校验逻辑,但是定时任务执行提交操作时并没有触发beforeDoOperation的校验逻辑。
解决方案:因为beforeDoOperation是界面点击操作触发的事件,所以需要在服务插件中写校验逻辑
六、参考资料
billplugin.zip(3.12KB)
推荐阅读