Sfoglia il codice sorgente

feat(hr): 新增员工职位档案保存时自动计算岗位津贴功能

- 在员工职位档案保存操作中增加岗位津贴自动计算逻辑
- 根据职位系数与所在岗级岗位工资一档金额计算岗位津贴
- 引入AdjFileServiceHelper工具类获取员工最新定调薪记录
- 通过薪酬标准表匹配获取岗位工资一档金额
- 实现职位系数、当前岗位工资、岗位津贴字段的自动填充
- 添加相关常量定义用于支持新功能实现
- 移除重复的岗位工资标准ID硬编码值,统一引用常量
- 增加日志记录以便于问题排查和监控
wyc 2 giorni fa
parent
commit
91c3526bfd

+ 4 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java

@@ -436,4 +436,8 @@ public class FormConstant {
     /** 别名 */
     public static final String NCKD_ISPARTICIPATE = "nckd_isparticipate";
 
+
+    /** 岗位工资标准(jt002)*/
+    public static final Long STANDARDITEM_ID_KEY = 2321899710350111744L;
+
 }

+ 143 - 0
code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/swc/helper/AdjFileServiceHelper.java

@@ -0,0 +1,143 @@
+package nckd.jxccl.base.swc.helper;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.validate.BillStatus;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.servicehelper.DispatchServiceHelper;
+import kd.sdk.swc.hcdm.business.helper.HCDMAdjFileServiceHelper;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.base.entity.helper.EntityHelper;
+import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 定调薪帮助类
+ *
+ * @author W.Y.C
+ * @version 1.0
+ * @date 2025/12/21 16:02
+ */
+public class AdjFileServiceHelper {
+
+    protected final static Log logger = LogFactory.getLog(AdjFileServiceHelper.class);
+
+    /**
+     * 获取员工某个薪酬项目最新定调薪记录
+     * @param personIds 人员id
+     * @param standardItemId 定调薪项目id
+     * @return: java.util.List<nckd.jxccl.base.swc.helper.AdjFileServiceHelper.SalaryAdjustmentResult>
+     * @author W.Y.C
+     * @date: 2025/12/21 16:06
+     */
+    public static List<SalaryAdjustmentResult> getLastDecAdjRecords(List<Long> personIds,Long standardItemId) {
+        //获取员工最新任职
+        Map<Long, DynamicObject> empPosOrgRelByEmployeesMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
+        List<Long> allEmpPosOrgRelIds = empPosOrgRelByEmployeesMap.values().stream()
+                .map(result -> result.getLong(FormConstant.ID_KEY))
+                .collect(Collectors.toList());
+
+        List<SalaryAdjustmentResult> salaryAdjustmentResultList = new ArrayList<>();
+
+        DynamicObject standardItem = EntityHelper.newEntity(FormConstant.HSBS_STANDARDITEM);
+        standardItem.set(FormConstant.ID_KEY, standardItemId);
+        Map<String, Object> adjFileParams = new HashMap<>();
+        adjFileParams.put("employees", personIds);
+        List<String> status = new ArrayList<>();
+        status.add(BillStatus.C.toString());
+        adjFileParams.put("status", status);
+        //获取人员定薪档案
+        Map<String, Object> adjFileResult = DispatchServiceHelper.invokeBizService("swc", "hcdm", "IAdjFileInfoService", "queryAdjFileBoByEmp", adjFileParams);
+        if (ConvertUtil.toBoolean(adjFileResult.get("success"))) {
+            List<Map> list = ConvertUtil.toList(adjFileResult.get("data"), ArrayList::new);
+            List<Long> adjFileIds = new ArrayList<>();
+            for (Map map : list) {
+                Long id = ConvertUtil.toLong(map.get(FormConstant.ID_KEY));
+                //根据员工任职匹配
+                Long empPosOrgRelId = ConvertUtil.toLong(map.get("empposorgrel_id"));
+                if (allEmpPosOrgRelIds.contains(empPosOrgRelId)) {
+                    adjFileIds.add(id);
+                }
+            }
+            //构建定调薪记录查询条件
+            Map<String, Object> adjRecordParams = new HashMap<>();
+            List<Map<String, Object>> dataList = new ArrayList<>();
+            for (Long adjFileId : adjFileIds) {
+                Map<String, Object> dataItem = new HashMap<>();
+                // 调薪档案ID
+                dataItem.put("adjfile", adjFileId);
+                // 调薪项目ID
+                dataItem.put("standarditem", standardItemId);
+                // 查询基准日期
+                dataItem.put("startdate", new Date());
+                // 唯一标识
+                dataItem.put("_uniquecode", "unique" + adjFileId);
+                dataList.add(dataItem);
+            }
+            adjRecordParams.put("data", dataList);
+            adjRecordParams.put("selprops", "salarystdv.rankentry.rank.id,salarystdv.rankentry.rank.name,salarystdv.rankentry.rank.number,salarystdv.rankentry.rank.index,salarystdv.rankentry.frankindex,company.id,company.name,");
+            //查询定调薪记录
+            Map<String, Object> lastDecAdjRecordMap = HCDMAdjFileServiceHelper.getLastDecAdjRecords(adjRecordParams);
+            if (ConvertUtil.toBoolean(lastDecAdjRecordMap.get("success"))) {
+                List<Map> datas = ConvertUtil.toList(lastDecAdjRecordMap.get("data"), ArrayList::new);
+                for (Map data : datas) {
+                    if (ConvertUtil.toBoolean(data.get("success"))) {
+                        List<DynamicObject> adjRecordList = ConvertUtil.toList(data.get("data"), ArrayList::new);
+                        for (DynamicObject dynamicObject : adjRecordList) {
+                            // 人员
+                            DynamicObject employee = dynamicObject.getDynamicObject("adjfile").getDynamicObject("employee");
+                            SalaryAdjustmentResult salaryAdjustmentResult = new SalaryAdjustmentResult();
+                            //薪酬标准表版本
+                            DynamicObject salaryStDv = dynamicObject.getDynamicObject("salarystdv");
+                            //薪等(01岗、02岗)
+                            DynamicObject salaryGrade = dynamicObject.getDynamicObject("salarygrade");
+                            //薪档(1档、2档)
+                            DynamicObject salaryRank = dynamicObject.getDynamicObject("salaryrank");
+                            //金额
+                            BigDecimal amount = dynamicObject.getBigDecimal("amount");
+                            salaryAdjustmentResult.employee = employee;
+                            salaryAdjustmentResult.adjFileInfo = dynamicObject.getDynamicObject("adjfile");
+                            salaryAdjustmentResult.salaryStDv = salaryStDv;
+                            salaryAdjustmentResult.standardItem = standardItem;
+                            salaryAdjustmentResult.salaryGrade = salaryGrade;
+                            salaryAdjustmentResult.salaryRank = salaryRank;
+                            salaryAdjustmentResult.amount = amount;
+                            salaryAdjustmentResultList.add(salaryAdjustmentResult);
+                        }
+                    }
+                }
+            } else {
+                logger.error("查询定调薪记录失败");
+            }
+        } else {
+            logger.error("获取人员定薪档案失败");
+        }
+        return salaryAdjustmentResultList;
+    }
+
+
+    public static class SalaryAdjustmentResult {
+        /** 人员ID*/
+        public DynamicObject employee;
+        /**定调薪档案*/
+        public DynamicObject adjFileInfo;
+        /**薪酬标准表*/
+        public DynamicObject salaryStDv;
+        /** 定调薪项目 */
+        public DynamicObject standardItem;
+        /** 薪等(01岗、02岗)*/
+        public DynamicObject salaryGrade;
+        /** 薪档(1档、2档)*/
+        public DynamicObject salaryRank;
+        //金额
+        public BigDecimal amount;
+    }
+}

+ 8 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/PositionStructureConstant.java

@@ -121,6 +121,14 @@ public class PositionStructureConstant extends FormConstant {
     public static final String NCKD_LEVELKEEPREASON = "nckd_levelkeepreason";
     /** 锁定时间*/
     public static final String POSITIONAPPOINTMENTQUERY = "positionappointmentquery";
+
+    /** 系数 */
+    public static final String NCKD_COEFFICIENT = "nckd_coefficient";
+    /** 当前岗位工资 */
+    public static final String NCKD_CURRENTPOSTSALARY = "nckd_currentpostsalary";
+    /** 岗位津贴 */
+    public static final String NCKD_POSTALLOWANCE = "nckd_postallowance";
+
     /*-------------------------------------- 员工职位档案 end --------------------------------------*/
 
 

+ 124 - 11
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/file/PersonPosFileSaveOpPlugin.java

@@ -3,34 +3,34 @@ package nckd.jxccl.hr.psms.plugin.operate.file;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.entity.EntityMetadataCache;
-import kd.bos.entity.ExtendedDataEntity;
 import kd.bos.entity.MainEntityType;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
-import kd.bos.entity.plugin.AddValidatorsEventArgs;
-import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
-import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+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.BusinessDataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
 import kd.sdk.plugin.Plugin;
+import kd.sdk.swc.hcdm.business.helper.HCDMSalaryStdServiceHelper;
+import kd.sdk.swc.hcdm.common.dto.stdtab.match.StdTableDataMatchParam;
+import kd.sdk.swc.hcdm.common.dto.stdtab.match.StdTableDataMatchResult;
 import nckd.jxccl.base.common.constant.FormConstant;
-import nckd.jxccl.base.common.enums.psms.TypeStateEnum;
-import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
-import nckd.jxccl.base.common.utils.StrFormatter;
-import nckd.jxccl.base.org.helper.OrgHelper;
+import nckd.jxccl.base.swc.helper.AdjFileServiceHelper;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.Date;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
-* 员工职位档案
+* 员工职位档案-保存
 * 实体标识:nckd_personposfile
 * @author W.Y.C
 * @date 2025/12/4 19:36
@@ -38,4 +38,117 @@ import java.util.stream.Collectors;
 */
 public class PersonPosFileSaveOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
 
+    protected final static Log logger = LogFactory.getLog(PersonPosFileSaveOpPlugin.class);
+
+
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        //职位津贴=职位系数 X 所在岗级岗位工资一档金额
+        List<Long> allPersonIds = new ArrayList<>(e.getDataEntities().length);
+        List<Long> jobLevelIds = new ArrayList<>(e.getDataEntities().length);
+        for (DynamicObject dataEntity : e.getDataEntities()) {
+            BigDecimal coefficient = dataEntity.getBigDecimal(PositionStructureConstant.NCKD_COEFFICIENT);
+            BigDecimal currentPostSalary = dataEntity.getBigDecimal(PositionStructureConstant.NCKD_CURRENTPOSTSALARY);
+            BigDecimal postAllowance = dataEntity.getBigDecimal(PositionStructureConstant.NCKD_POSTALLOWANCE);
+            //当职位系数、岗位工资一档金额、岗位津贴为0时才处理,不为空则跳过
+            if((coefficient == null || coefficient.compareTo(BigDecimal.ZERO) <= 0) && (currentPostSalary == null || currentPostSalary.compareTo(BigDecimal.ZERO) <= 0) && (postAllowance == null || postAllowance.compareTo(BigDecimal.ZERO) <= 0)){
+                long personId = dataEntity.getLong(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY));
+                if(personId > 0){
+                    allPersonIds.add(personId);
+                }
+                long jobLevelId = dataEntity.getLong(String.join(".", PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
+                jobLevelIds.add(jobLevelId);
+            }
+
+        }
+
+        //====================================== 获取当前人员所在定调的岗位标准工资一档金额 begin ======================================
+        Map<Long, BigDecimal> amountMap = new HashMap<>(e.getDataEntities().length);
+        if(!allPersonIds.isEmpty() && !jobLevelIds.isEmpty()) {
+            //获取人员最新岗位工资标准定薪记录
+            List<AdjFileServiceHelper.SalaryAdjustmentResult> salaryAdjustmentResultList = AdjFileServiceHelper.getLastDecAdjRecords(allPersonIds, FormConstant.STANDARDITEM_ID_KEY);
+            if (!salaryAdjustmentResultList.isEmpty()) {
+                //薪酬标准ID
+                List<Long> salaryStIds = salaryAdjustmentResultList.stream().map(result -> result.salaryStDv.getLong(FormConstant.ID_KEY)).collect(Collectors.toList());
+                QFilter filter = new QFilter(FormConstant.ID_KEY, QCP.in, salaryStIds)
+                        .and(String.join(".", "rankentry", "rank", FormConstant.NUMBER_KEY), QCP.equals, "01");
+                //获取标准表中01档的薪档
+                QueryFieldBuilder salaryStandFieldBuilder = QueryFieldBuilder.create()
+                        .add(FormConstant.ID_KEY)
+                        .addIdNumberNameWithExtras(new String[]{"rankentry", "rank"},FormConstant.INDEX_KEY);
+                DynamicObjectCollection salaryStandardColl = QueryServiceHelper.query("hcdm_salarystandard", salaryStandFieldBuilder.buildSelect(), new QFilter[]{filter});
+                Map<Long, DynamicObject> salaryStandardMap = salaryStandardColl.stream()
+                        .collect(Collectors.toMap(
+                                obj -> obj.getLong(FormConstant.ID_KEY),
+                                obj -> obj
+                        ));
+
+                if (!salaryStandardMap.isEmpty()) {
+                    List<StdTableDataMatchParam> matchParams = new ArrayList<>();
+                    for (AdjFileServiceHelper.SalaryAdjustmentResult result : salaryAdjustmentResultList) {
+                        StdTableDataMatchParam stdTableDataMatchParam = new StdTableDataMatchParam();
+                        stdTableDataMatchParam.setStdTableId(result.salaryStDv.getLong(FormConstant.ID_KEY));
+                        stdTableDataMatchParam.setStdItemId(FormConstant.STANDARDITEM_ID_KEY);
+                        stdTableDataMatchParam.setGradeId(result.salaryGrade.getLong(FormConstant.ID_KEY));
+                        DynamicObject dynamicObject = salaryStandardMap.get(result.salaryStDv.getLong(FormConstant.ID_KEY));
+                        if(dynamicObject != null) {
+                            long rankId = dynamicObject.getLong(String.join(".", "rankentry", "rank", FormConstant.ID_KEY));
+                            stdTableDataMatchParam.setRankId(rankId);
+                            matchParams.add(stdTableDataMatchParam);
+                        }
+                    }
+                    if(!matchParams.isEmpty()) {
+                        //获取薪酬项目、薪等、薪档对应金额(入参params的数组下标和出参的数组下标一一对应)
+                        List<StdTableDataMatchResult> stdTableDataMatchResults = HCDMSalaryStdServiceHelper.matchStdTableData(matchParams);
+                        for (int i = 0; i < salaryAdjustmentResultList.size(); i++) {
+                            AdjFileServiceHelper.SalaryAdjustmentResult result = salaryAdjustmentResultList.get(i);
+                            if (i < stdTableDataMatchResults.size() && stdTableDataMatchResults.get(i) != null) {
+                                amountMap.put(result.employee.getLong(FormConstant.ID_KEY), stdTableDataMatchResults.get(i).getAmount());
+                            }
+                        }
+                    }
+                } else {
+                    logger.warn("未获取薪酬标准表中01档的薪档数据,薪酬标准ID:{}",salaryStIds);
+                }
+            } else {
+                logger.warn("未获取到人员岗位工资标准定薪记录,人员ID:{}",allPersonIds);
+            }
+        }
+        //====================================== 获取当前人员所在定调的岗位标准工资一档金额 end ======================================
+        Map<Long, DynamicObject> jobLevelMap = new HashMap<>(e.getDataEntities().length);
+        if(!jobLevelIds.isEmpty()) {
+            MainEntityType jobLevelEntityType = EntityMetadataCache.getDataEntityType(FormConstant.HBJM_JOBLEVELHR);
+            //重新加载职级信息,避免获取不到系数
+            DynamicObject[] load = BusinessDataServiceHelper.load(jobLevelIds.toArray(new Long[0]), jobLevelEntityType);
+            jobLevelMap = Arrays.stream(load)
+                    .collect(Collectors.toMap(
+                            obj -> obj.getLong(FormConstant.ID_KEY),
+                            obj -> obj
+                    ));
+        }
+
+        for (DynamicObject dataEntity : e.getDataEntities()) {
+            long jobLevelId = dataEntity.getLong(String.join(".", PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
+            DynamicObject jobLevel = jobLevelMap.get(jobLevelId);
+            if(jobLevel != null){
+                DynamicObject person = dataEntity.getDynamicObject(FormConstant.NCKD_PERSON);
+                long personId = person.getLong(FormConstant.ID_KEY);
+                //当前岗位工资01档金额
+                BigDecimal amount = amountMap.get(personId);
+                if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) {
+                    BigDecimal coefficient = jobLevel.getBigDecimal(PositionStructureConstant.NCKD_COEFFICIENT);
+                    if(coefficient.compareTo(BigDecimal.ZERO) > 0) {
+                        dataEntity.set(PositionStructureConstant.NCKD_COEFFICIENT, coefficient);
+                        dataEntity.set(PositionStructureConstant.NCKD_CURRENTPOSTSALARY, amount);
+                        dataEntity.set(PositionStructureConstant.NCKD_POSTALLOWANCE, coefficient.multiply(amount));
+                    }
+                } else {
+                    logger.warn("未获取到员工【{}】最新岗位工资标准定薪记录01档的薪等金额,人员ID:", person.getString(FormConstant.NAME_KEY));
+                }
+            }
+        }
+    }
+
 }

+ 22 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/task/PsmsAdjustSalaryTask.java

@@ -0,0 +1,22 @@
+package nckd.jxccl.hr.psms.task;
+
+import kd.bos.context.RequestContext;
+import kd.bos.exception.KDException;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.sdk.plugin.Plugin;
+
+import java.util.Map;
+
+/**
+ * TODO
+ *
+ * @author W.Y.C
+ * @version 1.0
+ * @date 2025/12/21 15:01
+ */
+public class PsmsAdjustSalaryTask extends AbstractTask implements Plugin {
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+
+    }
+}

+ 3 - 5
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/salary/SalaryAdjOpPlugin.java

@@ -86,8 +86,6 @@ public class SalaryAdjOpPlugin extends AbstractOperationServicePlugIn implements
     private static final int TYPE_PROMOTE_FOR_TWO_EXCELLENT_AND_THREE_PASS = 3;
     /**连续两年考核结果为优秀且另一年考核结果为合格及以上*/
     private static final int TYPE_PROMOTE_FOR_TWO_EXCELLENT_AND_THREE_PASS_FOR_TWO_YEARS = 4;
-    /** 岗位工资标准(jt002)*/
-    private static final Long standardItemId = 2321899710350111744L;
 
 
     int passYear = 2018;
@@ -220,7 +218,7 @@ public class SalaryAdjOpPlugin extends AbstractOperationServicePlugIn implements
                         .collect(Collectors.toList());
 
                 DynamicObject standardItem = EntityHelper.newEntity(FormConstant.HSBS_STANDARDITEM);
-                standardItem.set(FormConstant.ID_KEY, standardItemId);
+                standardItem.set(FormConstant.ID_KEY, FormConstant.STANDARDITEM_ID_KEY);
                 Map<String, Object> adjFileParams = new HashMap<>();
                 adjFileParams.put("employees", allPersonIds);
                 List<String> status = new ArrayList<>();
@@ -247,7 +245,7 @@ public class SalaryAdjOpPlugin extends AbstractOperationServicePlugIn implements
                         // 调薪档案ID
                         dataItem.put("adjfile", adjFileId);
                         // 调薪项目ID
-                        dataItem.put("standarditem", standardItemId);
+                        dataItem.put("standarditem", FormConstant.STANDARDITEM_ID_KEY);
                         // 查询基准日期
                         dataItem.put("startdate", new Date());
                         // 唯一标识
@@ -373,7 +371,7 @@ public class SalaryAdjOpPlugin extends AbstractOperationServicePlugIn implements
                             List<StdTableDataMatchParam> matchParams = new ArrayList<>();
                             StdTableDataMatchParam stdTableDataMatchParam = new StdTableDataMatchParam();
                             stdTableDataMatchParam.setStdTableId(result.salaryStDv.getLong(FormConstant.ID_KEY));
-                            stdTableDataMatchParam.setStdItemId(standardItemId);
+                            stdTableDataMatchParam.setStdItemId(FormConstant.STANDARDITEM_ID_KEY);
                             stdTableDataMatchParam.setGradeId(result.oldSalaryGrade.getLong(FormConstant.ID_KEY));
                             stdTableDataMatchParam.setRankId(newSalaryRank.getLong(FormConstant.ID_KEY));
                             matchParams.add(stdTableDataMatchParam);