فهرست منبع

feat(wtc): 新增休假申请单关键岗位校验功能

- 新增 `VaApplyCheckOrgRangeOpPlugin` 插件用于工作流中校验行政组织范围
- 实现 `VaApplyCheckValidator` 校验器,检查关键岗位人员请假冲突
- 在 `WtcConstant` 中新增角色编码常量 `WTCROLE_NUMBER`
- 扩展 `WTCHelper` 工具类,增加获取工作流角色、休假单信息及相关查询方法
- 更新 `WtcUtils` 工具类,替换组织查询服务并新增日期格式化方法
Tyx 3 ساعت پیش
والد
کامیت
db5e1687e1

+ 122 - 16
code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/wtc/helper/WTCHelper.java

@@ -6,13 +6,13 @@ 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 kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
 import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
+import java.math.BigDecimal;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -25,19 +25,9 @@ public class WTCHelper {
     public static final HRBaseServiceHelper HOLIDAYFOROT_HELPER = new HRBaseServiceHelper("nckd_holidayforot");
     public static final HRBaseServiceHelper OTBILL_HELPER = new HRBaseServiceHelper("wtom_overtimeapplybill");
     public static final HRBaseServiceHelper OTTYPE_HELPER = new HRBaseServiceHelper("wtbd_ottype");
-    /**
-     * 根据组织ID列表获取关键岗位信息
-     * @param orgIds 组织ID列表
-     * @return
-     */
-    public static List<Long> getKeyPositionByOrg (List<Long> orgIds) {
-        QFilter filter = new QFilter("nckd_iskeypos", QCP.equals, "1");
-        filter.and(QFilterCommonHelper.getCurrentVersionFilter());
-        filter.and("adminorg.id", QCP.in, orgIds);
-        HRBaseServiceHelper helper = new HRBaseServiceHelper(FormConstant.HBPM_POSITIONHR);
-        DynamicObjectCollection positions = helper.queryOriginalCollection("id", filter.toArray());
-        return positions.stream().map(position -> position.getLong("id")).collect(Collectors.toList());
-    }
+    /* 工作流角色 */
+    public static final HRBaseServiceHelper WFROLE_HELPER = new HRBaseServiceHelper("wf_role");
+    public static final HRBaseServiceHelper VAAPPLY_HELPER = new HRBaseServiceHelper("wtabm_vaapply");
 
     /**
      * 根据考勤档案ID获取二级单位编码
@@ -91,5 +81,121 @@ public class WTCHelper {
         return OTTYPE_HELPER.loadOne(filter.toArray());
     }
 
+    /**
+     * 根据角色编码+用户ID获取工作流角色信息
+     *
+     * @param roleNumber
+     * @param userId
+     * @return
+     */
+    public static DynamicObject getWFRoleByUserId (String roleNumber, long userId) {
+        QFilter filter = new QFilter("number", QCP.equals, roleNumber);
+        filter.and("roleentry.user.id", QCP.equals, userId);
+        return WFROLE_HELPER.queryOriginalOne("roleentry.org.id, roleentry.includadminsub", filter.toArray());
+    }
+
+
+    /**
+     * 根据组织ID列表获取关键岗位信息
+     * @param orgIds 组织ID列表
+     * @return
+     */
+    public static List<Long> getKeyPositionByOrg (List<Long> orgIds) {
+        QFilter filter = new QFilter("nckd_iskeypos", QCP.equals, "1");
+        filter.and(QFilterCommonHelper.getCurrentVersionFilter());
+        filter.and("adminorg.id", QCP.in, orgIds);
+        HRBaseServiceHelper helper = new HRBaseServiceHelper(FormConstant.HBPM_POSITIONHR);
+        DynamicObjectCollection positions = helper.queryOriginalCollection("id", filter.toArray());
+        return positions.stream().map(position -> position.getLong("id")).collect(Collectors.toList());
+    }
+
+
+    /**
+     * 获取休假单信息
+     *
+     * @param positionIds
+     * @param startDate
+     * @param endDate
+     * @param billId
+     * @return
+     */
+    public static DynamicObjectCollection getVaApplyInfo (List<Long> positionIds, Date startDate, Date endDate, Long billId) {
+        QFilter filter = getVaApplyFilter(positionIds, startDate, endDate, billId);
+        String selectFields = getVaApplySelectFields();
+        DynamicObjectCollection cols = VAAPPLY_HELPER.queryOriginalCollection(selectFields, filter.toArray());
+        return cols;
+    }
+
+
+    /**
+     * 获取休假单过滤条件
+     *
+     * @param positionIds
+     * @param startDate
+     * @param endDate
+     * @param billId
+     * @return
+     */
+    public static QFilter getVaApplyFilter (List<Long> positionIds, Date startDate, Date endDate, Long billId) {
+        QFilter filter = new QFilter("attfile.position.id", QCP.in, positionIds);
+        filter.and("applytime", QCP.large_than, BigDecimal.ZERO);
+        filter.and("billstatus", QCP.in,  new HashSet<>(Arrays.asList("B", "C", "D")));
+        filter.and("id", QCP.not_equals, billId);
+
+        String startField = "startdate";
+        String endField = "enddate";
+        QFilter startFilter = new QFilter(startField, QCP.less_equals, startDate);
+        startFilter.and(new QFilter(endField, QCP.large_equals, startDate));
+
+        QFilter endFilter = new QFilter(startField, QCP.less_equals, endDate);
+        endFilter.and(new QFilter(endField, QCP.large_equals, endDate));
+
+        QFilter startFilter1 = new QFilter( startField, QCP.large_equals, startDate);
+        startFilter1.and(new QFilter(startField, QCP.less_than, endDate));
+
+        QFilter endFilter1 = new QFilter(endField, QCP.large_equals, startDate);
+        endFilter1.and(new QFilter( endField, QCP.less_than, endDate));
+
+        filter.and(startFilter.or(endFilter).or(startFilter1).or(endFilter1));
+
+        return filter;
+    }
+
+    /**
+     * 获取休假单查询字段
+     * @return
+     */
+    public static String getVaApplySelectFields() {
+        String selectFields = "billno, attfile.empnumber, attfile.employee.name, attfile.adminorg.name, attfile.position.name, startdate, enddate";
+        return selectFields;
+    }
+
+
+    /**
+     * 根据用户ID查询员工ID
+     * @param userId
+     * @return
+     */
+    public static Long queryEmployeeIdByUserId(Long userId) {
+        HRBaseServiceHelper SERVICE_HELPER = new HRBaseServiceHelper("hrpi_personuserrel");
+        DynamicObject personuserrel = SERVICE_HELPER.queryOne("employee,user,createtime", new QFilter[]{new QFilter("user", "=", userId), new QFilter("enable", "=", "1")}, "createtime desc");
+        return personuserrel == null ? 0L : personuserrel.getLong("employee_id");
+    }
+
+    /**
+     * 根据employeeId查询任职经历
+     * @param employeeId
+     * @return
+     */
+    public static DynamicObjectCollection queryEmpPosOrgRelDyns (List<Long> employeeId) {
+        QFilter filter = new QFilter("iscurrentdata", QCP.equals, "1"); // 启用
+        filter.and(new QFilter("employee.id", QCP.in, employeeId));
+
+        String selectFields1 = "adminorg.id";
+        DynamicObjectCollection empposorgreDyns = QueryServiceHelper.query("hrpi_empposorgrel", selectFields1, filter.toArray());
+
+        return empposorgreDyns;
+    }
+
 
 }

+ 2 - 0
code/wtc/nckd-jxccl-wtc/src/main/java/nckd/jxccl/wtc/wtabm/web/common/constant/WtcConstant.java

@@ -56,4 +56,6 @@ public class WtcConstant {
     public static final HRBaseServiceHelper HOLIDAYFOROT_HELPER = new HRBaseServiceHelper("nckd_holidayforot");
     /* 加班类型-休息日加班 */
     public static String OTTYPE_1020S = "1020_S";
+    /* 休假单用角色编码 */
+    public static String WTCROLE_NUMBER = "wtc_role";
 }

+ 13 - 2
code/wtc/nckd-jxccl-wtc/src/main/java/nckd/jxccl/wtc/wtabm/web/common/util/WtcUtils.java

@@ -11,11 +11,12 @@ import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
-import kd.hr.haos.business.domain.adminorg.service.impl.AdminOrgQueryServiceHelper;
 import kd.hr.hbp.common.util.HRDateTimeUtils;
 import kd.hr.hbp.common.util.HRStringUtils;
+import kd.sdk.hr.haos.business.helper.HAOSServiceHelper;
 import org.apache.commons.lang3.ObjectUtils;
 
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.util.*;
@@ -103,7 +104,7 @@ public class WtcUtils {
     public static Set getSubOrgFilters (DynamicObject adminOrgDyn, String field) {
         List<Long> adminOrgList = new ArrayList<Long>();
         adminOrgList.add(adminOrgDyn.getLong("id"));
-        List<Map<String, Object>> subOrgs = AdminOrgQueryServiceHelper.batchQuerySubOrg(adminOrgList, new Date(), null);
+        List<Map<String, Object>> subOrgs = HAOSServiceHelper.querySubOrgToList(adminOrgList, new Date(), null);
         Set subOrgIdset = subOrgs.stream().map(i -> i.get("orgId")).collect(Collectors.toSet());
         return subOrgIdset;
     }
@@ -132,5 +133,15 @@ public class WtcUtils {
         }
     }
 
+    /**
+     * 日期转yyyy-MM-dd
+     * @param date
+     * @return
+     */
+    public static String dateToStr(Date date, String pattern) {
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        return sdf.format(date);
+    }
+
 
 }

+ 34 - 0
code/wtc/nckd-jxccl-wtc/src/main/java/nckd/jxccl/wtc/wtabm/web/vaapply/VaApplyCheckOrgRangeOpPlugin.java

@@ -0,0 +1,34 @@
+package nckd.jxccl.wtc.wtabm.web.vaapply;
+
+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.BeforeOperationArgs;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.wtc.wtabm.web.validate.VaApplyCheckValidator;
+
+/**
+ * Tyx 2025-12-03
+ * 休假申请单校验行政组织范围操作-工作流用
+ * 校验当前审批人
+ */
+public class VaApplyCheckOrgRangeOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+    }
+
+    @Override
+    public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
+        super.beforeExecuteOperationTransaction(e);
+    }
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+        e.getValidators().add(new VaApplyCheckValidator());
+    }
+}

+ 107 - 0
code/wtc/nckd-jxccl-wtc/src/main/java/nckd/jxccl/wtc/wtabm/web/validate/VaApplyCheckValidator.java

@@ -0,0 +1,107 @@
+package nckd.jxccl.wtc.wtabm.web.validate;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.entity.validate.ErrorLevel;
+import kd.sdk.hr.haos.business.helper.HAOSServiceHelper;
+import nckd.jxccl.base.wtc.helper.WTCHelper;
+import nckd.jxccl.wtc.wtabm.web.common.constant.WtcConstant;
+import nckd.jxccl.wtc.wtabm.web.common.util.WtcUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class VaApplyCheckValidator extends AbstractValidator {
+
+    /**
+     * 休假申请单校验行政组织范围内是否存在关键岗位同时请假-工作流用
+     */
+    @Override
+    public void validate() {
+        // 操作标识 checkbyrole:根据工作流角色判断,checkbypar:根据直接上级判断
+        String operateKey = this.getOperateKey();
+        for (ExtendedDataEntity dataEntity : dataEntities) {
+            DynamicObject bill = dataEntity.getDataEntity();
+            // 当前用户ID
+            long userId = RequestContext.getOrCreate().getCurrUserId();
+            List<Long> allOrgIds = new ArrayList<Long>();
+            List<Long> positionIds = new ArrayList<Long>();
+            Date startDate = bill.getDate("startdate");
+            Date endDate = bill.getDate("enddate");
+
+            getKetPositionIds(operateKey, allOrgIds, positionIds, userId);
+
+            if(positionIds.size() > 0) {
+                // 根据关键岗位 + 日期范围 获取休假单信息
+                DynamicObjectCollection applyDyns = WTCHelper.getVaApplyInfo(positionIds, startDate, endDate, bill.getLong("id"));
+                if (applyDyns.size() > 0) {
+                    List<String> msgList = new ArrayList<String>();
+                    StringBuilder sb = new StringBuilder();
+                    int i = 1;
+                    for (DynamicObject applyBill : applyDyns) {
+                        String billNo = applyBill.getString("billno");
+                        String empName = applyBill.getString("attfile.employee.name");
+                        String orgName = applyBill.getString("attfile.adminorg.name");
+                        String posName = applyBill.getString("attfile.position.name");
+                        String startDateStr = WtcUtils.dateToStr(applyBill.getDate("startdate"), "yyyy-MM-dd");
+                        String endDateStr = WtcUtils.dateToStr(applyBill.getDate("enddate"), "yyyy-MM-dd");
+                        String msg = String.format(i + "、【%s】-【%s】-【%s】-【%s】-【%s】-【%s】", billNo, empName, orgName, posName, startDateStr, endDateStr);
+                        msgList.add(msg);
+                    }
+                    String titleMsg = "以下单据存在其他关键岗位人员正在休假:\n ";
+                    String errorMsg = titleMsg + String.join("\n ", msgList);
+                    this.addWarningMessage(dataEntity, errorMsg);
+                }
+            }
+        }
+    }
+
+    /**
+     * 获取关键岗位ID
+     * @param operateKey
+     * @param allOrgIds
+     * @param positionIds
+     * @param userId
+     */
+    public void getKetPositionIds (String operateKey, List<Long> allOrgIds, List<Long> positionIds, Long userId) {
+        // 根据工作流角色判断
+        if("checkbyrole".equals(operateKey)) {
+            // 获取工作流角色中的组织
+            DynamicObject role = WTCHelper.getWFRoleByUserId(WtcConstant.WTCROLE_NUMBER, userId);
+            if (role != null) {
+                List<Long> orgIds = new ArrayList<Long>();
+                orgIds.add(role.getLong("roleentry.org.id"));
+                // 根据工作流角色中维护的组织获取所有组织ID
+                // 如果是包含下级的情况 查询所有的下级组织
+                if (role.getBoolean("roleentry.includadminsub")) {
+                    List<Map<String, Object>> subOrgMap = HAOSServiceHelper.querySubOrgToList(orgIds, new Date(), null);
+                    allOrgIds.addAll(subOrgMap.stream().map(i -> Long.valueOf(i.get("orgId").toString())).collect(Collectors.toList()));
+                }
+                // 不包含下级
+                else {
+                    allOrgIds.add(role.getLong("roleentry.org.id"));
+                }
+            }
+        }
+        // 根据直接上级判断
+        else if ("checkbypar".equals(operateKey)) {
+            // 获取当前用户对应的employeeId
+            Long employeeId = WTCHelper.queryEmployeeIdByUserId(userId);
+            // 获取员工当前的行政组织
+            DynamicObjectCollection empPosOrgRelDyns = WTCHelper.queryEmpPosOrgRelDyns(Arrays.asList(employeeId));
+            List<Long> orgIds = new ArrayList<Long>();
+            orgIds.addAll(empPosOrgRelDyns.stream().map(i -> i.getLong("adminorg.id")).collect(Collectors.toList()));
+            List<Map<String, Object>> subOrgMap = HAOSServiceHelper.querySubOrgToList(orgIds, new Date(), null);
+            allOrgIds.addAll(subOrgMap.stream().map(i -> Long.valueOf(i.get("orgId").toString())).collect(Collectors.toList()));
+        }
+
+        // 获取组织范围内的关键岗位
+        positionIds.addAll(WTCHelper.getKeyPositionByOrg(allOrgIds));
+
+    }
+
+
+}