Эх сурвалжийг харах

Merge branch 'master' of http://111.75.220.136:10030/turborao/jyyy

tanya 5 өдөр өмнө
parent
commit
1daab2e36d

+ 16 - 0
code/base/nckd-jimin-base-helper/src/main/java/nckd/base/helper/CusFileServiceExt.java

@@ -8,6 +8,7 @@ import kd.bos.service.attachment.FilePathService;
 
 import java.io.File;
 import java.io.InputStream;
+import java.util.Map;
 
 /**
  * 自定义附件服务
@@ -49,4 +50,19 @@ public class CusFileServiceExt extends FilePathService {
         return in;
     }
 
+    @Override
+    public InputStream beforeWriteToResponse(String originalPath, InputStream in, String userAgent) {
+        logger.info("--------------beforeWriteToResponse测试 "+originalPath+"----------------");
+
+        if("preview".equals(userAgent)){
+            in = FileSECUtils.processFileWithSEC(originalPath, in);
+        }
+
+        return super.beforeWriteToResponse(originalPath, in, userAgent);
+    }
+
+    @Override
+    public Map<String, Object> beforeWrite(String originalPath, InputStream in, String userAgent, Map<String, Object> params) {
+        return super.beforeWrite(originalPath, in, userAgent, params);
+    }
 }

+ 155 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/DailyVehicleCusListPlugin.java

@@ -0,0 +1,155 @@
+package nckd.jimin.jyyy.fi.plugin.form;
+
+import kd.bos.bill.BillOperationStatus;
+import kd.bos.bill.BillShowParameter;
+import kd.bos.dataentity.RefObject;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.datamodel.ListSelectedRow;
+import kd.bos.entity.datamodel.ListSelectedRowCollection;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.form.ShowType;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.operate.AbstractOperate;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.list.BillList;
+import kd.bos.list.ListShowParameter;
+import kd.bos.list.plugin.AbstractListPlugin;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.botp.BFTrackerServiceHelper;
+import kd.bos.servicehelper.workflow.WorkflowServiceHelper;
+import kd.fi.er.business.utils.ErEntityTypeUtils;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 外办申请,
+ */
+public class DailyVehicleCusListPlugin extends AbstractListPlugin {
+
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+        super.beforeDoOperation(args);
+        Object source = args.getSource();
+
+        String opKey = ((AbstractOperate)source).getOperateKey();
+        Set<Long> selectedDatas = (Set)args.getListSelectedData().stream().map((data) -> {
+            return (Long)data.getPrimaryKeyValue();
+        }).collect(Collectors.toSet());
+
+        String confirmTip;
+        switch (opKey) {
+            case "unaudit":
+                if (!this.checkBeforeTripChange(selectedDatas)) {
+                    args.setCancel(true);
+                    return;
+                }
+                break;
+            case "nckd_tripinvoke":
+                if (selectedDatas.size() > 1 || selectedDatas.size() == 0) {
+                    this.getView().showTipNotification(ResManager.loadKDString("仅支持对单条外办申请单进行撤销变更。", "TripReqBillList_7", "fi-er-formplugin", new Object[0]));
+                    args.setCancel(true);
+                } else {
+                    if (selectedDatas.size() == 1) {
+                        ListSelectedRow row = args.getListSelectedData().get(0);
+                        confirmTip = ((ListShowParameter)this.getView().getFormShowParameter()).getBillFormId();
+                        DynamicObject item = QueryServiceHelper.queryOne(confirmTip, "nckd_ischange,billstatus", new QFilter[]{new QFilter("id", "=", row.getPrimaryKeyValue())});
+                        if (!item.getBoolean("nckd_ischange")) {
+                            this.getView().showTipNotification(ResManager.loadKDString("不满足操作条件:只有进行过变更的单据才允许撤销变更。", "TripReqBillList_11", "fi-er-formplugin", new Object[0]));
+                            args.setCancel(true);
+                            return;
+                        }
+
+                        if (!item.getString("billstatus").equals("A")) {
+                            this.getView().showTipNotification(ResManager.loadKDString("操作条件不满足:只有单据状态为“暂存”的单据才可撤销变更。", "TripReqBillList_12", "fi-er-formplugin", new Object[0]));
+                            args.setCancel(true);
+                            return;
+                        }
+                    }
+                }
+        }
+
+    }
+
+    public void afterDoOperation(AfterDoOperationEventArgs e) {
+        super.afterDoOperation(e);
+        String opKey = e.getOperateKey();
+
+        if ("unaudit".equalsIgnoreCase(opKey)) {
+            ListSelectedRowCollection selectedRows = this.getSelectedRows();
+            Object selectId = selectedRows.get(0).getPrimaryKeyValue();
+
+            OperationResult operationResult = e.getOperationResult();
+            if (operationResult.isSuccess()) {
+                BillShowParameter formShowParameter = new BillShowParameter();
+                formShowParameter.getOpenStyle().setShowType(ShowType.MainNewTabPage);
+                formShowParameter.setFormId(((ListShowParameter)this.getView().getFormShowParameter()).getBillFormId());
+                formShowParameter.setBillStatus(BillOperationStatus.EDIT);
+                formShowParameter.setPkId(selectId);
+                this.getView().showForm(formShowParameter);
+            }
+        } else if ("nckd_tripinvoke".equalsIgnoreCase(opKey)) {
+            ListSelectedRowCollection selectedRows = this.getSelectedRows();
+            Object selectId = selectedRows.get(0).getPrimaryKeyValue();
+            int row = selectedRows.get(0).getRowKey();
+            Long workId = WorkflowServiceHelper.getProcessInstanceIdByBusinessKey(String.valueOf(selectId));
+            List<Long> approveres = WorkflowServiceHelper.getApproverByBusinessKey(String.valueOf(selectId));
+            if (workId != null && !workId.equals(0L) && !approveres.isEmpty()) {
+                WorkflowServiceHelper.abandon(workId);
+                BillList list = (BillList)this.getControl("billlistap");
+                list.refresh();
+            }
+
+            OperationResult result = e.getOperationResult();
+            if (result.isSuccess()) {
+                this.getView().showSuccessNotification(ResManager.loadKDString("行程已成功撤销。", "TripReqBillList_9", "fi-er-formplugin", new Object[0]));
+            } else {
+                this.getView().showTipNotification(ResManager.loadKDString("行程撤销失败。", "TripReqBillList_10", "fi-er-formplugin", new Object[0]));
+            }
+
+            BillList list = (BillList)this.getControl("billlistap");
+            list.refresh();
+        }
+    }
+
+
+    private boolean checkBeforeTripChange(Set<Long> selectedDatas) {
+        if (selectedDatas.size() > 1 || selectedDatas.size() == 0) {
+            this.getView().showTipNotification(ResManager.loadKDString("仅支持对单条外办申请单进行行程变更。", "TripReqBillList_13", "fi-er-formplugin", new Object[0]));
+            return false;
+        } else {
+            Long selectReqBillId = (Long)selectedDatas.stream().findFirst().get();
+            String entityName = ((ListShowParameter)this.getView().getFormShowParameter()).getBillFormId();
+            DynamicObject reqBill = QueryServiceHelper.queryOne(entityName, "billno,billstatus,isloan", new QFilter[]{new QFilter("id", "=", selectReqBillId)});
+            if (reqBill == null) {
+                this.getView().showErrorNotification(ResManager.loadKDString("数据库无法查询到数据,请刷新页面后尝试。", "TripAutoOpenedListPlugin_2", "fi-er-formplugin", new Object[0]));
+                return false;
+            } else if (!"E".equals(reqBill.get("billstatus")) ) {
+                this.getView().showTipNotification(ResManager.loadKDString("只有“审核通过”的外办申请才能进行行程变更。", "TripReqBillList_14", "fi-er-formplugin", new Object[0]));
+                return false;
+            } else {
+                Map<String, HashSet<Long>> targetBills = BFTrackerServiceHelper.findTargetBills(entityName, (Long[]) Collections.singleton(selectReqBillId).toArray(new Long[0]));
+                if (targetBills.isEmpty()) {
+                    return true;
+                } else {
+                    HashSet<Long> targetBillIds = (HashSet)targetBills.get("er_tripreimbursebill");
+                    if (targetBillIds != null && !targetBillIds.isEmpty()) {
+                        this.getView().showTipNotification(ResManager.loadKDString("所选的外办申请单存在已关联的差旅报销单,不允许变更行程。", "TripReqBillList_15", "fi-er-formplugin", new Object[0]));
+                        return false;
+                    } else {
+                        if (ErEntityTypeUtils.isTripReqBillInter(entityName)) {
+                            targetBillIds = (HashSet)targetBills.get("er_tripreimburse_cardgrid");
+                            if (targetBillIds != null && !targetBillIds.isEmpty()) {
+                                this.getView().showTipNotification(ResManager.loadKDString("所选的外办申请单存在已关联的差旅报销单,不允许变更行程。", "TripReqBillList_15", "fi-er-formplugin", new Object[0]));
+                                return false;
+                            }
+                        }
+
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+}

+ 148 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/DailyVehicleBillInvokeOpPlugin.java

@@ -0,0 +1,148 @@
+package nckd.jimin.jyyy.fi.plugin.operate;
+
+import kd.bos.dataentity.OperateOption;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.operate.result.OperateErrorInfo;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.exception.KDException;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.servicehelper.operation.OperationServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.fi.er.common.ErBillStatusEnum;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 外办申请,撤销变更
+ */
+public class DailyVehicleBillInvokeOpPlugin extends AbstractOperationServicePlugIn {
+    private static final Log logger = LogFactory.getLog(DailyVehicleBillInvokeOpPlugin.class);
+
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+
+        List<String> fieldKeys = e.getFieldKeys();
+
+        fieldKeys.add("billstatus");
+        fieldKeys.add("applier");
+        fieldKeys.add("startdate");
+        fieldKeys.add("enddate");
+        fieldKeys.add("nckd_ischange");
+        fieldKeys.add("vehiclecity");
+
+        fieldKeys.add("nckd_historyentry");
+        fieldKeys.add("nckd_historyentry.nckd_historystartdate");
+        fieldKeys.add("nckd_historyentry.nckd_historyenddate");
+        fieldKeys.add("nckd_historyentry.nckd_historycity");
+        fieldKeys.add("nckd_historyentry.nckd_changetime");
+    }
+
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        this.addDailyVehicleInvokeValidator(e);
+    }
+
+    public void endOperationTransaction(EndOperationTransactionArgs e) {
+        DynamicObject[] bills = e.getDataEntities();
+        if (bills.length > 0) {
+            this.doRevoke(bills);
+            SaveServiceHelper.save(bills);
+            Object[] ids = new Object[bills.length];
+
+            for(int index = 0; index < bills.length; ++index) {
+                ids[index] = bills[index].getPkValue();
+            }
+
+            OperateOption op = OperateOption.create();
+            op.setVariableValue("WF", String.valueOf(true));
+            OperationResult res = OperationServiceHelper.executeOperate("audit", "er_dailyvehiclebill", ids, op);
+
+            if (!res.isSuccess()) {
+                StringBuilder tips = this.buildErrorInfoBuilder(res);
+                throw new KDException(String.format(ResManager.loadKDString("行程撤销失败:%1$s", "TripEntryInfoRevokeOP_0", "fi-er-opplugin", new Object[0]), tips.toString()));
+            }
+        }
+    }
+
+    private StringBuilder buildErrorInfoBuilder(OperationResult res) {
+        StringBuilder tips = new StringBuilder();
+        if (null != res.getMessage()) {
+            tips.append(res.getMessage());
+        }
+
+        if (null != res.getAllErrorInfo() && res.getAllErrorInfo().size() > 0) {
+            List<OperateErrorInfo> list = res.getAllErrorInfo();
+            list.stream().forEach((p) -> {
+                tips.append(p.getMessage());
+            });
+        }
+
+        return tips;
+    }
+
+    private void doRevoke(DynamicObject[] bills) {
+        DynamicObject bill = bills[0];
+        DynamicObjectCollection historyEntities = bill.getDynamicObjectCollection("nckd_historyentry");
+
+        if (historyEntities.size() != 0) {
+            Optional<DynamicObject> optional = historyEntities.stream().max(Comparator.comparing((e) -> {
+                return e.getDate("nckd_changetime");
+            }));
+            Date maxDate;
+            if (optional.isPresent()) {
+                maxDate = new Date(((DynamicObject)optional.get()).getDate("nckd_changetime").getTime());
+            } else {
+                maxDate = new Date(((DynamicObject)historyEntities.get(0)).getDate("nckd_changetime").getTime());
+            }
+
+            List<DynamicObject> upToDates = (List)historyEntities.stream().filter((v) -> {
+                return v.getDate("nckd_changetime").compareTo(maxDate) == 0;
+            }).collect(Collectors.toList());
+
+            if(upToDates.size() > 0){
+                DynamicObject upToDate = upToDates.get(0);
+
+                bill.set("vehiclecity", upToDate.getDynamicObject("nckd_historycity"));
+                bill.set("startdate", upToDate.getDate("nckd_historystartdate"));
+                bill.set("enddate", upToDate.getDate("nckd_historyenddate"));
+            }
+            bill.set("billstatus", "B");
+
+            historyEntities.removeAll(upToDates);
+        }
+    }
+
+    protected void addDailyVehicleInvokeValidator(AddValidatorsEventArgs e) {
+        e.addValidator(new DailyVehicleInfoInvokeValiator());
+    }
+
+    private static class DailyVehicleInfoInvokeValiator extends AbstractValidator {
+        private DailyVehicleInfoInvokeValiator() {
+        }
+
+        public void validate() {
+            ExtendedDataEntity[] dataEntities = this.getDataEntities();
+            ExtendedDataEntity[] var2 = dataEntities;
+            int var3 = dataEntities.length;
+
+            for(int var4 = 0; var4 < var3; ++var4) {
+                ExtendedDataEntity dataEntity = var2[var4];
+                DynamicObject billObj = dataEntity.getDataEntity();
+
+                if (!billObj.getString("billstatus").equals(ErBillStatusEnum.A.name())) {
+                    this.addErrorMessage(dataEntity, ResManager.loadKDString("只有单据状态为“暂存”的单据才允许撤销变更。", "TripEntryInfoRevokeOP_1", "fi-er-opplugin", new Object[0]));
+                }
+
+            }
+
+        }
+    }
+}

+ 43 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/DailyVehicleBillSubmitOpPlugin.java

@@ -1,6 +1,7 @@
 package nckd.jimin.jyyy.fi.plugin.operate;
 
 import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.entity.ExtendedDataEntity;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
 import kd.bos.entity.plugin.AddValidatorsEventArgs;
@@ -12,6 +13,10 @@ import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
 import kd.bos.entity.validate.AbstractValidator;
 import kd.bos.logging.Log;
 import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
+import nckd.base.helper.CommonHelperUtils;
 import nckd.jimin.jyyy.fi.common.FinanceCommonUtils;
 
 import java.util.Date;
@@ -34,6 +39,7 @@ public class DailyVehicleBillSubmitOpPlugin extends AbstractOperationServicePlug
         fieldKeys.add("applier");
         fieldKeys.add("startdate");
         fieldKeys.add("enddate");
+        fieldKeys.add("nckd_ischange");
     }
 
     @Override
@@ -65,6 +71,43 @@ public class DailyVehicleBillSubmitOpPlugin extends AbstractOperationServicePlug
                     if(checkMsg.length() > 0) {
                         this.addErrorMessage(dataEntity, "存在开始时间、结束时间重叠的单据!" + checkMsg);
                     }
+
+                    //如果是变更行程,需要与变更前的做校验
+                    QFilter qFilter = new QFilter("id", QCP.equals, vehicleReqBillInfo.getLong("id"));
+
+                    String selectFields = "nckd_historyentry.nckd_historystartdate, nckd_historyentry.nckd_historyenddate, nckd_historyentry.nckd_changetime";
+
+                    DynamicObjectCollection historyEntities = QueryServiceHelper.query(vehicleReqBillInfo.getDataEntityType().getName(), selectFields, qFilter.toArray(), "nckd_historyentry.nckd_changetime desc");
+
+                    if (vehicleReqBillInfo.getBoolean("nckd_ischange") && historyEntities.size() > 0) {
+                        DynamicObject historyEntry = historyEntities.get(0);
+                        Date now = new Date();
+                        Date curStartDate = vehicleReqBillInfo.getDate("startdate");
+                        Date hisStartDate = historyEntry.getDate("nckd_historyentry.nckd_historystartdate");
+
+                        Date curEndDate = vehicleReqBillInfo.getDate("enddate");
+                        Date hisEndDate = historyEntry.getDate("nckd_historyentry.nckd_historyenddate");
+
+                        String nowString = CommonHelperUtils.getDateFormatString(now, "yyyy-MM-dd HH:mm:ss");
+                        String curStartDateString = CommonHelperUtils.getDateFormatString(curStartDate, "yyyy-MM-dd HH:mm:ss");
+                        String hisStartDateString = CommonHelperUtils.getDateFormatString(hisStartDate, "yyyy-MM-dd HH:mm:ss");
+                        String curEndDateString = CommonHelperUtils.getDateFormatString(curEndDate, "yyyy-MM-dd HH:mm:ss");
+                        String hisEndDateString = CommonHelperUtils.getDateFormatString(hisEndDate, "yyyy-MM-dd HH:mm:ss");
+
+                        if(hisStartDate.compareTo(now) > 0){
+                            if(curStartDate.compareTo(now) < 0){
+                                this.addErrorMessage(dataEntity, "出差前变更, 变更后的开始时间(" + curStartDateString + ")不能小于当前时间(" + nowString + ")");
+                            }
+                        } else {
+                            if(curStartDate.compareTo(hisStartDate) < 0){
+                                this.addErrorMessage(dataEntity, "出差后变更, 变更后的开始时间(" + curStartDateString + ")不能小于原开始时间(" + hisStartDateString + ")");
+                            }
+                        }
+
+                        if(curEndDate.compareTo(hisEndDate) > 0){
+                            this.addErrorMessage(dataEntity, "变更后的结束时间(" + curEndDateString + ")不能大于原结束时间(" + hisEndDateString + ")");
+                        }
+                    }
                 }
             }
         });

+ 113 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/DailyVehicleBillUnAuditOpPlugin.java

@@ -0,0 +1,113 @@
+package nckd.jimin.jyyy.fi.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.fi.er.common.ErBillStatusEnum;
+import java.util.*;
+
+/**
+ * 外办申请单,变更行程
+ */
+public class DailyVehicleBillUnAuditOpPlugin extends AbstractOperationServicePlugIn {
+    private static final Log logger = LogFactory.getLog(DailyVehicleBillUnAuditOpPlugin.class);
+
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+
+        List<String> fieldKeys = e.getFieldKeys();
+
+        fieldKeys.add("applier");
+        fieldKeys.add("startdate");
+        fieldKeys.add("enddate");
+        fieldKeys.add("nckd_ischange");
+        fieldKeys.add("vehiclecity");
+    }
+
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        this.addDailyVehicleChangeValidator(e);
+    }
+
+    public void endOperationTransaction(EndOperationTransactionArgs e) {
+        DynamicObject[] bills = e.getDataEntities();
+        if (bills.length > 0) {
+            this.billsEntryChange(bills);
+            SaveServiceHelper.save(bills);
+        }
+    }
+
+    protected void billsEntryChange(DynamicObject[] bills) {
+        DynamicObject[] var2 = bills;
+        int var3 = bills.length;
+
+        for(int var4 = 0; var4 < var3; ++var4) {
+            DynamicObject bill = var2[var4];
+            bill.set("nckd_ischange", Boolean.TRUE);
+
+            this.addTripEntryHistory(bill);
+        }
+    }
+
+    protected void addTripEntryHistory(DynamicObject bill) {
+        DynamicObjectCollection historyColl = bill.getDynamicObjectCollection("nckd_historyentry");
+        Date changeDate = new Date();
+        int seq = historyColl.size() + 1;
+
+        DynamicObject newHistory = historyColl.addNew();
+
+//        newHistory.set("seq", seq);
+        newHistory.set("nckd_changetime", changeDate);
+
+        Map<String, String> historyMapping = new HashMap();
+        historyMapping.put("nckd_historycity", "vehiclecity");
+        historyMapping.put("nckd_historystartdate", "startdate");
+        historyMapping.put("nckd_historyenddate", "enddate");
+
+
+        Iterator var10 = historyMapping.entrySet().iterator();
+        while(var10.hasNext()) {
+            Map.Entry<String, String> mappingEntry = (Map.Entry)var10.next();
+            String mappingKey = (String)mappingEntry.getKey();
+            String value = (String)mappingEntry.getValue();
+
+            newHistory.set(mappingKey, bill.get(value));
+        }
+    }
+
+    protected void addDailyVehicleChangeValidator(AddValidatorsEventArgs e) {
+        e.addValidator(new DailyVehicleInfoChangeValiator());
+    }
+
+    private static class DailyVehicleInfoChangeValiator extends AbstractValidator {
+        private DailyVehicleInfoChangeValiator() {
+        }
+
+        public void validate() {
+            ExtendedDataEntity[] dataEntities = this.getDataEntities();
+            ExtendedDataEntity[] var2 = dataEntities;
+            int var3 = dataEntities.length;
+
+            for(int var4 = 0; var4 < var3; ++var4) {
+                ExtendedDataEntity dataEntity = var2[var4];
+                DynamicObject billObj = dataEntity.getDataEntity();
+
+                if (!billObj.getString("billstatus").equals(ErBillStatusEnum.E.name())) {
+                    this.addErrorMessage(dataEntity, ResManager.loadKDString("只有审核通过的出差申请单才能变更。", "TripEntryInfoChangeOP_1", "fi-er-opplugin", new Object[0]));
+                }
+//                else if (billObj.getInt("reimbursetime") > 0) {
+//                    this.addErrorMessage(dataEntity, ResManager.loadKDString("出差申请单已经报销,不能变更。", "TripEntryInfoChangeOP_2", "fi-er-opplugin", new Object[0]));
+//                }
+            }
+
+        }
+    }
+}

+ 76 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/SyncReqBillToTripExtOpPlugin.java

@@ -0,0 +1,76 @@
+package nckd.jimin.jyyy.fi.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.metadata.IDataEntityType;
+import kd.bos.entity.BillEntityType;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.AfterOperationArgs;
+import kd.bos.entity.plugin.args.InitOperationArgs;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.fi.er.opplugin.trip.dailybiz.SyncReqBillToTripOp;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 同步商旅,继承标准的插件。
+ */
+public class SyncReqBillToTripExtOpPlugin extends SyncReqBillToTripOp {
+    private static final Log logger = LogFactory.getLog(SyncReqBillToTripExtOpPlugin.class);
+    private String key_entityNumber;
+    private String key_operateKey;
+
+    @Override
+    public void initialize(InitOperationArgs e) {
+        super.initialize(e);
+
+        IDataEntityType entityType = this.billEntityType;
+        BillEntityType mainType = null;
+        if (entityType instanceof BillEntityType) {
+            mainType = (BillEntityType)entityType;
+        }
+
+        if (mainType != null) {
+            this.key_entityNumber = mainType.getName();
+        }
+
+        Map<String, Object> opParameter = this.operateMeta;
+        if (opParameter != null && opParameter.get("key") != null) {
+            this.key_operateKey = (String)opParameter.get("key");
+        }
+
+        logger.info("商旅集成,申请单同步,业务单据是:" + this.key_entityNumber + ", 业务操作是:" + this.key_operateKey);
+    }
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+
+        List<String> fieldKeys = e.getFieldKeys();
+
+        switch (this.key_entityNumber) {
+            case "er_dailyvehiclebill":
+                fieldKeys.add("nckd_ischange");
+                break;
+        }
+    }
+
+    @Override
+    public void afterExecuteOperationTransaction(AfterOperationArgs e) {
+
+        if("er_dailyvehiclebill".equals(this.key_entityNumber)){
+            DynamicObject[] datas = e.getDataEntities();
+
+            for(int i = 0; i < datas.length; i++) {
+                DynamicObject dynamicObject = datas[i];
+
+                //如果是变更过的就不同步到商旅
+                if(!dynamicObject.getBoolean("nckd_ischange")) {
+                    super.afterExecuteOperationTransaction(e);
+                }
+            }
+        } else {
+            super.afterExecuteOperationTransaction(e);
+        }
+    }
+}

+ 9 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/TripReqBillSubmitOpPlugin.java

@@ -105,9 +105,14 @@ public class TripReqBillSubmitOpPlugin extends AbstractOperationServicePlugIn {
                             Date curStartDate = entry.getDate("startdate");
                             Date hisStartDate = historyEntry.getDate("tripchangehistoryentry.historystartdate");
 
+                            Date curEndDate = entry.getDate("enddate");
+                            Date hisEndDate = historyEntry.getDate("tripchangehistoryentry.historyenddate");
+
                             String nowString = CommonHelperUtils.getDateFormatString(now, "yyyy-MM-dd HH:mm:ss");
                             String curStartDateString = CommonHelperUtils.getDateFormatString(curStartDate, "yyyy-MM-dd HH:mm:ss");
                             String hisStartDateString = CommonHelperUtils.getDateFormatString(hisStartDate, "yyyy-MM-dd HH:mm:ss");
+                            String curEndDateString = CommonHelperUtils.getDateFormatString(curEndDate, "yyyy-MM-dd HH:mm:ss");
+                            String hisEndDateString = CommonHelperUtils.getDateFormatString(hisEndDate, "yyyy-MM-dd HH:mm:ss");
 
                             if(hisStartDate.compareTo(now) > 0){
                                 if(curStartDate.compareTo(now) < 0){
@@ -118,6 +123,10 @@ public class TripReqBillSubmitOpPlugin extends AbstractOperationServicePlugIn {
                                     this.addErrorMessage(dataEntity, "行程" + index + ", 出差后变更, 变更后的开始时间(" + curStartDateString + ")不能小于原开始时间(" + hisStartDateString + ")");
                                 }
                             }
+
+                            if(curEndDate.compareTo(hisEndDate) > 0){
+                                this.addErrorMessage(dataEntity, "行程" + index + ", 变更后的结束时间(" + curEndDateString + ")不能大于原结束时间(" + hisEndDateString + ")");
+                            }
                         }
                     }
                 }

+ 49 - 48
code/jyyy/nckd-jimin-jyyy-hr/src/main/java/nckd/jimin/jyyy/hr/haos/staff/plugin/form/PrepareAdjustApplicationFormPlugin.java

@@ -339,62 +339,63 @@ public class PrepareAdjustApplicationFormPlugin extends AbstractBillPlugIn imple
             String dateStr = sdf.format(date);
 
             // 拼接 SQL 查询
-            StringBuilder sql = new StringBuilder("SELECT a.fid AS id, a.fboid AS boid, A.fparentid as parentorg, "
-                    + "t.flevel as level1, t.fstructlongnumber as structlongnumber, ST.fcount as count,ST.fcontainsubcount as containsubcount, "
+            StringBuilder sql = new StringBuilder("SELECT a.fid AS id, a.fboid AS boid, A.fparentid as parentorg, \n"
+                    + "t.flevel as level1, t.fstructlongnumber as structlongnumber, ST.fcount as count,ST.fcontainsubcount as containsubcount, \n"
 //                    + "(select top 1 N.fstaffcount  from t_haos_adminorg M where a.fparentid = M.fboid ) as "
 //                    + " (select top 1 CASE WHEN N.fstaffcount IS NULL THEN 999999 ELSE N.fstaffcount END AS fstaffcount  "
 //                    + "from t_haos_adminorg M left join t_haos_dutyorgdetail N on N.fdutyorgid = M.fid "
 //                    + "where M.fenable ='1'  and M.fboid  =a.fboid and N.fenable = '1' and N.fleffdt >='" + dateStr + "' "
 //                    + "AND M.fbsed <= '" + dateStr + "' AND M.fbsled >= '" + dateStr + "'  "
 //                    + "order by M.fhisversion desc) as staffcount "
-                    + "CASE "
-                    + "    WHEN (SELECT TOP 1 CASE WHEN N.fstaffcount IS NULL THEN 999999 ELSE N.fstaffcount END "
-                    + "          FROM t_haos_adminorg M "
-                    + "          LEFT JOIN t_haos_dutyorgdetail N ON N.fdutyorgid = M.fid "
-                    + "          WHERE M.fenable = '1' "
-                    + "          AND M.fboid = a.fboid "
-                    + "          AND N.fenable = '1' "
-                    + "          AND N.fid = ?  "
-                    + "          AND N.fleffdt >= '" + dateStr + "' "
-                    + "          AND M.fbsed <= '" + dateStr + "' "
-                    + "          AND M.fbsled >= '" + dateStr + "' "
-                    + "          ORDER BY M.fhisversion DESC) IS NULL "
-                    + "    THEN 999999 "
-                    + "    ELSE (SELECT TOP 1 CASE WHEN N.fstaffcount IS NULL THEN 999999 ELSE N.fstaffcount END "
-                    + "          FROM t_haos_adminorg M "
-                    + "          LEFT JOIN t_haos_dutyorgdetail N ON N.fdutyorgid = M.fid "
-                    + "          WHERE M.fenable = '1' "
-                    + "          AND M.fboid = a.fboid "
-                    + "          AND N.fenable = '1' "
-                    + "          AND N.fid = ?  "
-                    + "          AND N.fleffdt >= '" + dateStr + "' "
-                    + "          AND M.fbsed <= '" + dateStr + "' "
-                    + "          AND M.fbsled >= '" + dateStr + "' "
-                    + "          ORDER BY M.fhisversion DESC) "
-                    + "END AS staffcount "
-
-                    + "FROM T_HAOS_ADMINORG A "
-                    + "LEFT JOIN T_HAOS_STAFFORGEMPCOUNT ST on A.fboid = ST.fuseorgboid "
-                    + "LEFT JOIN T_HAOS_ADMINSTRUCT T ON A.fboid = T.fadminorgid "
-                    + "AND T.fiscurrentversion = '0' AND T.fdatastatus = '1' AND T.fstructprojectid = 1010 "
-                    + "AND T.finitstatus = '2' AND T.fbsed <= '" + dateStr + "' "
-                    + "AND T.fbsled >= '" + dateStr + "' AND T.fenable = '1' "
-                    + "LEFT JOIN T_HAOS_ORGSORTCODE S ON S.FADMINORGID = A.fboid "
-                    + "AND S.fiscurrentversion = '0' AND S.fdatastatus = '1' AND S.finitstatus = '2' "
-                    + "AND S.fbsed <= '" + dateStr + "' AND S.fbsled >= '" + dateStr + "' "
-                    + "AND S.fenable = '1' "
-                    + "LEFT JOIN T_HAOS_DUTYORGDETAIL M ON M.fdutyorgid = A.fboid "
-                    + "WHERE A.fiscurrentversion = '0' AND A.fdatastatus = '1' AND A.finitstatus = '2' "
-                    + "AND A.fbsed <= '" + dateStr + "' AND A.fbsled >= '" + dateStr + "' "
-                    + "AND A.fenable = '1' "
-                    + "AND ( T.fstructlongnumber LIKE ( select top 1 concat(F.fstructlongnumber,'%')  from  T_HAOS_ADMINSTRUCT F where  F.fadminorgid = ? "
-                    + "AND F.fiscurrentversion = '0' AND F.fdatastatus = '1' AND F.fstructprojectid = 1010 "
-                    + "AND F.finitstatus = '2' AND F.fbsed <= '" + dateStr + "' "
-                    + "AND F.fbsled >= '" + dateStr + "' AND F.fenable = '1' "
-                    +") " +") "
+                    + "CASE \n"
+                    + "    WHEN (SELECT TOP 1 CASE WHEN N.fstaffcount IS NULL THEN 999999 ELSE N.fstaffcount END \n "
+                    + "          FROM t_haos_adminorg M \n"
+                    + "          LEFT JOIN t_haos_dutyorgdetail N ON N.fdutyorgid = M.fid \n"
+                    + "          WHERE M.fenable = '1' \n"
+                    + "          AND M.fboid = a.fboid \n"
+                    + "          AND N.fenable = '1' \n"
+                    + "          AND N.fid = ?  \n"
+                    + "          AND N.fleffdt >= '" + dateStr + "' \n"
+                    + "          AND M.fbsed <= '" + dateStr + "' \n"
+                    + "          AND M.fbsled >= '" + dateStr + "' \n"
+                    + "          ORDER BY M.fhisversion DESC) IS NULL \n"
+                    + "    THEN 999999 \n"
+                    + "    ELSE (SELECT TOP 1 CASE WHEN N.fstaffcount IS NULL THEN 999999 ELSE N.fstaffcount END \n"
+                    + "          FROM t_haos_adminorg M \n"
+                    + "          LEFT JOIN t_haos_dutyorgdetail N ON N.fdutyorgid = M.fid \n"
+                    + "          WHERE M.fenable = '1' \n"
+                    + "          AND M.fboid = a.fboid \n"
+                    + "          AND N.fenable = '1' \n"
+                    + "          AND N.fid = ?  \n"
+                    + "          AND N.fleffdt >= '" + dateStr + "' \n"
+                    + "          AND M.fbsed <= '" + dateStr + "' \n"
+                    + "          AND M.fbsled >= '" + dateStr + "' \n"
+                    + "          ORDER BY M.fhisversion DESC) \n"
+                    + "END AS staffcount \n"
+
+                    + "FROM T_HAOS_ADMINORG A \n"
+                    + "LEFT JOIN T_HAOS_STAFFORGEMPCOUNT ST on A.fboid = ST.fuseorgboid \n"
+                    + "LEFT JOIN T_HAOS_ADMINSTRUCT T ON A.fboid = T.fadminorgid \n"
+                    + "AND T.fiscurrentversion = '0' AND T.fdatastatus = '1' AND T.fstructprojectid = 1010 \n"
+                    + "AND T.finitstatus = '2' AND T.fbsed <= '" + dateStr + "' \n"
+                    + "AND T.fbsled >= '" + dateStr + "' AND T.fenable = '1' \n"
+                    + "LEFT JOIN T_HAOS_ORGSORTCODE S ON S.FADMINORGID = A.fboid \n"
+                    + "AND S.fiscurrentversion = '0' AND S.fdatastatus = '1' AND S.finitstatus = '2' \n"
+                    + "AND S.fbsed <= '" + dateStr + "' AND S.fbsled >= '" + dateStr + "' \n"
+                    + "AND S.fenable = '1' \n"
+                    + "LEFT JOIN T_HAOS_DUTYORGDETAIL M ON M.fdutyorgid = A.fboid \n"
+                    + "WHERE A.fiscurrentversion = '0' AND A.fdatastatus = '1' AND A.finitstatus = '2' \n"
+                    + "AND A.fbsed <= '" + dateStr + "' AND A.fbsled >= '" + dateStr + "' \n"
+                    + "AND A.fenable = '1' \n"
+                    + "AND ( T.fstructlongnumber LIKE ( select top 1 concat(F.fstructlongnumber,'%')  from  T_HAOS_ADMINSTRUCT F where  F.fadminorgid = ? \n"
+                    + "AND A.fboid in (select fuseorgboid from t_haos_useorgdetail where fid = ? \n)"
+                    + "AND F.fiscurrentversion = '0' AND F.fdatastatus = '1' AND F.fstructprojectid = 1010 \n"
+                    + "AND F.finitstatus = '2' AND F.fbsed <= '" + dateStr + "' \n"
+                    + "AND F.fbsled >= '" + dateStr + "' AND F.fenable = '1' \n"
+                    +") " +") \n"
                     + "ORDER BY S.fsortcode");
 //            Object[] param = new Object[]{(Long) orgid,haosStaff.getPkValue()};
-            Object[] param = new Object[]{pkValue,pkValue,(Long) orgid};
+            Object[] param = new Object[]{pkValue,pkValue,(Long) orgid, pkValue};
             DataSet dataSet = HRDBUtil.queryDataSet("haos_adminOrgHisSearch", new DBRoute("hr"), sql.toString(), param);
 //            DataSet dataSet = DB.queryDataSet("leaseContractPushCard", DBRoute.of("hr"), sql);
 

+ 47 - 4
code/jyyy/nckd-jimin-jyyy-hr/src/main/java/nckd/jimin/jyyy/hr/wtc/wtis/util/SyncPunchCardHelper.java

@@ -2,8 +2,10 @@ package nckd.jimin.jyyy.hr.wtc.wtis.util;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.kingdee.util.StringUtils;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.utils.ObjectUtils;
 import kd.bos.exception.ErrorCode;
 import kd.bos.exception.KDBizException;
 import kd.bos.logging.Log;
@@ -23,6 +25,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class SyncPunchCardHelper {
 
@@ -37,15 +40,37 @@ public class SyncPunchCardHelper {
     public static void savePunchCardData(JSONArray resultArr, Map openMap) {
         //批次编码
         String batchNumber = String.valueOf(System.currentTimeMillis());
-        List<DynamicObject> saveList = resultArr.stream().map((data) -> {
+        //2025-06-09 如果invalidRecordType有值则为无效卡
+        logger.info("钉钉返回信息过滤前条数:{}", resultArr.size());
+        JSONArray actualArr = resultArr.stream().filter(obj -> StringUtils.isEmpty(((JSONObject) obj).getString("invalidRecordType")))
+                .collect(Collectors.toCollection(JSONArray::new));
+        logger.info("钉钉返回信息过滤后条数:{}", actualArr.size());
+        //如果过滤后size == 0直接返回
+        if(actualArr.size() == 0) {
+            String msg = "钉钉返回条数:" + resultArr.size() + "条,有效卡:" + actualArr.size() + "条";
+            DingTalkSyncUtil.createLog(DingTalkSyncUtil.v_success, msg, resultArr.toJSONString(), DingTalkSyncUtil.SyncPunch);
+            return;
+        }
+        List<DynamicObject> saveList = actualArr.stream().map((data) -> {
             return dealPunchCardData((JSONObject) data, openMap, batchNumber);
         }).collect(Collectors.toList());
-        PUNCH_CARD_HELPER.save((DynamicObject[])saveList.toArray(new DynamicObject[0]));
+        logger.info("钉钉待保存过滤重复前条数:{}", saveList.size());
+        //过滤下为空的
+        List<DynamicObject> actualSaveList = saveList.stream().filter(dyo -> !ObjectUtils.isEmpty(dyo)).collect(Collectors.toList());
+        logger.info("钉钉待保存过滤重复后条数:{}", actualSaveList.size());
+        if(actualSaveList.size() == 0) {
+            String msg = "钉钉返回条数:" + resultArr.size() + "条," + "有效卡:" + actualArr.size() + "条,重复:" + (saveList.size()-actualSaveList.size()) + "条";
+            DingTalkSyncUtil.createLog(DingTalkSyncUtil.v_success, msg, resultArr.toJSONString(), DingTalkSyncUtil.SyncPunch);
+            return;
+        }
+        String msg = "钉钉返回条数:" + resultArr.size() + "条," + "有效卡:" + actualArr.size() + "条,重复:" + (saveList.size()-actualSaveList.size()) + "条";
+        DingTalkSyncUtil.createLog(DingTalkSyncUtil.v_success, msg, resultArr.toJSONString(), DingTalkSyncUtil.SyncPunch);
+        PUNCH_CARD_HELPER.save((DynamicObject[])actualSaveList.toArray(new DynamicObject[0]));
 
         try {
             long l1 = System.currentTimeMillis();
             PunchCardSyncSupport.execute(() -> {
-                syncCardRecord(resultArr,batchNumber);
+                syncCardRecord(actualArr,batchNumber);
             });
             long l2 = System.currentTimeMillis();
             logger.info("SyncPunchCardHelper_sync_cardData_{}", l2 - l1);
@@ -66,6 +91,11 @@ public class SyncPunchCardHelper {
         DynamicObject dyo = PUNCH_CARD_HELPER.generateEmptyDynamicObject();
         dyo.set("batchnumber", batchNumber);
         String card = openMap.get(data.getString("userId")).toString();
+        String id = data.getString("id");
+        //如果存在记录直接返回
+        if(checkCardIsExists(card, id)) {
+            return null;
+        }
         dyo.set("number", card);
         dyo.set("card", card);
         //实际打卡时间
@@ -90,7 +120,7 @@ public class SyncPunchCardHelper {
         dyo.set("equipment", "钉钉同步");
         dyo.set("equipnumber", "1020_S");
         // dataId
-        dyo.set("dataid", data.getString("id"));
+        dyo.set("dataid", id);
 
         //默认值
         dyo.set("times", 0);
@@ -124,6 +154,19 @@ public class SyncPunchCardHelper {
     }
 
 
+    /**
+     * 根据考勤卡号和钉钉返回ID判断是否存在记录
+     * @param card
+     * @param id
+     */
+    public static boolean checkCardIsExists(String card, String id) {
+        QFilter filter = new QFilter("card", QCP.equals, card);
+        filter.and("dataid", QCP.equals, id);
+        return QueryServiceHelper.exists("wtis_punchcarddata", new QFilter[]{filter});
+    }
+
+
+
     /**
      * 时间戳转yyyy-MM-dd
      * @param unix