Преглед изворни кода

Merge remote-tracking branch 'origin/master'

jtd пре 2 недеља
родитељ
комит
60c8f6dc6b
29 измењених фајлова са 1625 додато и 118 уклоњено
  1. 4 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java
  2. 14 2
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/DateUtil.java
  3. 148 0
      code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/swc/helper/AdjFileServiceHelper.java
  4. 5 4
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/AnnualAdjustmentService.java
  5. 342 49
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/JobLevelCalculatorService.java
  6. 2 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/ContributionConstant.java
  7. 16 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/PositionStructureConstant.java
  8. 131 3
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/ContributionHelper.java
  9. 136 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/contribution/ContribBillFormPlugin.java
  10. 16 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/adjust/NewDynamicAdjustmentOperationPlugIn.java
  11. 18 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualAdjustmentOperationPlugin.java
  12. 1 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualLockOrUnLockedOpPlugin.java
  13. 27 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/contribution/ContribBillOpPlugin.java
  14. 129 10
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/file/PersonPosFileSaveOpPlugin.java
  15. 85 10
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/BaseInitialOperationPlugIn.java
  16. 21 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/NewHireInitialOperationPlugIn.java
  17. 20 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/ServingInitialOperationPlugIn.java
  18. 1 9
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/other/NewAppointMentOpPlugin.java
  19. 355 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/task/PsmsAdjustSalaryTask.java
  20. 1 1
      code/nckd-cosmic-debug/src/main/java/kd/cosmic/debug/tools/CosmicLauncher.java
  21. 3 2
      code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/salary/PushAdjustOpPlugin.java
  22. 3 5
      code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/salary/SalaryAdjOpPlugin.java
  23. 1 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/business/coordination/SinsurCoordSplitService.java
  24. 1 1
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/business/datacomparison/DataComparisonQueryService.java
  25. 21 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/formplugin/web/coordination/HCSIEmpCoordVerifBillListEx.java
  26. 1 1
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/utils/ReportUtils.java
  27. 23 5
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/hcdm/opplugin/annualincome/SalAnnualIncomeUpdatePlugin.java
  28. 87 4
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/business/SynPendingSalaryAdjDataServiceImpl.java
  29. 13 5
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/utils/SwcUtils.java

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

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

+ 14 - 2
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/DateUtil.java

@@ -399,6 +399,16 @@ public class DateUtil {
 
     // ==================== 时间范围处理 ====================
 
+    /**
+     * 获取日期的开始时间(00:00:00)
+     *
+     * @param date 日期时间
+     * @return 当天的开始时间
+     */
+    public static Date beginOfDay(Date date) {
+        return toDate(beginOfDay(toLocalDateTime(date)));
+    }
+
     /**
      * 获取日期的开始时间(00:00:00)
      *
@@ -450,14 +460,16 @@ public class DateUtil {
         return dateTime.withDayOfYear(1).toLocalDate().atStartOfDay();
     }
 
+
+
     /**
      * 获取日期当天的结束时间(23:59:59.999999999)
      *
      * @param date 日期时间
      * @return 当天的结束时间
      */
-    public static LocalDateTime endOfDay(Date date) {
-        return endOfDay(toLocalDateTime(date));
+    public static Date endOfDay(Date date) {
+        return toDate(endOfDay(toLocalDateTime(date)));
     }
 
     /**

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

@@ -0,0 +1,148 @@
+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,hcdmorg.id,");
+            //查询定调薪记录
+            //hcdm_decadjrecor
+            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 hcdmOrg = dynamicObject.getDynamicObject("hcdmorg");
+                            //薪酬标准表版本
+                            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.hcdmOrg = hcdmOrg;
+                            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 hcdmOrg;
+        /**定调薪档案*/
+        public DynamicObject adjFileInfo;
+        /**薪酬标准表*/
+        public DynamicObject salaryStDv;
+        /** 定调薪项目 */
+        public DynamicObject standardItem;
+        /** 薪等(01岗、02岗)*/
+        public DynamicObject salaryGrade;
+        /** 薪档(1档、2档)*/
+        public DynamicObject salaryRank;
+        //金额
+        public BigDecimal amount;
+    }
+}

+ 5 - 4
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/AnnualAdjustmentService.java

@@ -351,9 +351,9 @@ public class AnnualAdjustmentService {
 
         //4、获取年度贡献积分
         //对应SHR:291行;utils.YearContributeScoreBillEntryScoreSumBypersonidAndYear
-        List<ContributionHelper.ScoreItemValidScore> scoreItemAccumulateScore = ContributionHelper.getApprovedScoreItemAccumulateScore(new Long[]{ac.personId}, DateUtil.toDate(lastYearDateTime));
+        List<ContributionHelper.ScoreItemValidScore> scoreItemAccumulateScore = ContributionHelper.sumScoreItemAccumulateScore(new Long[]{ac.personId}, DateUtil.toDate(lastYearDateTime));
         //计算出最多可得的分数(根据积分配置项)
-        List<ContributionHelper.ScoreItemValidScore> allowedScoreList = ContributionHelper.calculateMaxAllowedScore(scoreItemAccumulateScore);
+        List<ContributionHelper.ScoreItemValidScore> allowedScoreList = ContributionHelper.calculateMaxAllowedScore1(scoreItemAccumulateScore);
         BigDecimal allowedScoreSum = BigDecimal.ZERO;
         for (ContributionHelper.ScoreItemValidScore allowedScore : allowedScoreList) {
             String scoreItemNumber = allowedScore.getScoreItemNumber();
@@ -385,7 +385,8 @@ public class AnnualAdjustmentService {
             //比较实际累计总分和未受限制的实际累计总分
             if(sumScore.compareTo(validScore) != 0){
                 //实际累计积分与有效积分不符,说明被限高
-                ac.whyAdjust1.add(StrFormatter.format("上年度【{}】【{}】积分实际累计总分为【{}】但达到项目最高分限制,最终有效应用分为【{}】;", scoreItemEnum.getCode(), sumScore, validScore));
+                ac.whyAdjust1.add(StrFormatter.format("上年度【{}】【{}】积分实际累计总分为【{}】但达到项目最高分限制,最终有效应用分为【{}】;", scoreItemEnum.getName(), sumScore, validScore));
+                logger.warn(StrFormatter.format("上年度【{}】积分实际累计总分为【{}】但达到项目最高分限制,最终有效应用分为【{}】;", scoreItemEnum.getName(), sumScore, validScore));
             }
 
         }
@@ -594,7 +595,7 @@ public class AnnualAdjustmentService {
         logger.info("上年度贡献综合评价分: " + ac.lastYearContributeScore);
 
         ac.addYearContributeScore = ac.lastYearContributeScore.multiply(new BigDecimal("0.1"));
-        logger.info("年度新增的贡献积分: " + ac.addYearContributeScore);
+        logger.info("年度新增的贡献积分(*10%): " + ac.addYearContributeScore);
 
         BigDecimal lastsum = ac.data.getLastSumScore() == null ? BigDecimal.ZERO : ac.data.getLastSumScore();
         logger.info("上年累计积分池的分: " + lastsum);

Разлика између датотеке није приказан због своје велике величине
+ 342 - 49
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/JobLevelCalculatorService.java


+ 2 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/ContributionConstant.java

@@ -39,6 +39,8 @@ public class ContributionConstant extends FormConstant {
     public static final String NCKD_SCOREITEMSUB = "nckd_scoreitemsub";
     /** 积分项目名次 */
     public static final String NCKD_SCOREITEMRANK = "nckd_scoreitemrank";
+    /** 分录-积分项目名次 */
+    public static final String NCKD_SCOREITEMRANKEN = "nckd_scoreitemranken";
 
 
 

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

@@ -121,6 +121,22 @@ 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";
+    /** 当前01档岗位工资 */
+    public static final String NCKD_CURRENTPOSTSALARY = "nckd_currentpostsalary";
+    /** 岗位津贴 */
+    public static final String NCKD_POSTALLOWANCE = "nckd_postallowance";
+    /** 是否已推送调薪 */
+    public static final String NCKD_ISSALADJPUSH = "nckd_issaladjpush";
+    /** 调薪推送时间 */
+    public static final String NCKD_SALADJPUSHTIME = "nckd_saladjpushtime";
+    /** 调薪id */
+    public static final String NCKD_SALADJID = "nckd_saladjid";
+    /** 调薪编码 */
+    public static final String NCKD_SALADJNUMBER = "nckd_saladjnumber";
+
     /*-------------------------------------- 员工职位档案 end --------------------------------------*/
 
 

+ 131 - 3
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/ContributionHelper.java

@@ -5,13 +5,17 @@ import kd.bos.algo.AlgoContext;
 import kd.bos.algo.DataSet;
 import kd.bos.algo.Row;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+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.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.psms.ScoreItemEnum;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.psms.business.AnnualAdjustmentService;
 import nckd.jxccl.hr.psms.common.ContributionConstant;
 
 import java.math.BigDecimal;
@@ -32,6 +36,8 @@ import java.util.stream.Collectors;
  */
 public class ContributionHelper {
 
+    protected final static Log logger = LogFactory.getLog(AnnualAdjustmentService.class);
+
     /**
      * 根据人员获取积分项目有效分数
      * 依据人员某年度已获得的积分(含在途单据)+积分配置的最高分计算出可获得的分数
@@ -186,7 +192,8 @@ public class ContributionHelper {
                             String.join(".", ContributionConstant.NCKD_SCOREITEM, FormConstant.ID_KEY),
                             String.join(".", ContributionConstant.NCKD_SCOREITEM, FormConstant.NUMBER_KEY),
                             String.join(".", ContributionConstant.NCKD_SCOREITEMSUB, FormConstant.ID_KEY),
-                            String.join(".", ContributionConstant.NCKD_SCOREITEMRANK, FormConstant.ID_KEY)}) // 添加名次分组
+                            String.join(".", ContributionConstant.NCKD_SCOREITEMRANK, FormConstant.ID_KEY)
+                    })
                     .sum(String.join(".", ContributionConstant.NCKD_ENTRYENTITY, FormConstant.NCKD_SCORE),"sumScore").finish();
 
             while (sumDateSet.hasNext()) {
@@ -205,6 +212,67 @@ public class ContributionHelper {
         return scoreItemValidScoreList;
     }
 
+
+    /**
+     * 根据人员和年度获取积分项目已累计分数
+     * @param personIds 人员
+     * @param year 年度
+     * @return: List<ScoreItemValidScore> 积分项目已累计分数
+     * @author W.Y.C
+     * @date: 2025/10/26 16:20
+     */
+    public static List<ScoreItemValidScore> sumScoreItemAccumulateScore(Long[] personIds, Date year) {
+        if (personIds == null || personIds.length == 0) {
+            return new ArrayList<>();
+        }
+
+        LocalDateTime yearStarDateTime = DateUtil.beginOfYear(DateUtil.toLocalDateTime(year));
+        QueryFieldBuilder scoreItemConfFieldBuilder = QueryFieldBuilder.create()
+                .add(ContributionConstant.NCKD_YEAR)
+                .addIdNumberName(ContributionConstant.NCKD_SCOREITEM)
+                .addIdNumberName(ContributionConstant.NCKD_SCOREITEMSUB)
+                .addIdNumberName(ContributionConstant.NCKD_SCOREITEMRANK) // 添加积分项目名次字段
+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_PERSON},FormConstant.ID_KEY)
+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY}, ContributionConstant.NCKD_SCORE, ContributionConstant.NCKD_ORISCORE);
+
+        //只查询"已审批通过"年度贡献积分
+        QFilter filter = QFilterCommonHelper.getBillStatusFilter()
+                .and(ContributionConstant.NCKD_YEAR,QCP.large_equals,DateUtil.beginOfDay(yearStarDateTime))
+                .and(ContributionConstant.NCKD_YEAR,QCP.less_equals, DateUtil.endOfDay(yearStarDateTime))
+                .and(String.join( ".",FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_PERSON),QCP.in,personIds);
+
+        List<ScoreItemValidScore> scoreItemValidScoreList = new ArrayList<>();
+        try(AlgoContext context = Algo.newContext()) {
+            DataSet dateSet = QueryServiceHelper.queryDataSet(ContributionHelper.class.getName(),
+                    ContributionConstant.CONTRIBBILL_ENTITYID,
+                    scoreItemConfFieldBuilder.buildSelect(),
+                    new QFilter[]{filter}, null, 5000);
+
+            DataSet sumDateSet = dateSet.copy()
+                    // 按人员、积分项目、积分项目子项、积分项目名次进行分组
+                    .groupBy(new String[]{String.join(".", ContributionConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_PERSON, FormConstant.ID_KEY),
+                            String.join(".", ContributionConstant.NCKD_SCOREITEM, FormConstant.ID_KEY),
+                            String.join(".", ContributionConstant.NCKD_SCOREITEM, FormConstant.NUMBER_KEY)
+                    })
+                    .sum(String.join(".", ContributionConstant.NCKD_ENTRYENTITY, FormConstant.NCKD_SCORE),"sumScore").finish();
+
+            while (sumDateSet.hasNext()) {
+                Row row = sumDateSet.next();
+                Long personId = row.getLong(String.join(".", ContributionConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_PERSON, FormConstant.ID_KEY));
+                Long scoreItemId = row.getLong(String.join(".", ContributionConstant.NCKD_SCOREITEM, FormConstant.ID_KEY));
+                String scoreItemNumber = row.getString(String.join(".", ContributionConstant.NCKD_SCOREITEM, FormConstant.NUMBER_KEY));
+                //已获得的累计积分
+                BigDecimal sumScore = row.getBigDecimal("sumScore");
+                ScoreItemValidScore scoreItemValidScore = new ScoreItemValidScore(personId, scoreItemId,scoreItemNumber, null, null, sumScore);
+                scoreItemValidScoreList.add(scoreItemValidScore);
+            }
+        }
+        return scoreItemValidScoreList;
+    }
+
+
+
+
     /**
      * 根据人员和年度获取积分项目已累计分数(包含所有未废弃记录)
      * @param personIds 人员
@@ -439,6 +507,65 @@ public class ContributionHelper {
         return result;
     }
 
+
+    /**
+     * 计算最多可得的分数
+     * 根据累计积分和分数配置映射表,如果超过配置的限制分数则返回限制分最大分数,
+     * 计算每个积分大项在考虑三重限制条件下的最大可获得分数:
+     * 1. 名次限制:每个积分项目名次可能有分数上限(最高优先级)
+     * 2. 子项限制:每个具体积分项目子项可能有分数上限
+     * 3. 大项限制:整个积分大项可能有总分上限
+     *
+     * @param scoreItemValidScoreList 某个人员所有积分项目的累计积分(personId、scoreItemId、scoreItemSubId、scoreItemRankId、sumScore有值)
+     * @return 最多可得的分数列表(按大项维度聚合)
+     * @author W.Y.C
+     * @date: 2025/10/27
+     */
+    public static List<ScoreItemValidScore> calculateMaxAllowedScore1(List<ScoreItemValidScore> scoreItemValidScoreList) {
+
+        //获取积分限分配置
+        Map<String, BigDecimal> scoreConfMap = ContributionHelper.getScoreConf();
+        /*Map<String, BigDecimal> scoreConfMap = Maps.newConcurrentMap();
+         scoreConfMap.put("11-111-1111",new BigDecimal(2));
+         scoreConfMap.put("11-121",new BigDecimal(5));
+         scoreConfMap.put("11",new BigDecimal(20));*/
+
+        List<ScoreItemValidScore> result = new ArrayList<>();
+
+        // 按大类分组
+        Map<Long, List<ScoreItemValidScore>> groupedByScoreItemId = scoreItemValidScoreList.stream()
+                .collect(Collectors.groupingBy(ScoreItemValidScore::getScoreItemId));
+
+        for (Map.Entry<Long, List<ScoreItemValidScore>> entry : groupedByScoreItemId.entrySet()) {
+            Long scoreItemId = entry.getKey();
+            List<ScoreItemValidScore> valueList = entry.getValue();
+
+            // 获取大项限制分数
+            BigDecimal scoreItemMaxScore = scoreConfMap.get(scoreItemId + "");
+
+            BigDecimal totalAllowedScore = BigDecimal.ZERO;
+            for (ScoreItemValidScore item : valueList) {
+                BigDecimal score = item.getSumScore() == null ? BigDecimal.ZERO : item.getSumScore();
+                // 应用大项限制(如果设置了大项限制)
+                if (scoreItemMaxScore != null && scoreItemMaxScore.compareTo(BigDecimal.ZERO) >= 0) {
+                    totalAllowedScore = scoreItemMaxScore.min(score);
+                }else{
+                    //没有配置限制,则直接使用录入的分数
+                    ScoreItemEnum scoreItemEnum = ScoreItemEnum.getByCode(item.getScoreItemNumber());
+                    logger.warn("积分【{}】没有配置积分项限制,使用实际录入的分数:{}",scoreItemEnum.getName() ,score);
+                    totalAllowedScore = score;
+                }
+                // 创建结果对象,只包含scoreItemId和validScore
+                ScoreItemValidScore resultItem = new ScoreItemValidScore(item.getPersonId(), scoreItemId, null, null);
+                resultItem.setScoreItemNumber(item.getScoreItemNumber());
+                resultItem.setValidScore(totalAllowedScore);
+                resultItem.setSumScore(score);
+                result.add(resultItem);
+            }
+        }
+        return result;
+    }
+
     /**
      * 决定使用哪种累计分数
      * @param scoreConfMap 分数配置映射
@@ -619,7 +746,7 @@ public class ContributionHelper {
         }
 
         public BigDecimal getValidScore() {
-            //为空时说明不限制分数
+           /* //为空时说明不限制分数
             BigDecimal trulyValidScore = this.currentScore;
             if(this.validScore != null && this.currentScore != null){
                 //如果可使用分数超过录入分数则使用录入分数(oriScore),否则使用可使用分数
@@ -627,7 +754,8 @@ public class ContributionHelper {
             }else{
                 return BigDecimal.ZERO;
             }
-            return trulyValidScore;
+            return trulyValidScore;*/
+            return this.validScore;
         }
 
         public void setValidScore(BigDecimal validScore) {

+ 136 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/contribution/ContribBillFormPlugin.java

@@ -1,9 +1,11 @@
 package nckd.jxccl.hr.psms.plugin.form.contribution;
 
+import kd.bos.bill.OperationStatus;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.entity.datamodel.events.ChangeData;
 import kd.bos.entity.datamodel.events.PropertyChangedArgs;
+import kd.bos.form.FormShowParameter;
 import kd.bos.form.field.BasedataEdit;
 import kd.bos.form.field.events.BeforeF7SelectEvent;
 import kd.bos.form.field.events.BeforeF7SelectListener;
@@ -11,9 +13,12 @@ import kd.bos.form.plugin.AbstractFormPlugin;
 import kd.bos.list.ListShowParameter;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.psms.ScoreItemEnum;
 import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.base.entity.helper.EntityHelper;
 import nckd.jxccl.hr.psms.common.ContributionConstant;
 import nckd.jxccl.hr.psms.helper.ContributionHelper;
 
@@ -22,6 +27,7 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.EventObject;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -33,6 +39,38 @@ import java.util.Objects;
 */
 public class ContribBillFormPlugin extends AbstractFormPlugin implements Plugin, BeforeF7SelectListener {
 
+    @Override
+    public void afterCreateNewData(EventObject e) {
+        FormShowParameter formShowParameter = this.getView().getFormShowParameter();
+        if (formShowParameter.getStatus() == OperationStatus.ADDNEW) {
+            Object value = this.getModel().getValue(ContributionConstant.NCKD_SCOREITEM);
+            if (value != null) {
+                DynamicObject scoreItem = ConvertUtil.toDynamicObjectOrNull(value);
+                if (scoreItem != null) {
+                    String scoreItemNumber = scoreItem.getString(FormConstant.NUMBER_KEY);
+                    if (ScoreItemEnum.SKILL_CONTEST_SCORE.getCode().equalsIgnoreCase(scoreItemNumber)) {
+                        //技能竞赛积分默认三行分录
+                        DynamicObjectCollection dynamicObjectCollection = this.getModel().getDataEntity(true).getDynamicObjectCollection(ContributionConstant.NCKD_ENTRYENTITY);
+                        DynamicObjectCollection scoreItemRankColl = QueryServiceHelper.query(ContributionConstant.NCKD_SCOREITEMRANK,
+                                FormConstant.ID_KEY+","+FormConstant.NAME_KEY+","+FormConstant.NUMBER_KEY,
+                                new QFilter[]{new QFilter(ContributionConstant.NCKD_SCOREITEM, QCP.equals, scoreItem.getLong(FormConstant.ID_KEY))},
+                                ContributionConstant.INDEX_KEY
+                        );
+                        for (DynamicObject scoreItemRank : scoreItemRankColl) {
+                            DynamicObject dynamicObject = dynamicObjectCollection.addNew();
+                            DynamicObject newScoreItemRank = EntityHelper.newEntity(ContributionConstant.NCKD_SCOREITEMRANK, scoreItemRank.getLong(FormConstant.ID_KEY));
+                            newScoreItemRank.set(ContributionConstant.NAME_KEY, scoreItemRank.getString(FormConstant.NAME_KEY));
+                            newScoreItemRank.set(ContributionConstant.NUMBER_KEY, scoreItemRank.getString(FormConstant.NUMBER_KEY));
+
+                            dynamicObject.set(ContributionConstant.NCKD_SCOREITEMRANKEN,newScoreItemRank);
+                        }
+                        this.getView().updateView(ContributionConstant.NCKD_ENTRYENTITY);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void registerListener(EventObject e) {
         super.registerListener(e);
@@ -118,6 +156,49 @@ public class ContribBillFormPlugin extends AbstractFormPlugin implements Plugin,
         DynamicObject scoreItemRank = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMRANK));
         DynamicObject person = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_PERSON, rowIndex));
         BigDecimal oriScore = ConvertUtil.toBigDecimal(this.getModel().getValue(ContributionConstant.NCKD_ORISCORE, rowIndex));
+        if (date != null && scoreItem != null && scoreItemSub != null) {
+            String scoreItemNumber = scoreItem.getString(FormConstant.NUMBER_KEY);
+            if (ScoreItemEnum.RESEARCH_SCORE.getCode().equalsIgnoreCase(scoreItemNumber)) {
+                if (person != null  && oriScore != null && oriScore.compareTo(BigDecimal.ZERO) > 0) {
+                    //科研与创新需要需要匹配积分规则
+                    QFilter filter = new QFilter(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_SCOREITEM), QCP.equals, scoreItem.getLong(FormConstant.ID_KEY))
+                            .and(new QFilter(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_SCOREITEMSUB), QCP.equals, scoreItemSub.getLong(FormConstant.ID_KEY)))
+                            .and(new QFilter(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_SCOREITEMRANK), QCP.equals, scoreItemRank.getLong(FormConstant.ID_KEY)));
+                    Map<String, BigDecimal> scoreConf = ContributionHelper.getScoreConf(filter);
+                    String key = scoreItem.getLong(FormConstant.ID_KEY) + "-" + scoreItemSub.getLong(FormConstant.ID_KEY) + "-" + scoreItemRank.getLong(FormConstant.ID_KEY);
+                    BigDecimal validScore = oriScore;
+                    if (!scoreConf.isEmpty() && scoreConf.containsKey(key)) {
+                        BigDecimal maxScore = scoreConf.get(key);
+                        if (maxScore != null) {
+                            validScore = oriScore.compareTo(maxScore) > 0 ? maxScore : oriScore;
+                        }
+                    }
+                    this.getModel().setValue(ContributionConstant.NCKD_SCORE, validScore, rowIndex);
+                    this.getView().updateView(ContributionConstant.NCKD_SCORE, rowIndex);
+                }
+            } else {
+                this.getModel().setValue(ContributionConstant.NCKD_SCORE, oriScore, rowIndex);
+                this.getView().updateView(ContributionConstant.NCKD_SCORE, rowIndex);
+            }
+        }
+    }
+
+    /**
+     * 处理分录行变更
+     * 分录变更则针对当前分录计算积分
+     * @param rowIndex 行索引
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/10/26 19:47
+     */
+    private void handleEntryRowChange1(int rowIndex) {
+        Long id = ConvertUtil.toLong(this.getModel().getValue(FormConstant.ID_KEY));
+        Date date = ConvertUtil.toDate(this.getModel().getValue(ContributionConstant.NCKD_YEAR));
+        DynamicObject scoreItem = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEM));
+        DynamicObject scoreItemSub = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMSUB));
+        DynamicObject scoreItemRank = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMRANK));
+        DynamicObject person = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_PERSON, rowIndex));
+        BigDecimal oriScore = ConvertUtil.toBigDecimal(this.getModel().getValue(ContributionConstant.NCKD_ORISCORE, rowIndex));
 
         if (date != null && scoreItem != null && scoreItemSub != null && person != null
                 && oriScore != null && oriScore.compareTo(BigDecimal.ZERO) > 0) {
@@ -149,6 +230,61 @@ public class ContribBillFormPlugin extends AbstractFormPlugin implements Plugin,
         DynamicObject scoreItemSub = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMSUB));
         DynamicObject scoreItemRank = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMRANK));
 
+
+        if (date != null && scoreItem != null && scoreItemSub != null) {
+
+            DynamicObjectCollection entryEntity = this.getModel().getEntryEntity(FormConstant.NCKD_ENTRYENTITY);
+            String scoreItemNumber = scoreItem.getString(FormConstant.NUMBER_KEY);
+            if(ScoreItemEnum.RESEARCH_SCORE.getCode().equalsIgnoreCase(scoreItemNumber)){
+                if(scoreItemRank != null) {
+                    //科研与创新需要需要匹配积分规则
+                    QFilter filter = new QFilter(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_SCOREITEM), QCP.equals, scoreItem.getLong(FormConstant.ID_KEY))
+                            .and(new QFilter(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_SCOREITEMSUB), QCP.equals, scoreItemSub.getLong(FormConstant.ID_KEY)))
+                            .and(new QFilter(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionConstant.NCKD_SCOREITEMRANK), QCP.equals, scoreItemRank.getLong(FormConstant.ID_KEY)));
+                    Map<String, BigDecimal> scoreConf = ContributionHelper.getScoreConf(filter);
+                    String key = scoreItem.getLong(FormConstant.ID_KEY)+"-"+scoreItemSub.getLong(FormConstant.ID_KEY)+"-"+scoreItemRank.getLong(FormConstant.ID_KEY);
+                    for (int i = 0; i < entryEntity.size(); i++) {
+                        DynamicObject entry = entryEntity.get(i);
+                        BigDecimal oriScore = entry.getBigDecimal(ContributionConstant.NCKD_ORISCORE);
+                        BigDecimal validScore = oriScore;
+                        if(!scoreConf.isEmpty() && scoreConf.containsKey(key)){
+                            BigDecimal maxScore = scoreConf.get(key);
+                            if (maxScore != null && oriScore != null) {
+                                validScore = oriScore.compareTo(maxScore) > 0 ? maxScore : oriScore;
+                            } else {
+                                // 根据业务需求处理 null 值情况
+                                validScore = oriScore != null ? oriScore : BigDecimal.ZERO;
+                            }
+                        }
+                        this.getModel().setValue(ContributionConstant.NCKD_SCORE, validScore, i);
+                    }
+                }
+            }else{
+                for (int i = 0; i < entryEntity.size(); i++) {
+                    DynamicObject entry = entryEntity.get(i);
+                    BigDecimal oriScore = entry.getBigDecimal(ContributionConstant.NCKD_ORISCORE);
+                    this.getModel().setValue(ContributionConstant.NCKD_SCORE, oriScore, i);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 处理表头字段变更
+     * 表头变更则重新计算所有分录(已维护人员和原积分的数据)的积分
+     * @param
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/10/26 19:47
+     */
+    private void handleHeadFieldChange1() {
+        Long id = ConvertUtil.toLong(this.getModel().getValue(FormConstant.ID_KEY));
+        Date date = ConvertUtil.toDate(this.getModel().getValue(ContributionConstant.NCKD_YEAR));
+        DynamicObject scoreItem = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEM));
+        DynamicObject scoreItemSub = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMSUB));
+        DynamicObject scoreItemRank = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionConstant.NCKD_SCOREITEMRANK));
+
         if (date != null && scoreItem != null && scoreItemSub != null) {
             //重置分录所有分录的"录用积分"字段
             DynamicObjectCollection entryEntity = this.getModel().getEntryEntity(FormConstant.NCKD_ENTRYENTITY);

+ 16 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/adjust/NewDynamicAdjustmentOperationPlugIn.java

@@ -2,11 +2,15 @@ package nckd.jxccl.hr.psms.plugin.operate.adjust;
 
 import kd.bos.common.enums.EnableEnum;
 import kd.bos.context.RequestContext;
+import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.CloneUtils;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.utils.ObjectUtils;
 import kd.bos.entity.ExtendedDataEntity;
 import kd.bos.entity.constant.StatusEnum;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
 import kd.bos.entity.plugin.AddValidatorsEventArgs;
 import kd.bos.entity.plugin.args.BeforeOperationArgs;
@@ -175,7 +179,18 @@ public class NewDynamicAdjustmentOperationPlugIn extends AbstractOperationServic
 
         }
 
-        SaveServiceHelper.save(newPersonPosFiles.toArray(new DynamicObject[0]));
+//        SaveServiceHelper.save(newPersonPosFiles.toArray(new DynamicObject[0]));
+        OperationResult operationResult = SaveServiceHelper.saveOperate(PositionStructureConstant.PERSONPOSFILE_ENTITYID, newPersonPosFiles.toArray(new DynamicObject[0]), OperateOption.create());
+        if (!operationResult.isSuccess()) {
+            StringJoiner errorMsg = new StringJoiner("\n");
+            for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+                errorMsg.add(error.getMessage());
+            }
+            if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
+                errorMsg.add(operationResult.getMessage());
+            }
+            throw new ValidationException("保存职位档案失败,原因:" + errorMsg.toString());
+        }
         PositionFileHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
         PositionFileHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
 

+ 18 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualAdjustmentOperationPlugin.java

@@ -1,9 +1,13 @@
 package nckd.jxccl.hr.psms.plugin.operate.annualadjust;
 
 import kd.bos.common.enums.EnableEnum;
+import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.utils.ObjectUtils;
 import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
 import kd.bos.entity.plugin.AddValidatorsEventArgs;
 import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
@@ -16,6 +20,7 @@ import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.enums.psms.AdjustTypeEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.base.pm.helper.PerformanceManagerHelper;
@@ -33,6 +38,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.StringJoiner;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -176,7 +182,18 @@ public class AnnualAdjustmentOperationPlugin extends AbstractOperationServicePlu
             }
         }
 
-        SaveServiceHelper.save(newPersonPosFiles.toArray(new DynamicObject[0]));
+//        SaveServiceHelper.save(newPersonPosFiles.toArray(new DynamicObject[0]));
+        OperationResult operationResult = SaveServiceHelper.saveOperate(PositionStructureConstant.PERSONPOSFILE_ENTITYID, newPersonPosFiles.toArray(new DynamicObject[0]), OperateOption.create());
+        if (!operationResult.isSuccess()) {
+            StringJoiner errorMsg = new StringJoiner("\n");
+            for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+                errorMsg.add(error.getMessage());
+            }
+            if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
+                errorMsg.add(operationResult.getMessage());
+            }
+            throw new ValidationException("保存职位档案失败,原因:" + errorMsg.toString());
+        }
         PositionFileHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
         PositionFileHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
         for (DynamicObject newPersonPosFile : newPersonPosFiles) {

+ 1 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualLockOrUnLockedOpPlugin.java

@@ -149,6 +149,7 @@ public class AnnualLockOrUnLockedOpPlugin extends AbstractOperationServicePlugIn
                 for (DynamicObject dynamicObject : load) {
                     DynamicObject entryObj = new DynamicObject(entryType);
                     entryObj.set(PositionStructureConstant.NCKD_PERSONPOSFILE, dynamicObject);
+                    entryObj.set(PositionStructureConstant.NCKD_ORG, dynamicObject.getDynamicObject(FormConstant.NCKD_DEP).getDynamicObject(FormConstant.BELONGCOMPANY_KEY));
                     entryColl.add(entryObj);
                 }
                 //提交单据

+ 27 - 2
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/contribution/ContribBillOpPlugin.java

@@ -16,6 +16,7 @@ import kd.bos.entity.validate.ErrorLevel;
 import kd.bos.form.MessageBoxResult;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.psms.ScoreItemEnum;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.hr.psms.common.ContributionConstant;
@@ -26,6 +27,7 @@ import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -46,6 +48,7 @@ public class ContribBillOpPlugin extends AbstractOperationServicePlugIn implemen
             @Override
             public void validate() {
                 //校验参与人数
+                Map<String, BigDecimal> scoreConf = ContributionHelper.getScoreConf();
                 for (ExtendedDataEntity dataEntity : this.getDataEntities()) {
                     DynamicObject data = dataEntity.getDataEntity();
                     int participants = data.getInt(ContributionConstant.NCKD_PARTICIPANTS);
@@ -62,7 +65,29 @@ public class ContribBillOpPlugin extends AbstractOperationServicePlugIn implemen
                             DynamicObject scoreItem = data.getDynamicObject(ContributionConstant.NCKD_SCOREITEM);
                             DynamicObject scoreItemSub = data.getDynamicObject(ContributionConstant.NCKD_SCOREITEMSUB);
                             DynamicObject scoreItemRank = data.getDynamicObject(ContributionConstant.NCKD_SCOREITEMRANK);
-                            List<ContributionHelper.ScoreItemValidScore> scoreItemValidScoreList = new ArrayList<>(entryEntity.size());
+                            String scoreItemNumber = scoreItem.getString(FormConstant.NUMBER_KEY);
+                            if(ScoreItemEnum.RESEARCH_SCORE.getCode().equalsIgnoreCase(scoreItemNumber)){
+                                String key = scoreItem.getLong(FormConstant.ID_KEY)+"-"+scoreItemSub.getLong(FormConstant.ID_KEY)+"-"+scoreItemRank.getLong(FormConstant.ID_KEY);
+                                if(!scoreConf.isEmpty() && scoreConf.containsKey(key)){
+                                    BigDecimal maxScore = scoreConf.get(key);
+                                    for (DynamicObject entry : entryEntity) {
+                                        DynamicObject person = entry.getDynamicObject(ContributionConstant.NCKD_PERSON);
+                                        long personId = person.getLong(FormConstant.ID_KEY);
+                                        BigDecimal oriScore = entry.getBigDecimal(ContributionConstant.NCKD_ORISCORE);
+                                        BigDecimal score = entry.getBigDecimal(ContributionConstant.NCKD_SCORE);
+                                        if(oriScore.compareTo(maxScore) > 0) {
+                                            this.addFatalErrorMessage(dataEntity, StrFormatter.format("参与人【{}】的原始分数【{}】超出限制积分【{}】。请重新填写“原始积分”,系统将会自动重算“录入积分”;",
+                                                    person.getString(FormConstant.NAME_KEY),
+                                                    oriScore.setScale(2, RoundingMode.HALF_UP),
+                                                    maxScore.setScale(2, RoundingMode.HALF_UP)));
+                                        }
+                                    }
+
+                                }
+                            }
+
+
+                           /* List<ContributionHelper.ScoreItemValidScore> scoreItemValidScoreList = new ArrayList<>(entryEntity.size());
                             for (DynamicObject entry : entryEntity) {
                                 DynamicObject person = entry.getDynamicObject(ContributionConstant.NCKD_PERSON);
                                 BigDecimal oriScore = entry.getBigDecimal(ContributionConstant.NCKD_ORISCORE);
@@ -94,7 +119,7 @@ public class ContribBillOpPlugin extends AbstractOperationServicePlugIn implemen
                                         }
                                     }
                                 }
-                            }
+                            }*/
                         }
                     }
                 }

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

@@ -3,34 +3,36 @@ 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;
+import java.util.stream.Stream;
 
 /**
-* 员工职位档案
+* 员工职位档案-保存
 * 实体标识:nckd_personposfile
 * @author W.Y.C
 * @date 2025/12/4 19:36
@@ -38,4 +40,121 @@ 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()) {
+            String typeState = dataEntity.getString(PositionStructureConstant.NCKD_TYPESTATE);
+            if(Arrays.asList(TypeStateEnum.NEW_ENTRY.getCode(), TypeStateEnum.IN_SERVICE_LEVEL.getCode(), TypeStateEnum.ANNUAL_ADJUSTMENT.getCode(), TypeStateEnum.POSITION_TRANSFER.getCode()).contains(typeState)){
+                //只有新入职、在职人员初定、年度调整、动态调整才要获取薪酬
+                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) {
+                                //当前薪等01档的金额
+                                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));
+                }
+            }
+        }
+    }
+
 }

+ 85 - 10
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/BaseInitialOperationPlugIn.java

@@ -3,9 +3,13 @@ package nckd.jxccl.hr.psms.plugin.operate.initial;
 import com.google.common.collect.Lists;
 import kd.bos.common.enums.EnableEnum;
 import kd.bos.context.RequestContext;
+import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.utils.ObjectUtils;
 import kd.bos.entity.constant.StatusEnum;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
 import kd.bos.logging.Log;
 import kd.bos.logging.LogFactory;
@@ -15,6 +19,7 @@ import kd.bos.servicehelper.operation.SaveServiceHelper;
 import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.enums.AppraisalResultEnum;
 import nckd.jxccl.base.common.enums.psms.JobSeqEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
@@ -32,6 +37,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.StringJoiner;
 
 /**
  * 人员初定操作插件基类
@@ -118,75 +124,101 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
      * @date: 2025/10/12 14:20
      */
     protected List<BaseInitialData> extractBasicInfo(DynamicObject initialData) {
+        logger.info("【职位体系】-开始提取基本信息");
         List<BaseInitialData> dataList = new ArrayList<>();
         if(initialData.containsProperty(FormConstant.NCKD_ENTRYENTITY)){
             DynamicObjectCollection dynamicObjectCollection = initialData.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
-            for (DynamicObject dynamicObject : dynamicObjectCollection) {
+            logger.info("【职位体系】-检测到批量初定数据,条数: {}", dynamicObjectCollection.size());
+            for (int i = 0; i < dynamicObjectCollection.size(); i++) {
+                DynamicObject dynamicObject = dynamicObjectCollection.get(i);
+                logger.info("【职位体系】-处理第 {} 条数据", i+1);
                 //批量初定
                 BaseInitialData data = getBaseInitialData(dynamicObject);
                 dataList.add(data);
                 baseInitialData.add(data);
             }
         }else{
+            logger.info("【职位体系】-处理单条初定数据");
             BaseInitialData data = getBaseInitialData(initialData);
             dataList.add(data);
             baseInitialData.add(data);
         }
+        logger.info("【职位体系】-基本信息提取完成,共提取 {} 条数据", dataList.size());
         return dataList;
     }
 
     @NotNull
     private BaseInitialData getBaseInitialData(DynamicObject initialData) {
         BaseInitialData data = new BaseInitialData();
+        logger.info("【职位体系】-开始获取基础数据");
 
         data.beginDate = initialData.getDate(PositionStructureConstant.NCKD_BEGINDATE);
         data.causeRemark = initialData.getString(PositionStructureConstant.KEY_NCKD_CAUSEREMARK);
         data.person = initialData.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
 
         PositionAppointmentBO positionAppointment = PositionFileHelper.positionAppointmentQuery(data.person.getLong(FormConstant.ID_KEY), data.beginDate);
+        logger.info("【职位体系】-获取人员任职信息完成,personId={}", data.person.getLong(FormConstant.ID_KEY));
+        
         // 学历
         DynamicObject perEduExp = positionAppointment.getPerEduExp();
         if (perEduExp != null) {
             // 学历
             long diplomaId = perEduExp.getLong(String.join(".", FormConstant.EDUCATION_KEY, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取学历信息,diplomaId={}", diplomaId);
             if(diplomaId > 0) {
                 DynamicObject diploma = BusinessDataServiceHelper.newDynamicObject(PositionStructureConstant.HBSS_DIPLOMA);
                 diploma.set(FormConstant.ID_KEY, diplomaId);
                 data.diploma = diploma;
             }
+        } else {
+            logger.info("【职位体系】-无学历信息");
         }
+        
         // 职称信息
         DynamicObject perProTitle = positionAppointment.getPerProTitle();
         if (perProTitle != null) {
             data.rankName = perProTitle.getString(String.join(".", FormConstant.PROFESSIONAL_KEY, FormConstant.NAME_KEY));
+            logger.info("【职位体系】-获取职称信息,rankName={}", data.rankName);
+            
             // 职称等级
             long perProTitleId = perProTitle.getLong(String.join(".", FormConstant.PROLEVEL_KEY, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取职称等级,perProTitleId={}", perProTitleId);
             if(perProTitleId > 0) {
                 DynamicObject proTitleLevel = BusinessDataServiceHelper.newDynamicObject(PositionStructureConstant.HBSS_PROTITLELEVEL);
                 proTitleLevel.set(FormConstant.ID_KEY, perProTitleId);
                 data.proTitleLevel = proTitleLevel;
             }
+        } else {
+            logger.info("【职位体系】-无职称信息");
         }
 
         // 技能信息
         DynamicObject perOcpQual = positionAppointment.getPerOcpQual();
         if (perOcpQual != null) {
             data.jobStatusName = perOcpQual.getString(String.join(".", FormConstant.QUALIFICATION_KEY, FormConstant.NAME_KEY));
+            logger.info("【职位体系】-获取技能信息,jobStatusName={}", data.jobStatusName);
+            
             // 技能等级
             long quaLevelId = perOcpQual.getLong(String.join(".", FormConstant.QUALEVEL_KEY, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取技能等级,quaLevelId={}", quaLevelId);
             if(quaLevelId > 0) {
                 DynamicObject ocpQualLevel = BusinessDataServiceHelper.newDynamicObject(PositionStructureConstant.HBSS_OCPQUALLEVEL);
                 ocpQualLevel.set(FormConstant.ID_KEY, quaLevelId);
                 data.ocpQualLevel = ocpQualLevel;
             }
-
+        } else {
+            logger.info("【职位体系】-无技能信息");
         }
+        
         // 任职信息
         DynamicObject empPosOrgRel = positionAppointment.getEmpPosOrgRel();
         if (empPosOrgRel != null) {
             data.empPosOrgRel = empPosOrgRel;
+            logger.info("【职位体系】-获取任职信息完成");
+            
             //岗位
             long positionId = empPosOrgRel.getLong(String.join(".", FormConstant.POSITION_KEY, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取岗位信息,positionId={}", positionId);
             if(positionId > 0) {
                 DynamicObject position = BusinessDataServiceHelper.newDynamicObject(FormConstant.HBPM_POSITIONHR);
                 position.set(FormConstant.ID_KEY, positionId);
@@ -195,12 +227,15 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
             }
 
             long companyId = empPosOrgRel.getLong(String.join(".", FormConstant.COMPANY_KEY, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取公司信息,companyId={}", companyId);
             if(companyId > 0) {
                 DynamicObject company = BusinessDataServiceHelper.newDynamicObject(FormConstant.ADMINORG_ENTITYID);
                 company.set(FormConstant.ID_KEY, companyId);
                 data.company = company;
             }
+            
             long adminOrgId = empPosOrgRel.getLong(String.join(".", FormConstant.ADMINORG, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取部门信息,adminOrgId={}", adminOrgId);
             if(adminOrgId > 0) {
                 DynamicObject dep = BusinessDataServiceHelper.newDynamicObject(FormConstant.ADMINORG_ENTITYID);
                 dep.set(FormConstant.ID_KEY, adminOrgId);
@@ -209,6 +244,7 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
 
             // 职位序列
             Long jobSeqId = empPosOrgRel.getLong(String.join(".", FormConstant.HBPM_POSITIONHR, FormConstant.NCKD_JOBSEQ, FormConstant.ID_KEY));
+            logger.info("【职位体系】-获取职位序列信息,jobSeqId={}", jobSeqId);
             if(jobSeqId > 0) {
                 String jobSeqNumber = empPosOrgRel.getString(String.join(".", FormConstant.HBPM_POSITIONHR, FormConstant.NCKD_JOBSEQ, FormConstant.NUMBER_KEY));
                 String jobSeqName = empPosOrgRel.getString(String.join(".", FormConstant.HBPM_POSITIONHR, FormConstant.NCKD_JOBSEQ, FormConstant.NAME_KEY));
@@ -220,20 +256,25 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
                 data.jobSeqNumber = jobSeqNumber;
                 data.jobSeqName = jobSeqName;
                 data.jobSeqEnum = JobSeqEnum.getByCode(data.jobSeqNumber);
+                logger.info("【职位体系】-职位序列编号={},名称={}", jobSeqNumber, jobSeqName);
             }
 
-
-
             //本次加入集团时间
             data.joinComDate = empPosOrgRel.getDate(String.join(".", FormConstant.HRPI_PERSERLEN, FormConstant.JOINCOMDATE_KEY));
+            logger.info("【职位体系】-本次加入集团时间={}", data.joinComDate);
+        } else {
+            logger.info("【职位体系】-无任职信息");
         }
 
         data.isExcellent = Boolean.FALSE;
         if(positionAppointment.getExcellent() != null && positionAppointment.getExcellent()){
             data.isExcellent = Boolean.TRUE;
+            logger.info("【职位体系】-该员工为优秀生");
         }
+        
         // 特定字段由子类处理
         extractSpecificFields(data, initialData);
+        logger.info("【职位体系】-基础数据获取完成");
         return data;
     }
 
@@ -275,6 +316,7 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
      * 获取积分数据
      */
     protected ScoreData getScoreData(BaseInitialData data, String logPrefix) {
+        logger.info("{}-开始获取积分数据", logPrefix);
         ScoreData scoreData = new ScoreData();
 
         QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create().addIdNumberNameWithExtras(FormConstant.NCKD_SCORE);
@@ -282,6 +324,7 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         // 学历积分
         scoreData.educationScore = BigDecimal.ZERO;
         if (data.diploma != null) {
+            logger.info("{}-开始获取学历积分,diplomaId={}", logPrefix, data.diploma.getLong(FormConstant.ID_KEY));
             DynamicObject education = BusinessDataServiceHelper.loadSingle(FormConstant.HBSS_DIPLOMA,
                     queryFieldBuilder.buildSelect(),
                     new QFilter[]{QFilterCommonHelper.getIdEqFilter(data.diploma.getLong(FormConstant.ID_KEY))});
@@ -302,30 +345,41 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         scoreData.dbProTitleLevel = null;
         scoreData.dbOcpQualLevel = null;
 
-
+        logger.info("{}-职位序列类型={}, proTitleLevel={}, ocpQualLevel={}", 
+                   logPrefix, data.jobSeqEnum, data.proTitleLevel, data.ocpQualLevel);
 
         if (data.jobSeqEnum != JobSeqEnum.SKILL && data.proTitleLevel != null) {
             // 非技能序列获取职称积分
+            logger.info("{}-开始获取职称积分", logPrefix);
             scoreData.dbProTitleLevel = BusinessDataServiceHelper.loadSingle(FormConstant.HBSS_PROTITLELEVEL,
                     queryFieldBuilder.buildSelect(),
                     new QFilter[]{QFilterCommonHelper.getIdEqFilter(data.proTitleLevel.getLong(FormConstant.ID_KEY))});
             if (scoreData.dbProTitleLevel != null) {
                 scoreData.proTitleScore = scoreData.dbProTitleLevel.getBigDecimal(FormConstant.NCKD_SCORE);
                 data.jobStatusName = null;
+                logger.info("{}-职称积分获取完成,积分为{}", logPrefix, scoreData.proTitleScore);
+            } else {
+                logger.warn("{}-未找到职称等级信息", logPrefix);
             }
         } else if (data.jobSeqEnum == JobSeqEnum.SKILL && data.ocpQualLevel != null) {
             // 技能序列获取技能积分
+            logger.info("{}-开始获取技能积分", logPrefix);
             scoreData.dbOcpQualLevel = BusinessDataServiceHelper.loadSingle(FormConstant.HBSS_OCPQUALLEVEL,
                     queryFieldBuilder.buildSelect(),
                     new QFilter[]{QFilterCommonHelper.getIdEqFilter(data.ocpQualLevel.getLong(FormConstant.ID_KEY))});
             if (scoreData.dbOcpQualLevel != null) {
                 scoreData.perOcpQualScore = scoreData.dbOcpQualLevel.getBigDecimal(FormConstant.NCKD_SCORE);
                 data.rankName = null;
+                logger.info("{}-技能积分获取完成,积分为{}", logPrefix, scoreData.perOcpQualScore);
+            } else {
+                logger.warn("{}-未找到技能等级信息", logPrefix);
             }
+        } else {
+            logger.info("{}-无需获取职称或技能积分", logPrefix);
         }
 
-        logger.info("{}-初定职位序列【{}】-职称积分【{}】-技能积分【{}】",
-                logPrefix, data.jobSeqName, scoreData.proTitleScore, scoreData.perOcpQualScore);
+        logger.info("{}-初定职位序列【{}】-学历积分【{}】-职称积分【{}】-技能积分【{}】",
+                logPrefix, data.jobSeqName, scoreData.educationScore, scoreData.proTitleScore, scoreData.perOcpQualScore);
 
         return scoreData;
     }
@@ -355,12 +409,15 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
     protected DynamicObject createAndSavePersonPosFile(BaseInitialData data, ScoreData scoreData,
                                              BigDecimal allSumScore, BigDecimal sumScore, 
                                              DynamicObject jobLeve, String logPrefix, String typeState) {
+        logger.info("{}-开始创建并保存职位档案", logPrefix);
         // 优秀生得2分
         BigDecimal excellentScore = data.isExcellent ? new BigDecimal(2) : BigDecimal.ZERO;
+        logger.info("{}-优秀生分数: {}", logPrefix, excellentScore);
 
         // 构建职位档案并存入数据库
         DynamicObject personPosFile = BusinessDataServiceHelper.newDynamicObject(
                 PositionStructureConstant.PERSONPOSFILE_ENTITYID);
+        logger.info("{}-创建职位档案对象完成", logPrefix);
 
         personPosFile.set(PositionStructureConstant.NCKD_PERSON, data.person);
         personPosFile.set(PositionStructureConstant.NCKD_FIRSTRANK, EnableEnum.YES.getCode());
@@ -380,18 +437,24 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         personPosFile.set(PositionStructureConstant.NCKD_DEP, data.dep);
         personPosFile.set(PositionStructureConstant.NCKD_ALLSUMSCORE, allSumScore);
         personPosFile.set(PositionStructureConstant.NCKD_SUMSCORE, sumScore);
+        logger.info("{}-设置基本字段完成,总积分={}, 累计积分={}", logPrefix, allSumScore, sumScore);
 
         DynamicObject convertJobSeq = data.convertJobSeq;
         JobSeqEnum jobSeqEnum = JobSeqEnum.getByCode(convertJobSeq.getString(FormConstant.NUMBER_KEY));
+        logger.info("{}-转换后的职位序列类型={}", logPrefix, jobSeqEnum);
+        
         if(JobSeqEnum.SKILL == jobSeqEnum){
             personPosFile.set(PositionStructureConstant.NCKD_JOBSTATUSNAME, data.jobStatusName);
             personPosFile.set(PositionStructureConstant.NCKD_OCPQUALLEVEL, scoreData.dbOcpQualLevel);
             personPosFile.set(PositionStructureConstant.NCKD_JOBSTATUSSCORE, scoreData.perOcpQualScore);
+            logger.info("{}-设置技能序列相关信息完成", logPrefix);
         }else{
             personPosFile.set(PositionStructureConstant.NCKD_RANKNAME, data.rankName);
             personPosFile.set(PositionStructureConstant.NCKD_PROTITLELEVEL, scoreData.dbProTitleLevel);
             personPosFile.set(PositionStructureConstant.NCKD_RANKSCORE, scoreData.proTitleScore);
+            logger.info("{}-设置非技能序列相关信息完成", logPrefix);
         }
+        
         personPosFile.set(PositionStructureConstant.NCKD_JOBLEVELHR, jobLeve);
         personPosFile.set(PositionStructureConstant.NCKD_DIPLOMA, data.diploma);
         personPosFile.set(PositionStructureConstant.NCKD_TYPESTATE, typeState);
@@ -405,9 +468,21 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         personPosFile.set(PositionStructureConstant.STATUS, StatusEnum.C.toString());
         personPosFile.set(PositionStructureConstant.ENABLE, EnableEnum.YES.getCode());
         personPosFile.set(PositionStructureConstant.CREATOR_KEY, RequestContext.get().getCurrUserId());
-
-
-        SaveServiceHelper.save(new DynamicObject[]{personPosFile});
+        logger.info("{}-设置所有字段完成", logPrefix);
+
+//        SaveServiceHelper.save(new DynamicObject[]{personPosFile});
+        OperationResult operationResult = SaveServiceHelper.saveOperate(PositionStructureConstant.PERSONPOSFILE_ENTITYID, new DynamicObject[]{personPosFile}, OperateOption.create());
+        if (!operationResult.isSuccess()) {
+            StringJoiner errorMsg = new StringJoiner("\n");
+            for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+                errorMsg.add(error.getMessage());
+            }
+            if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
+                errorMsg.add(operationResult.getMessage());
+            }
+            throw new ValidationException("保存职位档案失败,原因:" + errorMsg.toString());
+        }
+        logger.info("{}-职位档案保存完成,ID={}", logPrefix, personPosFile.getLong(FormConstant.ID_KEY));
         return personPosFile;
     }
 

+ 21 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/NewHireInitialOperationPlugIn.java

@@ -139,9 +139,12 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
      * 处理单个在职人员初定
      */
     private void processNewHireInitialData() {
+        logger.info("【职位体系】-开始处理新入职人员初定");
 
         List<DynamicObject> savePersonPosFileList = Lists.newArrayList();
-        for (BaseInitialData data : baseInitialData) {
+        for (int i = 0; i < baseInitialData.size(); i++) {
+            BaseInitialData data = baseInitialData.get(i);
+            logger.info("【职位体系】-处理第{}个新入职人员初定", i+1);
 
             String logPrefix = StrFormatter.format("【职位体系】-新入职人员初定-人员【{}({})】",
                     data.person.getString(FormConstant.NAME_KEY),
@@ -153,9 +156,11 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
                     data.positionHr.getString(FormConstant.NAME_KEY));
 
             // 获取上年度绩效结果
+            logger.info("{}-开始获取上年度绩效结果", logPrefix);
             getPreviousYearPerformance(data, logPrefix);
 
             // 获取学历、职称、技能对应的积分
+            logger.info("{}-开始获取积分数据", logPrefix);
             ScoreData scoreData = getScoreData(data, logPrefix);
 
             // 优秀生得2分
@@ -165,34 +170,49 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
             BigDecimal allSumScore = scoreData.educationScore.add(scoreData.proTitleScore).add(scoreData.perOcpQualScore).add(excellentScore);
             logger.info("{}-学历分 + 职称/技能分 + 优秀生分 = {}", logPrefix, allSumScore);
             // 计算累计积分池(生涯积分)
+            logger.info("{}-开始计算累计积分池", logPrefix);
             BigDecimal sumScore = calculateSumScore(allSumScore, scoreData, logPrefix);
 
             // 计算职级
             //当考核结果为无时,职级定为最低级
             boolean useMinLevel = data.lastYearAppraisalResultEnum == nckd.jxccl.base.common.enums.AppraisalResultEnum.NONE;
             // 如果是管理序列,则按职能序列进行初定
+            logger.info("{}-开始处理职位序列转换", logPrefix);
             data.convertJobSeq = JobLevelCalculatorService.handleJobSeq(data.jobSeq);
+            logger.info("{}-职位序列转换完成,convertJobSeq={}", logPrefix, data.convertJobSeq);
+            
             //【三期需求】-不满足三要素(聘任职称/技能、考核结果、积分)按"无职级"初定
             String perProTitleNumber = scoreData.dbProTitleLevel != null ? scoreData.dbProTitleLevel.getString(FormConstant.NUMBER_KEY) : null;
             String quaLevelNumber = scoreData.dbOcpQualLevel != null ? scoreData.dbOcpQualLevel.getString(FormConstant.NUMBER_KEY) : null;
             boolean threeElementMeet = JobLevelCalculatorService.checkThreeElementsRequirement(data.convertJobSeq, allSumScore, scoreData.dbProTitleLevel,
                     scoreData.dbOcpQualLevel, data.lastYearAppraisalResultEnum);
+                    
+            logger.info("{}-计算职级参数: convertJobSeq={}, allSumScore={}, perProTitleNumber={}, quaLevelNumber={}, downgradeNum={}, useMinLevel={}, !threeElementMeet={}",
+                       logPrefix, data.convertJobSeq, allSumScore, perProTitleNumber, quaLevelNumber, data.downgradeNum, useMinLevel, !threeElementMeet);
 
             DynamicObject jobLeve = JobLevelCalculatorService.getJobLevel(
                     data.convertJobSeq, allSumScore, perProTitleNumber,
                     quaLevelNumber,data.downgradeNum,useMinLevel,!threeElementMeet);
+            logger.info("{}-职级计算完成,jobLeve={}", logPrefix, jobLeve);
+            
             if(jobLeve != null) {
                 // 构建职位档案并存入数据库
+                logger.info("{}-开始创建并保存职位档案", logPrefix);
                 DynamicObject savePersonPosFile = createAndSavePersonPosFile(data, scoreData, allSumScore, sumScore, jobLeve, logPrefix, "1");
                 savePersonPosFileList.add(savePersonPosFile);
                 //返回定级后的职级
                 setJobLevelResult(data.person, jobLeve);
+                logger.info("{}-职位档案创建并保存完成", logPrefix);
 
                 //TODO 【待修改】-职位体系-这里可能有协同,初定完成后需要将待办任务置为已完成
+            } else {
+                logger.warn("{}-未能计算出有效职级,跳过创建职位档案", logPrefix);
             }
         }
         //职位津贴
+        logger.info("【职位体系】-开始生成职位津贴,处理数量: {}", savePersonPosFileList.size());
         ManagerAllowanceService.generateMgrPostAllow(savePersonPosFileList);
+        logger.info("【职位体系】-新入职人员初定处理完成");
 
     }
 

+ 20 - 2
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/ServingInitialOperationPlugIn.java

@@ -147,9 +147,13 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
      * 处理单个在职人员初定
      */
     private void processServingInitial() {
+        logger.info("【职位体系】-开始处理在职人员初定");
         List<DynamicObject> savePersonPosFileList = Lists.newArrayList();
         // 提取基本信息
-        for (BaseInitialData data : baseInitialData) {
+        for (int i = 0; i < baseInitialData.size(); i++) {
+            BaseInitialData data = baseInitialData.get(i);
+            logger.info("【职位体系】-处理第{}个在职人员初定", i+1);
+            
             String logPrefix = StrFormatter.format("【职位体系】-在职人员初定-人员【{}({})】",
                     data.person.getString(FormConstant.NAME_KEY),
                     data.person.getString(FormConstant.EMP_NUMBER_KEY));
@@ -161,17 +165,21 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
                     data.allSumScore.toString());
 
             // 获取上年度绩效结果
+            logger.info("{}-开始获取上年度绩效结果", logPrefix);
             getPreviousYearPerformance(data, logPrefix);
 
             // 获取学历、职称、技能对应的积分
+            logger.info("{}-开始获取积分数据", logPrefix);
             ScoreData scoreData = getScoreData(data, logPrefix);
 
             // 计算累计积分池(生涯积分)
+            logger.info("{}-开始计算累计积分池", logPrefix);
             BigDecimal sumScore = calculateSumScore(data.allSumScore, scoreData, logPrefix);
 
             // 如果是管理序列,则按职能序列进行初定
+            logger.info("{}-开始处理职位序列转换", logPrefix);
             data.convertJobSeq = JobLevelCalculatorService.handleJobSeq(data.jobSeq);
-
+            logger.info("{}-职位序列转换完成,convertJobSeq={}", logPrefix, data.convertJobSeq);
 
             // 计算职级
             //当考核结果为无时,职级定为最低级
@@ -180,20 +188,30 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
             String quaLevelNumber = scoreData.dbOcpQualLevel != null ? scoreData.dbOcpQualLevel.getString(FormConstant.NUMBER_KEY) : null;
             boolean threeElementMeet = JobLevelCalculatorService.checkThreeElementsRequirement(data.convertJobSeq, data.allSumScore, scoreData.dbProTitleLevel,
                     scoreData.dbOcpQualLevel, data.lastYearAppraisalResultEnum);
+            logger.info("{}-计算职级参数: convertJobSeq={}, allSumScore={}, perProTitleNumber={}, quaLevelNumber={}, downgradeNum={}, useMinLevel={}, !threeElementMeet={}",
+                       logPrefix, data.convertJobSeq, data.allSumScore, perProTitleNumber, quaLevelNumber, data.downgradeNum, useMinLevel, !threeElementMeet);
+                       
             DynamicObject jobLeve = JobLevelCalculatorService.getJobLevel(
                     data.convertJobSeq, data.allSumScore, perProTitleNumber,
                     quaLevelNumber,  data.downgradeNum,useMinLevel,!threeElementMeet);
+            logger.info("{}-职级计算完成,jobLeve={}", logPrefix, jobLeve);
 
             if(jobLeve != null) {
                 // 构建职位档案并存入数据库
+                logger.info("{}-开始创建并保存职位档案", logPrefix);
                 DynamicObject savePersonPosFile = createAndSavePersonPosFile(data, scoreData, data.allSumScore, sumScore, jobLeve, logPrefix, "2");
                 savePersonPosFileList.add(savePersonPosFile);
                 //返回定级后的职级。张三:职位级为"初级(1)"
                 setJobLevelResult(data.person, jobLeve);
+                logger.info("{}-职位档案创建并保存完成", logPrefix);
+            } else {
+                logger.warn("{}-未能计算出有效职级,跳过创建职位档案", logPrefix);
             }
         }
         //职位津贴
+        logger.info("【职位体系】-开始生成职位津贴,处理数量: {}", savePersonPosFileList.size());
         ManagerAllowanceService.generateMgrPostAllow(savePersonPosFileList);
+        logger.info("【职位体系】-在职人员初定处理完成");
     }
 
     @Override

+ 1 - 9
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/other/NewAppointMentOpPlugin.java

@@ -161,11 +161,7 @@ public class NewAppointMentOpPlugin extends AbstractOperationServicePlugIn imple
                 ));
         List<DynamicObject> newEntityList = new ArrayList<>();
 
-        DynamicObject org = OrgHelper.getCreateOrg(PositionStructureConstant.PERSONPOSFILE_ENTITYID);
-        String bdCtrlStrgy = null;
-        if(org != null) {
-            bdCtrlStrgy = OrgHelper.getBdCtrlStrgy(PositionStructureConstant.PERSONPOSFILE_ENTITYID, org.getLong(FormConstant.ID_KEY));
-        }
+
         for (DynamicObject entry : e.getDataEntities()) {
             DynamicObject newEntity = EntityHelper.newEntity(PositionStructureConstant.NCKD_PERSONPOSFILE);
             DynamicObject person = entry.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
@@ -182,10 +178,6 @@ public class NewAppointMentOpPlugin extends AbstractOperationServicePlugIn imple
             newEntity.set(PositionStructureConstant.NCKD_POSITIONHR, empPosOrgRel.get(PositionStructureConstant.POSITION_KEY));
             newEntity.set(PositionStructureConstant.NCKD_EXECUTEYEAR, beginDateDateTime.getYear());
             newEntity.set(PositionStructureConstant.NCKD_APPOINTSTATUS, "1");
-            newEntity.set(FormConstant.CREATEORG_KEY, org);
-            newEntity.set(FormConstant.ORG_KEY, org);
-            newEntity.set(FormConstant.USEORG_KEY, org);
-            newEntity.set(FormConstant.CTRLSTRATEGY_KEY, bdCtrlStrgy);
             newEntity.set(FormConstant.CREATOR_KEY, UserServiceHelper.getCurrentUserId());
             newEntity.set(FormConstant.DESCRIPTION_KEY, entry.get(FormConstant.DESCRIPTION_KEY));
             newEntityList.add(newEntity);

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

@@ -0,0 +1,355 @@
+package nckd.jxccl.hr.psms.task;
+
+import com.alibaba.fastjson.JSON;
+import kd.bos.common.enums.EnableEnum;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.OperateOption;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.utils.ObjectUtils;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.MainEntityType;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.exception.KDException;
+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.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.sdk.plugin.Plugin;
+import kd.sdk.swc.hcdm.business.helper.HCDMApplyBillServiceHelper;
+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.AdjustTypeEnum;
+import nckd.jxccl.base.common.enums.psms.TypeStateEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+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.entity.helper.EntityHelper;
+import nckd.jxccl.base.swc.helper.AdjFileServiceHelper;
+import nckd.jxccl.hr.psms.common.PositionStructureConstant;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.StringJoiner;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * 职位体系推送薪酬
+ *
+ * @author W.Y.C
+ * @version 1.0
+ * @date 2025/12/21 15:01
+ */
+public class PsmsAdjustSalaryTask extends AbstractTask implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(PsmsAdjustSalaryTask.class);
+
+
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        //1:为本月数据,2:为上月数据
+        Integer type = ConvertUtil.toInt(map.get("type"));
+        Date beginDateParam = ConvertUtil.toDate(map.get("beginDateParam"));
+        Date endDateParam = ConvertUtil.toDate(map.get("endDateParam"));
+        // 校验日期:要么都为空,要么都不为空
+        if ((beginDateParam == null && endDateParam != null) || (beginDateParam != null && endDateParam == null)) {
+            throw new ValidationException("日期参数错误-开始日期和结束日期必须同时为空或同时不为空");
+        }
+
+        QFilter filter = new QFilter(PositionStructureConstant.NCKD_DISABLE, QCP.equals, EnableEnum.NO.getCode())
+                .and(PositionStructureConstant.NCKD_TYPESTATE, QCP.in, new String[]{TypeStateEnum.NEW_ENTRY.getCode(),TypeStateEnum.IN_SERVICE_LEVEL.getCode(),TypeStateEnum.ANNUAL_ADJUSTMENT.getCode(),TypeStateEnum.POSITION_TRANSFER.getCode()});
+        Date beginDate = null;
+        Date endDate = null;
+        if(beginDateParam != null && endDateParam != null){
+            beginDate = DateUtil.beginOfDay(beginDateParam);
+            endDate = DateUtil.endOfDay(endDateParam);
+        }else{
+            LocalDateTime now = DateUtil.now();
+            if(type == 2){
+                now = DateUtil.minusMonths(now, 1);
+            }else if(type == 1){
+                //本月
+            }else{
+                throw new ValidationException("参数错误-type,只能为1或2");
+            }
+            beginDate = DateUtil.toDate(DateUtil.beginOfMonth(now));
+            endDate = DateUtil.toDate(DateUtil.endOfMonth(now));
+        }
+        filter.and(FormConstant.CREATE_TIME_KEY,QCP.large_equals,beginDate);
+        filter.and(FormConstant.CREATE_TIME_KEY,QCP.less_equals,new Date());
+
+        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                .add(FormConstant.ID_KEY)
+                .addIdNumberName(FormConstant.NCKD_PERSON)
+                .add(PositionStructureConstant.NCKD_ISSALADJPUSH)
+                .add(PositionStructureConstant.NCKD_BEGINDATE)
+                .add(PositionStructureConstant.CREATE_TIME_KEY)
+                .addIdNumberNameWithExtras(new String[]{PositionStructureConstant.NCKD_JOBLEVELHR},PositionStructureConstant.JOBLEVELSEQ,PositionStructureConstant.NCKD_COEFFICIENT)
+                .addIdNumberName(PositionStructureConstant.NCKD_LASTPERSONPOSFILE,PositionStructureConstant.NCKD_JOBLEVELHR)
+                .orderDesc(FormConstant.CREATE_TIME_KEY);
+        DynamicObjectCollection personPosFileColl = QueryServiceHelper.query(PositionStructureConstant.PERSONPOSFILE_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+        // 按人员分组,Map<Long,List<DynamicObject>>
+        Map<Long, List<DynamicObject>> personPosFileMap = personPosFileColl.stream()
+                .collect(Collectors.groupingBy(
+                        obj -> obj.getLong(String.join(".", PositionStructureConstant.NCKD_PERSON, FormConstant.ID_KEY))
+                ));
+        //需要推送调薪的员工档案id
+        List<Long> needAdjustSalaryId = new ArrayList<>();
+        List<Long> needPersonId = new ArrayList<>();
+        List<Long> jobLevelIds = new ArrayList<>();
+        // 处理每个员工的记录
+        for (Map.Entry<Long, List<DynamicObject>> entry : personPosFileMap.entrySet()) {
+            List<DynamicObject> records = entry.getValue();
+            // 在当前员工的所有记录中,找出beginDate~endDate范围内CREATE_TIME_KEY最新的那条记录
+            Date finalBeginDate = beginDate;
+            Date finalEndDate = endDate;
+            Optional<DynamicObject> latestRecordOpt = records.stream()
+                    .filter(record -> {
+                        Date createTime = record.getDate(PositionStructureConstant.CREATE_TIME_KEY);
+                        return createTime != null &&
+                                !createTime.before(finalBeginDate) &&
+                                !createTime.after(finalEndDate);
+                    })
+                    .max(Comparator.comparing(record -> record.getDate(PositionStructureConstant.CREATE_TIME_KEY)));
+
+            // 如果找到了时间范围内的最新记录
+            if (latestRecordOpt.isPresent()) {
+                DynamicObject latestRecord = latestRecordOpt.get();
+                Date latestCreateTime = latestRecord.getDate(PositionStructureConstant.CREATE_TIME_KEY);
+
+                // 检查在latestCreateTime到当前时间范围内,该员工是否有NCKD_ISSALADJPUSH=true的记录(有的话说明当前数据之后已经有推送薪酬了,这条不用推送)
+                boolean hasPushedRecord = records.stream()
+                        .filter(record -> {
+                            Date createTime = record.getDate(PositionStructureConstant.CREATE_TIME_KEY);
+                            return createTime != null &&
+                                    !createTime.before(latestCreateTime);
+                        })
+                        .anyMatch(record -> record.getBoolean(PositionStructureConstant.NCKD_ISSALADJPUSH));
+                // 如果在最新记录时间之后没有推送调薪的记录,则添加到需要推送调薪的列表中
+                if (!hasPushedRecord) {
+                    needAdjustSalaryId.add(latestRecord.getLong(FormConstant.ID_KEY));
+                    needPersonId.add(latestRecord.getLong(String.join(".", PositionStructureConstant.NCKD_PERSON, FormConstant.ID_KEY)));
+                    jobLevelIds.add(latestRecord.getLong(String.join(".", PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY)));
+                    //上一档案职级
+                    long lastJobLevel = latestRecord.getLong(String.join(".", PositionStructureConstant.NCKD_LASTPERSONPOSFILE, PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
+                    jobLevelIds.add(lastJobLevel);
+                }
+            }
+        }
+
+        if(!needAdjustSalaryId.isEmpty()){
+            //获取人员最新岗位工资标准定薪记录
+            List<AdjFileServiceHelper.SalaryAdjustmentResult> salaryAdjustmentResultList = AdjFileServiceHelper.getLastDecAdjRecords(needPersonId, FormConstant.STANDARDITEM_ID_KEY);
+            Map<Long,AdjFileServiceHelper.SalaryAdjustmentResult> salaryAdjustmentResultMap = new HashMap<>(salaryAdjustmentResultList.size());
+            if (!salaryAdjustmentResultList.isEmpty()) {
+                //薪酬标准ID
+                List<Long> salaryStIds = salaryAdjustmentResultList.stream().map(result -> result.salaryStDv.getLong(FormConstant.ID_KEY)).collect(Collectors.toList());
+                QFilter salaryStandardFilter = 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[]{salaryStandardFilter});
+                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);
+                            result.salaryRank = EntityHelper.newEntity(FormConstant.HSBS_SALARYRANK, 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) {
+                                //当前薪等01档的金额
+                                result.amount = stdTableDataMatchResults.get(i).getAmount();
+                                salaryAdjustmentResultMap.put(result.employee.getLong(FormConstant.ID_KEY), result);
+                            }
+                        }
+                    }
+                } else {
+                    logger.warn("未获取薪酬标准表中01档的薪档数据,薪酬标准ID:{}",salaryStIds);
+                }
+            } else {
+                logger.warn("未获取到人员岗位工资标准定薪记录,人员ID:{}",needPersonId);
+            }
+
+            if(!salaryAdjustmentResultMap.isEmpty()){
+                Map<Long, DynamicObject> jobLevelMap = new HashMap<>(jobLevelIds.size());
+                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
+                            ));
+                }
+
+                List<DynamicObject> updatePersonPosFile = new ArrayList<>();
+                MainEntityType personPosFileEntityType = EntityMetadataCache.getDataEntityType(PositionStructureConstant.PERSONPOSFILE_ENTITYID);
+                DynamicObject[] personPosFileArray = BusinessDataServiceHelper.load(needAdjustSalaryId.toArray(), personPosFileEntityType);
+                for (DynamicObject personPosFile : personPosFileArray) {
+                    long jobLevelId = personPosFile.getLong(String.join(".", PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
+                    long lastJobLevelId = personPosFile.getLong(String.join(".",PositionStructureConstant.NCKD_LASTPERSONPOSFILE, PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
+                    DynamicObject jobLevel = jobLevelMap.get(jobLevelId);
+                    DynamicObject lastJobLevel = jobLevelMap.get(lastJobLevelId);
+
+                    if(jobLevel != null) {
+                        DynamicObject person = personPosFile.getDynamicObject(FormConstant.NCKD_PERSON);
+                        Date date = personPosFile.getDate(PositionStructureConstant.NCKD_BEGINDATE);
+                        AdjFileServiceHelper.SalaryAdjustmentResult salaryAdjustmentResult = salaryAdjustmentResultMap.get(person.getLong(FormConstant.ID_KEY));
+                        if (salaryAdjustmentResult != null && salaryAdjustmentResult.amount.compareTo(BigDecimal.ZERO) > 0) {
+                            BigDecimal coefficient = jobLevel.getBigDecimal(PositionStructureConstant.NCKD_COEFFICIENT);
+                            BigDecimal finalAmount = BigDecimal.ZERO;
+                            if(coefficient.compareTo(BigDecimal.ZERO) > 0) {
+                                //职位津贴=职位系数 X 所在岗级岗位工资一档金额
+                                finalAmount = coefficient.multiply(salaryAdjustmentResult.amount);
+                            }
+
+
+                            //触发定调薪
+                            Map<String, Object> applyBill = new HashMap<>();
+                            applyBill.put("billname", StrFormatter.format("【{}】的职位体系调整(职位津贴)",person.getString(FormConstant.NAME_KEY)));
+                            Long orgId = RequestContext.get().getOrgId();
+
+                            String uniquecode = UUID.randomUUID().toString().replace("-", "");
+                            applyBill.put("_uniquecode", uniquecode);
+                            if(salaryAdjustmentResult.hcdmOrg != null){
+                                applyBill.put("org", salaryAdjustmentResult.hcdmOrg.getLong(FormConstant.ID_KEY));
+                            }else{
+                                applyBill.put("org", orgId);
+                            }
+
+                            //定调薪明细字段显示方案   调薪明细字段
+                            applyBill.put("billtype", 2215975998602655744L);
+                            //国家
+                            applyBill.put("billcountry", 1000001L);
+                            //定调薪类型
+                            applyBill.put("salaryadjrsn", 2352338490244480000L);
+                            //默认币种
+                            applyBill.put("billcurrency", 1L);
+                            //定调薪方案
+                            applyBill.put("salaryadjscm", 2322515162646457344L);
+                            //汇率日期
+                            applyBill.put("exchangeratedate", new Date());
+                            //汇率表
+                            applyBill.put("exctable", 2321965096026258432L);
+                            //默认生效日期
+                            applyBill.put("effectivedate", date);
+                            //草稿状态
+                            applyBill.put("isdraft", "1");
+                            //审核状态
+                            applyBill.put("auditstatus", "A");
+                            //申请单数据来源   //1:手工新增  2:接口写入
+                            applyBill.put("datasource", "2");
+
+                            String typeStateStr = personPosFile.getString(PositionStructureConstant.NCKD_TYPESTATE);
+                            TypeStateEnum typeState = TypeStateEnum.getByCode(typeStateStr);
+                            String adjustTypeStr = personPosFile.getString(PositionStructureConstant.NCKD_ADJUSTTYPE);
+                            AdjustTypeEnum adjustType = AdjustTypeEnum.getByCode(adjustTypeStr);
+                            String description = StrFormatter.format("【{}】执行【{}】,调整生效时间【{}】,调整类别【{}】,由【{}({})】 -> 【{}({}级)】。系数【{}】",
+                                    DateUtil.format(personPosFile.getDate(FormConstant.CREATE_TIME_KEY),DateUtil.NORM_DATETIME_PATTERN),
+                                    typeState.getName(),
+                                    DateUtil.format(personPosFile.getDate(PositionStructureConstant.NCKD_BEGINDATE),DateUtil.NORM_DATE_PATTERN),
+                                    adjustType != null ? adjustType.getName() : "初定",
+                                    lastJobLevel == null ? "无" : lastJobLevel.getString(FormConstant.NAME_KEY),
+                                    lastJobLevel == null ? "无" : lastJobLevel.getString(FormConstant.JOBLEVELSEQ)+"级",
+                                    jobLevel.getString(FormConstant.NAME_KEY),
+                                    jobLevel.getString(FormConstant.JOBLEVELSEQ),
+                                     coefficient
+                            );
+                            applyBill.put("description", description);
+                            List<Map<String, Object>> applyBillEntryData = new ArrayList<>();
+                            Map<String, Object> applyBillEntry = new HashMap<>();
+                            Long employeeId = person.getLong(FormConstant.ID_KEY);
+                            Long positionId = personPosFile.getLong(String.join(".",PositionStructureConstant.NCKD_POSITIONHR, FormConstant.ID_KEY));
+                            applyBillEntry.put("adjfile", salaryAdjustmentResult.adjFileInfo.getLong(FormConstant.ID_KEY));
+                            applyBillEntry.put("employee", employeeId);
+                            applyBillEntry.put("standarditem", 2321901533681170432L);    //定调薪项目   职位系数
+                            applyBillEntry.put("frequency", 1095454108284088320L);       //频度  月
+                            applyBillEntry.put("amount", finalAmount);
+                            applyBillEntry.put("position", positionId);
+                            applyBillEntry.put("joblevel", jobLevel.getLong(FormConstant.ID_KEY));
+                            applyBillEntry.put("salarygrade", salaryAdjustmentResult.salaryGrade.getLong(FormConstant.ID_KEY));
+                            applyBillEntry.put("salaryrank", salaryAdjustmentResult.salaryRank.getLong(FormConstant.ID_KEY));
+                            applyBillEntry.put("reason", description);
+                            applyBillEntryData.add(applyBillEntry);
+                            applyBill.put("applybillent", applyBillEntryData);
+                            List<Map<String, Object>> applyBillData = new ArrayList<>();
+                            applyBillData.add(applyBill);
+                            Map<String, Object> papams = new HashMap<>();
+                            papams.put("data", applyBillData);
+                            papams.put("isUseMatchAmount", Boolean.TRUE);
+                            Map<String, Object> result = HCDMApplyBillServiceHelper.saveDraftApplyBill(papams);
+                            if (!ConvertUtil.toBoolean(result.get("success")) || result.get("data") == null || ConvertUtil.toList(result.get("data")).isEmpty()) {
+                                throw new ValidationException("【"+person.getString(FormConstant.NAME_KEY)+"】推送定调薪失败,原因:" + JSON.toJSONString(result));
+                            }else{
+                                personPosFile.set(PositionStructureConstant.NCKD_ISSALADJPUSH, Boolean.TRUE);
+                                personPosFile.set(PositionStructureConstant.NCKD_SALADJPUSHTIME, new Date());
+                                personPosFile.set(PositionStructureConstant.NCKD_SALADJID, ConvertUtil.toMap(ConvertUtil.toList(result.get("data")).get(0)).get("id"));
+                                personPosFile.set(PositionStructureConstant.NCKD_SALADJNUMBER, null);
+
+                                updatePersonPosFile.add(personPosFile);
+                            }
+                        } else {
+                            logger.warn("未获取到员工【{}】最新岗位工资标准定薪记录01档的薪等金额,人员ID:", person.getString(FormConstant.NAME_KEY));
+                        }
+                    }
+                }
+
+                if(!updatePersonPosFile.isEmpty()){
+                    OperationResult operationResult = SaveServiceHelper.saveOperate(PositionStructureConstant.PERSONPOSFILE_ENTITYID, updatePersonPosFile.toArray(new DynamicObject[0]), OperateOption.create());
+                    if (!operationResult.isSuccess()) {
+                        StringJoiner errorMsg = new StringJoiner("\n");
+                        for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+                            errorMsg.add(error.getMessage());
+                        }
+                        if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
+                            errorMsg.add(operationResult.getMessage());
+                        }
+                        throw new ValidationException("保存职位档案失败,原因:" + errorMsg.toString());
+                    }
+                }
+            }
+        }else{
+            logger.warn("没有需要推送的调薪数据");
+        }
+    }
+}

+ 1 - 1
code/nckd-cosmic-debug/src/main/java/kd/cosmic/debug/tools/CosmicLauncher.java

@@ -43,7 +43,7 @@ public final class CosmicLauncher {
      */
     private static final String DEFAULT_COSMIT_HOME_PATH = System.getProperty("user.home").replaceAll("\\\\", "/") + "/cosmic/home";
 	
-	private static final String PROJECT_HOME = "E:/2.work/xuding/jxccl";
+	private static final String PROJECT_HOME = "D:/jxcc/workspace/jtcosmic";
 	
 	private static final String LOCAL_IP = "127.0.0.1";
 	

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

@@ -1,5 +1,6 @@
 package nckd.jxccl.opmc.pm.plugin.operate.salary;
 
+import com.alibaba.fastjson.JSON;
 import kd.bos.context.RequestContext;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.db.tx.TX;
@@ -155,8 +156,8 @@ public class PushAdjustOpPlugin extends AbstractOperationServicePlugIn implement
             papams.put("data", applyBillData);
             papams.put("isUseMatchAmount", Boolean.TRUE);
             Map<String, Object> result = HCDMApplyBillServiceHelper.saveDraftApplyBill(papams);
-            if (!ConvertUtil.toBoolean(result.get("success"))) {
-                throw new ValidationException("推送定调薪失败,原因:" + result.get("message").toString());
+            if (!ConvertUtil.toBoolean(result.get("success")) || result.get("data") == null || ConvertUtil.toList(result.get("data")).isEmpty()) {
+                throw new ValidationException("推送定调薪失败,原因:" + JSON.toJSONString(result));
             }
         }
     }

+ 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);

+ 1 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/business/coordination/SinsurCoordSplitService.java

@@ -144,6 +144,7 @@ public class SinsurCoordSplitService {
      */
     public void writeBackSourceBill (DynamicObject bill) {
         bill.set("dealresult", "9");
+        SitConstant.COORDVERIFYBILL_HELPER.update(new DynamicObject[]{bill});
     }
 
     /**

+ 1 - 1
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/business/datacomparison/DataComparisonQueryService.java

@@ -91,7 +91,7 @@ public class DataComparisonQueryService {
     public DataSet queryAllCalPersonAndWelfareTypeByTaskId(List<Long> taskIds) {
         // 获取核算任务下的所有人
         QFilter filter = new QFilter("sinsurtask.id", QCP.in, taskIds);
-        String selectFields = "welfarepayer.id as welfarepayer, empnumberdb as empnumber,namedb as empname,percre.number as empidcard,employee.id as employee, '1' as flag ";
+        String selectFields = "welfarepayer.id as welfarepayer, empnumberdb as empnumber,namedb as empname,percrenum as empidcard,employee.id as employee, '1' as flag ";
         DataSet dataSet1 = SitConstant.CALPERSON_HELPER.queryDataSet("queryAllCalPerson", selectFields, filter.toArray());
 
         // 获取所有险种

+ 21 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/formplugin/web/coordination/HCSIEmpCoordVerifBillListEx.java

@@ -0,0 +1,21 @@
+package nckd.jxccl.sit.hcsi.formplugin.web.coordination;
+
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.list.plugin.AbstractListPlugin;
+
+public class HCSIEmpCoordVerifBillListEx extends AbstractListPlugin {
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs afterDoOperationEventArgs) {
+        super.afterDoOperation(afterDoOperationEventArgs);
+        String key = afterDoOperationEventArgs.getOperateKey();
+        switch(key) {
+            case "donothing_split":
+                afterDoSplit(afterDoOperationEventArgs);
+        }
+    }
+
+    private void afterDoSplit(AfterDoOperationEventArgs afterDoOperationEventArgs) {
+        this.getView().invokeOperation("refresh");
+    }
+}

+ 1 - 1
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/utils/ReportUtils.java

@@ -24,7 +24,7 @@ public class ReportUtils {
     //参保单位,险种,工号,姓名,证件号,单位缴费金额 = 单位固定+单位缴费+单位补缴,个人缴费金额=个人固定+个人缴费+个人补缴
     //2025-11-17调整 单位缴费金额 = 单位固定+单位缴费,单位补缴金额 = 单位补缴,个人缴费金额=个人固定+个人缴费;个人补缴 = 个人补缴;
     private static String CALPERSON_FIELDS = "welfarepayer.id as welfarepayer,entryentity.insuranceitem.group.id as welfaretypeid,"
-            +"empnumberdb as empnumber,namedb as empname,percre.number as empidcard,employee.id as employee,"
+            +"empnumberdb as empnumber,namedb as empname,percrenum as empidcard,employee.id as employee,"
             +"case when entryentity.insuranceitem.insurancetypeattr.number in ('1006_S','1005_S','1009_S','1010_S') then entryentity.amountvalue else 0 end as value,"
             +"case when entryentity.insuranceitem.insurancetypeattr.number in ('1011_S','1012_S') then entryentity.amountvalue else 0 end as value1,"
             +"case when entryentity.insuranceitem.insurancetypeattr.number in ('1005_S','1009_S','1011_S') then '1'"

+ 23 - 5
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/hcdm/opplugin/annualincome/SalAnnualIncomeUpdatePlugin.java

@@ -54,8 +54,23 @@ public class SalAnnualIncomeUpdatePlugin extends AbstractOperationServicePlugIn
                         obj -> obj.getLong("groupId") + "_" + obj.getLong("employeeId"), // 构造唯一键
                         obj -> obj  // 保留原始对象
                 ));
-        Set<String> keySet = resultMap.keySet();
+        Set<String> allKeySet = resultMap.keySet();
         DynamicObjectCollection entryCols = bill.getDynamicObjectCollection("nckd_entryentity");
+        Map<String, DynamicObject> currentMap = entryCols.stream()
+                .collect(Collectors.toMap(
+                        obj -> obj.getLong("nckd_payrollgrp.id") + "_" + obj.getLong("nckd_employee.id"), // 构造唯一键
+                        obj -> obj  // 保留原始对象
+                ));
+        Set<String> currentKeySet = currentMap.keySet();
+
+
+        Set<String> updateKeySet = allKeySet.stream()
+                .filter(currentKeySet::contains)
+                .collect(Collectors.toSet());
+        Set<String> addnewSet = allKeySet.stream()
+                .filter(key -> !currentKeySet.contains(key))
+                .collect(Collectors.toSet());
+
         for (DynamicObject entry : entryCols) {
             // 如果当前分录推送状态不为【社保未拉取】则继续
             if(!entry.getString("nckd_pushstatus").equals("0")) {
@@ -67,13 +82,16 @@ public class SalAnnualIncomeUpdatePlugin extends AbstractOperationServicePlugIn
             String key = groupId + "_" + employeeId;
 
             // 根据唯一键获取,如果不存在则新增一行记录
-            if(keySet.contains(key)) {
+            if(updateKeySet.contains(key)) {
                 doUpdateEntry(entry,resultMap.get(key));
             }
-            else {
-                doAddnewEntry(entryCols.addNew(), resultMap.get(key));
-            }
         }
+
+        //处理新增分录
+        for (String key : addnewSet) {
+            doAddnewEntry(entryCols.addNew(),resultMap.get(key));
+        }
+
     }
 
     /**

+ 87 - 4
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/business/SynPendingSalaryAdjDataServiceImpl.java

@@ -121,8 +121,8 @@ public class SynPendingSalaryAdjDataServiceImpl implements SynPendingSalaryAdjDa
 
         QFilter qFilter22 = new QFilter("nckd_billid", QCP.in, onhasonbrdIDs);
         List<Object> listIDs = QueryServiceHelper.queryPrimaryKeys(FormConstant.NCKD_PENDINGSALARYADJ,new QFilter[]{qFilter22}, null, Integer.MAX_VALUE);
-        DynamicObject billDyn =  BusinessDataServiceHelper.newDynamicObject(FormConstant.NCKD_PENDINGSALARYADJ);
-        DynamicObject[] billDyns = BusinessDataServiceHelper.load(listIDs.toArray(),billDyn.getDynamicObjectType());
+        DynamicObject billDynType =  BusinessDataServiceHelper.newDynamicObject(FormConstant.NCKD_PENDINGSALARYADJ);
+        DynamicObject[] billDyns = BusinessDataServiceHelper.load(listIDs.toArray(),billDynType.getDynamicObjectType());
 
         int onhasonbrdCount = 0;
         Map<Long, DynamicObject> billMap =
@@ -180,7 +180,6 @@ public class SynPendingSalaryAdjDataServiceImpl implements SynPendingSalaryAdjDa
 
         QFilter qFilter15 = new QFilter("nckd_billid", QCP.in, transferIDs);
         List<Object> transferlistIDs = QueryServiceHelper.queryPrimaryKeys(FormConstant.NCKD_PENDINGSALARYADJ,new QFilter[]{qFilter15}, null, Integer.MAX_VALUE);
-        DynamicObject billDynType =  BusinessDataServiceHelper.newDynamicObject(FormConstant.NCKD_PENDINGSALARYADJ);
         DynamicObject[] billDyns1 = BusinessDataServiceHelper.load(transferlistIDs.toArray(),billDynType.getDynamicObjectType());
 
         int transferCount = 0;
@@ -238,12 +237,96 @@ public class SynPendingSalaryAdjDataServiceImpl implements SynPendingSalaryAdjDa
             billDynList.add(dyn);
         }
 
+
+        /**
+         * 批量调动
+         */
+        String selectField3 = "id,billno,entryentity.b_effectivedate,createtime,entryentity.bb_em_tid as bb_em_tid,entryentity.ba_em_empnumber,entryentity.bb_po_position.boid,entryentity.aposition.boid,entryentity.bb_po_adminorg.boid,entryentity.aorg.boid,entryentity.aorg.belongcompany.id";
+        QFilter qFilter31 = new QFilter("billstatus", QCP.equals, "C");
+        QFilter qFilter32 = new QFilter("entryentity.transfereffectstatus", QCP.equals, "2");  //同步结果 =  同步成功
+        QFilter qFilter33 = new QFilter("entryentity.b_effectivedate", QCP.large_equals, daysAgo);
+        QFilter qFilter34 = new QFilter("entryentity.b_effectivedate", QCP.less_equals, currentDate);
+        QFilter qFilter35 = new QFilter("entryentity.aposition.nckd_paystdplan.name", QCP.equals, "江铜集团岗位绩效工资制");
+        DynamicObjectCollection transferBatchDyns = QueryServiceHelper.query(FormConstant.HDM_TRANSFERBATCH, selectField3,new QFilter[]{qFilter31,qFilter32,qFilter33,qFilter34,qFilter35});
+
+        Map<Long, DynamicObject> transferBatchMap = (Map)transferBatchDyns.stream().collect(Collectors.toMap((obj) -> {
+            return obj.getLong("id");
+        }, (obj) -> {
+            return obj;
+        }, (k1, k2) -> {
+            return k1;
+        }));
+        List<Long> transferBatchIDs = transferBatchMap.keySet().stream().collect(Collectors.toList());
+
+        QFilter qFilter38 = new QFilter("nckd_billid", QCP.in, transferBatchIDs);
+        List<Object> transferBatchlistIDs = QueryServiceHelper.queryPrimaryKeys(FormConstant.NCKD_PENDINGSALARYADJ,new QFilter[]{qFilter38}, null, Integer.MAX_VALUE);
+        DynamicObject[] billDyns3 = BusinessDataServiceHelper.load(transferBatchlistIDs.toArray(),billDynType.getDynamicObjectType());
+
+        int transferBatchCount = 0;
+        Map<Long, DynamicObject> billMap3 =
+                Arrays.stream(billDyns3)
+                        .collect(Collectors.toMap(
+                                detail -> detail.getLong("nckd_billid"),
+                                detail -> detail, // 整个 DynamicObject 作为 value
+                                (existing, replacement) -> existing // 保留前面的值
+                        ));
+
+        Map<Long, DynamicObject> adjRecordMap3 = getAdjRecordInfo(transferBatchDyns);
+
+        for(DynamicObject transferDyn: transferBatchDyns) {
+            DynamicObject billDyn3 = billMap3.get(transferDyn.getLong("id"));
+
+            if(billDyn3 != null) {
+                continue;
+            }
+            DynamicObject dyn = new DynamicObject(entityType);
+            Long employeeID = transferDyn.getLong("bb_em_tid");
+            dyn.set("billno", transferDyn.getString("billno"));
+            dyn.set("nckd_billid", transferDyn.getLong("id"));
+            dyn.set("nckd_billtype", "调动单");
+            dyn.set("billstatus", "A");  ///待处理
+            dyn.set("nckd_employeefield", employeeID);
+            dyn.set("nckd_hrorg", transferDyn.getLong("entryentity.aorg.belongcompany.id"));  //薪酬管理组织 来源  调后部门中的公司
+            dyn.set("nckd_changedate", transferDyn.getDate("entryentity.b_effectivedate"));
+            dyn.set("nckd_dodatetime", transferDyn.getDate("createtime"));
+            dyn.set("nckd_salaryadjus", salaryTypeDyns.get(1).getLong("id"));  //定调薪类型
+            /**
+             * 调动前
+             */
+            dyn.set("nckd_oldhradminorg", transferDyn.getLong("entryentity.bb_po_adminorg.boid"));  //部门
+            dyn.set("nckd_oldposition", transferDyn.getLong("entryentity.bb_po_position.boid"));  //岗位
+            DynamicObject adjRecordDyn  = adjRecordMap3.get(employeeID);
+            if(adjRecordDyn != null) {
+                dyn.set("nckd_oldsalaryrank", adjRecordDyn.getLong("salaryrank.id"));  //薪档
+            }
+            /**
+             * 调动后
+             */
+            dyn.set("nckd_newhradminorg", transferDyn.getLong("entryentity.aorg.boid"));  //部门
+            dyn.set("nckd_newposition", transferDyn.getLong("entryentity.aposition.boid"));  //岗位
+            //判断薪档是否改变
+            boolean isChange = calaSararyRank(transferDyn.getLong("entryentity.bb_po_position.boid"), transferDyn.getLong("entryentity.aposition.boid"));
+            if(isChange) {
+                dyn.set("nckd_newsalaryrank", salaryRankDyn.getLong("id"));   //薪档
+            }else{
+                if(adjRecordDyn != null) {
+                    dyn.set("nckd_newsalaryrank", adjRecordDyn.getLong("salaryrank.id"));
+                }
+            }
+
+            transferBatchCount++;
+            billDynList.add(dyn);
+
+        }
+
+
+
         int length = 0;
         if(billDynList.size() != 0) {
             //保存
             Object[] update = SaveServiceHelper.save(billDynList.toArray(new DynamicObject[0]));
             length = update.length;
-            errorInfo.append("成功导入,"+length+"条数据,其中入职单"+onhasonbrdCount+"条,调动单"+transferCount+"条"); // 成功类型
+            errorInfo.append("成功导入,"+length+"条数据,其中入职单"+onhasonbrdCount+"条,调动单"+transferCount+transferBatchCount+"条"); // 成功类型
         }else{
             errorInfo.append("没有导入数据");
         }

+ 13 - 5
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/utils/SwcUtils.java

@@ -9,6 +9,7 @@ import kd.bos.orm.query.QFilter;
 import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
 import nckd.jxccl.swc.constants.SwcConstant;
 
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.ZoneId;
@@ -66,8 +67,8 @@ public class SwcUtils {
 
     public static StringBuilder getSalaryDetailSql(List<Long> groupIds, Date startDate, Date endDate) {
         String ids = String.join(",",groupIds.stream().map(String::valueOf).toArray(String[]::new));
-        String startDateStr = dateToStr(startDate);
-        String endDateStr = dateToStr(endDate);
+        String startDateStr = dateToStr(startDate, 1);
+        String endDateStr = dateToStr(endDate, 2);
 
         StringBuilder sb = new StringBuilder();
         sb.append("/*dialect*/ SELECT a.fid groupId,\n" +
@@ -109,9 +110,16 @@ public class SwcUtils {
         return excludeGroupIds;
     }
 
-    public static String dateToStr(Date date) {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        return sdf.format(date);
+    public static String dateToStr(Date date, int type) {
+        if(type == 1) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            return sdf.format(date);
+        }
+        else {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            String dateStr = sdf.format(date);
+            return dateStr + " 23:59:59";
+        }
     }
 
 }

Неке датотеке нису приказане због велике количине промена