Quellcode durchsuchen

feat(hr): 新增年度贡献积分计算功能

- 在ConvertUtil工具类中新增toDynamicObjectOrNull转换方法
- 将PositionStructureHelper重命名为PositionFileHelper并更新相关引用- 新增ContributionEvaluationConstant常量类定义积分相关字段标识
- 创建ContributionHelper辅助类实现积分计算逻辑
- 开发ContribBillFormPlugin表单插件处理积分录入与计算
- 新增ScoreItemConfFormPlugin插件支持积分项目配置依赖关系
wyc vor 1 Monat
Ursprung
Commit
d08be3ddd0
27 geänderte Dateien mit 913 neuen und 191 gelöschten Zeilen
  1. 17 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ConvertUtil.java
  2. 3 3
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/AnnualAdjustmentService.java
  3. 4 4
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/JobLevelCalculatorService.java
  4. 31 4
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/ContributionEvaluationConstant.java
  5. 397 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/ContributionHelper.java
  6. 1 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/PositionFileHelper.java
  7. 5 5
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/adjust/NewDynamicAdjustmentDiaLogFormPlugin.java
  8. 6 4
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/annualadjust/UnAnnualAdjustListPlugin.java
  9. 178 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/contribution/ContribBillFormPlugin.java
  10. 69 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/contribution/ScoreItemConfFormPlugin.java
  11. 2 6
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/NewHireInitialFormPlugin.java
  12. 2 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/ServingInitialFormPlugin.java
  13. 1 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/UngradedPersonQueryListPlugin.java
  14. 2 13
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/performance/PerfrankMgmtFormPlugin.java
  15. 6 6
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/adjust/NewDynamicAdjustmentOperationPlugIn.java
  16. 6 6
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualAdjustmentOperationPlugin.java
  17. 3 3
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualEffectiveOpPlugin.java
  18. 30 44
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualLockOrUnLockedOpPlugin.java
  19. 3 3
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualSetinActiveOpPlugin.java
  20. 134 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/contribution/ContribBillOpPlugin.java
  21. 0 74
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/contribution/validate/ScoreItemConfValidate.java
  22. 3 3
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/file/PersonPosFileDeleteOpPlugin.java
  23. 2 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/BaseInitialOperationPlugIn.java
  24. 2 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/NewHireInitialOperationPlugIn.java
  25. 2 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/ServingInitialOperationPlugIn.java
  26. 2 4
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/validate/PerfRankMgmtSaveValidate.java
  27. 2 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/report/adjust/UnAdjustedReportReportListDataPlugin.java

+ 17 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ConvertUtil.java

@@ -693,6 +693,23 @@ public class ConvertUtil {
         return defaultValue;
     }
 
+    /**
+     * 将对象转换为DynamicObject类型,为空时返回null
+     * @param value 要转换的对象
+     * @return 转换后的DynamicObject值,输入为null时返回null
+     * @author W.Y.C
+     * @date: 2025/08/04 12:05
+     */
+    public static DynamicObject toDynamicObjectOrNull(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof DynamicObject) {
+            return (DynamicObject) value;
+        }
+        return null;
+    }
+
     /**
      * 将对象转换为DynamicObject类型
      * @param value 要转换的对象

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

@@ -18,7 +18,7 @@ import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
@@ -247,7 +247,7 @@ public class AnnualAdjustmentService {
         data.setRankingResultInfo(rankingInfo);
 
         //4.查询上一条有效年度调整记录(对应SHR:PersonpositionfileUtils:946~997行)
-        DynamicObject[] personPosFileByPersonAndState = PositionStructureHelper.getPersonPosFileByPersonAndState(ac.personId,
+        DynamicObject[] personPosFileByPersonAndState = PositionFileHelper.getPersonPosFileByPersonAndState(ac.personId,
                 new String[]{"3","4"},
                 null,null,
                 QueryFieldBuilder.create()
@@ -393,7 +393,7 @@ public class AnnualAdjustmentService {
      */
     private static void evaluateFirstAndAppraisalUsage(AdjustmentContext ac) {
 
-        DynamicObject nowYearPersonPosFile = PositionStructureHelper.getLatsPersonPosFileByPerson(ac.personId, new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR, QCP.equals, ac.nowYear));
+        DynamicObject nowYearPersonPosFile = PositionFileHelper.getLatsPersonPosFileByPerson(ac.personId, new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR, QCP.equals, ac.nowYear));
 
         boolean isyearfirstdo = false;
         if (nowYearPersonPosFile != null) {

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

@@ -27,7 +27,7 @@ import nckd.jxccl.base.pm.helper.PerformanceManagerHelper;
 import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
@@ -91,7 +91,7 @@ public class JobLevelCalculatorService {
 
         // 1. 获取最近的职位档案(必须存在,否则抛错)
         //对应SHR:personpositionfileInfo
-        DynamicObject currentPersonPosFile = PositionStructureHelper.getLatsPersonPosFileByPerson(personId);
+        DynamicObject currentPersonPosFile = PositionFileHelper.getLatsPersonPosFileByPerson(personId);
         if(currentPersonPosFile == null){
             throw new ValidationException(StrFormatter.format("当前无法为【{}】进行调整,因为他/她尚未建立职位档案。请前往“职位及积分初定” -> 进行初定!", person.getString(FormConstant.NAME_KEY)));
         }
@@ -251,7 +251,7 @@ public class JobLevelCalculatorService {
         String lastYearAppraisalResultNumber = lastYearAppraisalResult != null ? lastYearAppraisalResult.getString(FormConstant.NUMBER_KEY) : null;
         //当前年度职位档案;
         // 对应SHR:nowyearpersonpositionfileCollection
-        DynamicObject currentYearPersonPosFileByPerson = PositionStructureHelper.getLatsPersonPosFileByPerson(personId,new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR,QCP.equals,year));
+        DynamicObject currentYearPersonPosFileByPerson = PositionFileHelper.getLatsPersonPosFileByPerson(personId,new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR,QCP.equals,year));
         //对应SHR:newpersonfirstrank
         //对应SHR:878行
         boolean newPersonFirstRank = isNewPersonFirstRank(date, personId);
@@ -561,7 +561,7 @@ public class JobLevelCalculatorService {
      * @date: 2025/09/20 19:04
      */
     private static boolean isNewPersonFirstRank(Date beginYear, long personId) {
-        DynamicObject firstRankDynamicObject = PositionStructureHelper.getFirstRank(personId);
+        DynamicObject firstRankDynamicObject = PositionFileHelper.getFirstRank(personId);
         if(firstRankDynamicObject == null){
             throw new ValidationException(StrFormatter.format("未获取到人员【{}】首次初定档案", personId));
         }

+ 31 - 4
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/ContributionEvaluationConstant.java

@@ -13,12 +13,39 @@ import nckd.jxccl.base.common.constant.FormConstant;
 */
 public class ContributionEvaluationConstant extends FormConstant {
 
-    /** 积分项目配置-实体标识 */
-    public static final String SCOREITEMCONF_ENTITYID = "nckd_scoreitemconf";
+
+
+
+
+    /** 年度贡献积分单据-实体标识 */
+    public static final String CONTRIBBILL_ENTITYID = "nckd_contribbill";
+    /** 单据体 */
+    public static final String NCKD_CONTRIBBILLENTRY = "NCKD_CONTRIBBILLENTRY";
+    /** 原始分数 */
+    public static final String NCKD_ORISCORE = "NCKD_ORISCORE";
+    /** 录入积分 */
+    public static final String NCKD_SCORE = "NCKD_SCORE";
+    /** 二级单位 */
+    public static final String NCKD_ADMINORG = "NCKD_ADMINORG";
+    /** 姓名 */
+    public static final String NCKD_PERSON = "NCKD_PERSON";
+    /** 参与人数 */
+    public static final String NCKD_PARTICIPANTS = "NCKD_PARTICIPANTS";
+    /** 积分所属年度 */
+    public static final String NCKD_YEAR = "NCKD_YEAR";
     /** 积分项目 */
     public static final String NCKD_SCOREITEM = "NCKD_SCOREITEM";
+    /** 积分具体项目 */
+    public static final String NCKD_SCOREITEMSUB = "NCKD_SCOREITEMSUB";
+    /** 积分项目名次 */
+    public static final String NCKD_SCOREITEMRANK = "NCKD_SCOREITEMRANK";
+
+
+
+    /*-------------------------------------- 积分项目分数配置 begin --------------------------------------*/
+    /** 积分项目分数配置-实体标识 */
+    public static final String SCOREITEMCONF_ENTITYID = "nckd_scoreitemconf";
     /** 最高分数 */
     public static final String NCKD_MAXSCORE = "NCKD_MAXSCORE";
-    /** 级别 */
-    public static final String NCKD_AWARDLEVEL = "NCKD_AWARDLEVEL";
+    /*-------------------------------------- 积分项目分数配置 begin --------------------------------------*/
 }

+ 397 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/ContributionHelper.java

@@ -0,0 +1,397 @@
+package nckd.jxccl.hr.psms.helper;
+
+import kd.bos.algo.Algo;
+import kd.bos.algo.AlgoContext;
+import kd.bos.algo.DataSet;
+import kd.bos.algo.Row;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+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.utils.DateUtil;
+import nckd.jxccl.base.common.utils.QueryFieldBuilder;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.psms.common.ContributionEvaluationConstant;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 年度贡献积分辅助类
+ * @author W.Y.C
+ * @date 2025/10/26 13:34
+ * @version 1.0
+ */
+public class ContributionHelper {
+
+    /**
+     * 根据人员获取积分项目有效分数
+     * 依据人员某年度已获得的积分(含在途单据)+积分配置的最高分计算出可获得的分数
+     *
+     * @param scoreItemValidScoreList 待计算列表
+     * @param year 年份
+     * @param excludeBillId 排除的单据ID(计算有效分数不含当前单据),可为空
+     * @return: ScoreItemValidScore
+     * @author W.Y.C
+     * @date: 2025/10/26 13:38
+     */
+    public static List<ScoreItemValidScore> getScoreItemValidScore(List<ScoreItemValidScore> scoreItemValidScoreList, Date year, Long excludeBillId) {
+        if (scoreItemValidScoreList == null || scoreItemValidScoreList.isEmpty()) {
+            return scoreItemValidScoreList;
+        }
+
+        //获取积分项目分数配置
+        Map<Long, BigDecimal> scoreConfMap = getScoreConf();
+        //统计人员各项目已累计积分
+        Long[] personIdArray = scoreItemValidScoreList.stream()
+                .map(ScoreItemValidScore::getPersonId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .toArray(Long[]::new);
+
+        List<ScoreItemValidScore> scoreItemAccumulateScoreList = getScoreItemAccumulateScore(personIdArray, year, excludeBillId);
+
+        //按人员分组已累计积分数据,提高查找效率
+        Map<Long, List<ScoreItemValidScore>> personAccumulateScoreMap = scoreItemAccumulateScoreList.stream()
+                .collect(Collectors.groupingBy(ScoreItemValidScore::getPersonId));
+
+        for (ScoreItemValidScore scoreItemValidScore : scoreItemValidScoreList) {
+            if (scoreItemValidScore == null) {
+                continue;
+            }
+
+            Long personId = scoreItemValidScore.getPersonId();
+            Long scoreItemId = scoreItemValidScore.getScoreItemId();
+            Long scoreItemSubId = scoreItemValidScore.getScoreItemSubId();
+
+            //获取该人员的累计积分数据
+            List<ScoreItemValidScore> personAccumulateScores = personAccumulateScoreMap.getOrDefault(personId, new ArrayList<>());
+
+            //计算积分项目和具体项目累计分数
+            BigDecimal scoreItemSumScore = BigDecimal.ZERO;
+            BigDecimal scoreItemSubSumScore = BigDecimal.ZERO;
+
+            for (ScoreItemValidScore accumulateScore : personAccumulateScores) {
+                Long tempScoreItemId = accumulateScore.getScoreItemId();
+                Long tempScoreItemSubId = accumulateScore.getScoreItemSubId();
+
+                if (Objects.equals(tempScoreItemId, scoreItemId)) {
+                    scoreItemSumScore = scoreItemSumScore.add(accumulateScore.getSumScore());
+                    if (Objects.equals(tempScoreItemSubId, scoreItemSubId)) {
+                        scoreItemSubSumScore = accumulateScore.getSumScore();
+                    }
+                }
+            }
+
+            //根据配置决定使用哪种累计分数
+            BigDecimal sumScore = determineSumScore(scoreConfMap, scoreItemId, scoreItemSumScore, scoreItemSubSumScore);
+
+            BigDecimal validScore = calculateAvailableScore(scoreConfMap, scoreItemId, scoreItemSubId, sumScore);
+            scoreItemValidScore.setValidScore(validScore);
+            scoreItemValidScore.setSumScore(sumScore);
+        }
+        return scoreItemValidScoreList;
+    }
+
+    /**
+     * 根据人员、年度、积分项目、具体积分项目获取有效分数
+     * 依据人员某年度已获得的积分(含在途单据)+积分配置的最高分计算出可获得的分数
+     *
+     * @param scoreItemValidScore 待计算积分信息
+     * @param year                年份
+     * @param excludeBillId       排除的单据ID(计算有效分数不含当前单据),可为空
+     * @author W.Y.C
+     * @date: 2025/10/26 13:38
+     */
+    public static void getScoreItemValidScore(ScoreItemValidScore scoreItemValidScore, Date year, Long excludeBillId) {
+        if (scoreItemValidScore == null) {
+            return;
+        }
+
+        //复用批量处理方法
+        List<ScoreItemValidScore> inputList = new ArrayList<>();
+        inputList.add(scoreItemValidScore);
+        List<ScoreItemValidScore> result = getScoreItemValidScore(inputList, year, excludeBillId);
+    }
+
+    /**
+     * 根据人员和年度获取积分项目已累计分数
+     * @param personIds 人员
+     * @param year 年度
+     * @param excludeBillId 排除的单据ID(计算有效分数不含当前单据),可为空
+     * @return: List<ScoreItemValidScore> 积分项目已累计分数
+     * @author W.Y.C
+     * @date: 2025/10/26 16:20
+     */
+    public static List<ScoreItemValidScore> getScoreItemAccumulateScore(Long[] personIds, Date year, Long excludeBillId) {
+        if (personIds == null || personIds.length == 0) {
+            return new ArrayList<>();
+        }
+
+        LocalDateTime yearStarDateTime = DateUtil.beginOfYear(DateUtil.toLocalDateTime(year));
+        QueryFieldBuilder scoreItemConfFieldBuilder = QueryFieldBuilder.create()
+                .add(ContributionEvaluationConstant.NCKD_YEAR)
+                .addIdNumberName(ContributionEvaluationConstant.NCKD_SCOREITEM)
+                .addIdNumberName(ContributionEvaluationConstant.NCKD_SCOREITEMSUB)
+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY,ContributionEvaluationConstant.NCKD_PERSON},FormConstant.ID_KEY)
+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY}, ContributionEvaluationConstant.NCKD_SCORE,ContributionEvaluationConstant.NCKD_ORISCORE);
+
+        //查询非"审批不通过"、"已废弃"年度贡献积分
+        QFilter filter = new QFilter(FormConstant.BILL_STATUS_KEY, QCP.not_in, new String[]{"E", "F"})
+                .and(ContributionEvaluationConstant.NCKD_YEAR,QCP.large_equals,DateUtil.beginOfDay(yearStarDateTime))
+                .and(ContributionEvaluationConstant.NCKD_YEAR,QCP.less_equals, DateUtil.endOfDay(yearStarDateTime))
+                .and(String.join( ".",FormConstant.NCKD_ENTRYENTITY,ContributionEvaluationConstant.NCKD_PERSON),QCP.in,personIds);
+
+        if(excludeBillId != null && excludeBillId > 0){
+            filter.and(FormConstant.ID_KEY,QCP.not_equals,excludeBillId);
+        }
+
+        List<ScoreItemValidScore> scoreItemValidScoreList = new ArrayList<>();
+        try(AlgoContext context = Algo.newContext()) {
+            DataSet dateSet = QueryServiceHelper.queryDataSet(ContributionHelper.class.getName(),
+                    ContributionEvaluationConstant.CONTRIBBILL_ENTITYID,
+                    scoreItemConfFieldBuilder.buildSelect(),
+                    new QFilter[]{filter}, null, 5000);
+
+            DataSet sumDateSet = dateSet.copy()
+                    // 按人员、积分项目、积分项目子项进行分组
+                    .groupBy(new String[]{String.join(".", ContributionEvaluationConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_PERSON, FormConstant.ID_KEY),
+                            String.join(".", ContributionEvaluationConstant.NCKD_SCOREITEM, FormConstant.ID_KEY),
+                            String.join(".", ContributionEvaluationConstant.NCKD_SCOREITEMSUB, FormConstant.ID_KEY)})
+                    .sum(String.join(".", ContributionEvaluationConstant.NCKD_ENTRYENTITY, FormConstant.NCKD_SCORE),"sumScore").finish();
+
+            while (sumDateSet.hasNext()) {
+                Row row = sumDateSet.next();
+                Long personId = row.getLong(String.join(".", ContributionEvaluationConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_PERSON, FormConstant.ID_KEY));
+                Long scoreItemId = row.getLong(String.join(".", ContributionEvaluationConstant.NCKD_SCOREITEM, FormConstant.ID_KEY));
+                Long scoreItemSubId = row.getLong(String.join(".", ContributionEvaluationConstant.NCKD_SCOREITEMSUB, FormConstant.ID_KEY));
+                //已获得的累计积分
+                BigDecimal sumScore = row.getBigDecimal("sumScore");
+                ScoreItemValidScore scoreItemValidScore = new ScoreItemValidScore(personId, scoreItemId, scoreItemSubId, sumScore);
+                scoreItemValidScoreList.add(scoreItemValidScore);
+            }
+        }
+        return scoreItemValidScoreList;
+    }
+
+    /**
+     * 计算可获得的有效分数
+     * 基于累计总分和限制分数,计算还可以获得多少分数(不超过限制)
+     *
+     * @param scoreConfMap 分数配置映射表,key为配置ID,value为限分数值
+     * @param scoreItemId 积分项目ID
+     * @param scoreItemSubId 具体积分项目ID
+     * @param accumulatedScore 累计总分
+     * @return 可获得的有效分数
+     *         如果没有任何限制返回null
+     *         如果已超过限制返回BigDecimal.ZERO
+     *         否则返回剩余可加分数
+     * @author W.Y.C
+     * @date: 2025/10/26 16:53
+     */
+    private static BigDecimal calculateAvailableScore(Map<Long, BigDecimal> scoreConfMap, Long scoreItemId, Long scoreItemSubId, BigDecimal accumulatedScore) {
+        // 积分项目限分 - 如果没有找到则不限分
+        BigDecimal scoreItemMaxScore = scoreConfMap.get(scoreItemId);
+
+        // 具体积分项目限分 - 如果没有找到则不限分
+        BigDecimal scoreItemSubMaxScore = null;
+        if (scoreItemSubId != null && scoreItemSubId > 0) {
+            scoreItemSubMaxScore = scoreConfMap.get(scoreItemSubId);
+        }
+
+        // 处理累计分数的空值
+        BigDecimal actualAccumulatedScore = accumulatedScore == null ? BigDecimal.ZERO : accumulatedScore;
+
+        // 计算实际的最大限制
+        BigDecimal actualMaxScore = null;
+
+        // 检查具体积分项目限分是否存在且大于0
+        if (scoreItemSubMaxScore != null && scoreItemSubMaxScore.compareTo(BigDecimal.ZERO) > 0) {
+            actualMaxScore = scoreItemSubMaxScore;
+        }
+
+        // 检查积分项目限分是否存在且大于0
+        if (scoreItemMaxScore != null && scoreItemMaxScore.compareTo(BigDecimal.ZERO) > 0) {
+            if (actualMaxScore == null) {
+                actualMaxScore = scoreItemMaxScore;
+            } else {
+                // 双重限制,取较小值
+                actualMaxScore = actualMaxScore.min(scoreItemMaxScore);
+            }
+        }
+
+        // 如果没有限制,返回null
+        if (actualMaxScore == null) {
+            return null;
+        }
+
+        // 计算可获得的有效分数
+        BigDecimal availableScore;
+        if (actualAccumulatedScore.compareTo(actualMaxScore) >= 0) {
+            // 已经超过限制,不能再获得分数
+            availableScore = BigDecimal.ZERO;
+        } else {
+            // 计算剩余可加分数
+            availableScore = actualMaxScore.subtract(actualAccumulatedScore);
+        }
+
+        return availableScore;
+    }
+
+    /**
+     * 决定使用哪种累计分数
+     * @param scoreConfMap 分数配置映射
+     * @param scoreItemId 积分项目ID
+     * @param scoreItemSumScore 积分项目累计分数
+     * @param scoreItemSubSumScore 积分项目具体项目累计分数
+     * @return 应该使用的累计分数
+     */
+    private static BigDecimal determineSumScore(Map<Long, BigDecimal> scoreConfMap, Long scoreItemId,
+                                                BigDecimal scoreItemSumScore, BigDecimal scoreItemSubSumScore) {
+        BigDecimal scoreItemMaxScore = scoreConfMap.get(scoreItemId);
+        if (scoreItemMaxScore != null) {
+            //如果设置积分项目大类分数限制,则取大类的累计积分
+            return scoreItemSumScore;
+        } else {
+            //如果没有设置积分项目大类分数限制,则取小类的累计积分
+            return scoreItemSubSumScore;
+        }
+    }
+
+    /**
+     * 获取积分配置
+     * @return: java.util.Map<java.lang.Long, java.math.BigDecimal>;key为积分项目子项ID(项目子项为空时key为项目大项),value为积分项目对应的最大分数
+     * @author W.Y.C
+     * @date: 2025/10/26 13:38
+     */
+    public static Map<Long, BigDecimal> getScoreConf() {
+        //查询积分项目分数配置
+        QueryFieldBuilder scoreItemConfFieldBuilder = QueryFieldBuilder.create()
+                .addIdNumberName(FormConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_SCOREITEM)
+                .addIdNumberName(FormConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_SCOREITEMSUB)
+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY}, ContributionEvaluationConstant.NCKD_MAXSCORE);
+
+        DynamicObjectCollection scoreItemConfQuery = QueryServiceHelper.query(ContributionEvaluationConstant.SCOREITEMCONF_ENTITYID,
+                scoreItemConfFieldBuilder.buildSelect(),
+                new QFilter[]{QFilterCommonHelper.getEnableFilter()});
+
+        //scoreMap:key为积分项目子项ID(项目子项为空时key为项目大项),value为积分项目对应的最大分数
+        Map<Long, BigDecimal> scoreMap = scoreItemConfQuery.stream().collect(Collectors.toMap(
+                item -> {
+                    long scoreItemSubId = item.getLong(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_SCOREITEMSUB, FormConstant.ID_KEY));
+                    if (scoreItemSubId <= 0) {
+                        return item.getLong(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_SCOREITEM, FormConstant.ID_KEY));
+                    } else {
+                        return scoreItemSubId;
+                    }
+                },
+                item -> item.getBigDecimal(String.join(".", FormConstant.NCKD_ENTRYENTITY, ContributionEvaluationConstant.NCKD_MAXSCORE)),
+                //处理重复key的情况,取最大值
+                (existing, replacement) -> existing.max(replacement)
+        ));
+        return scoreMap;
+    }
+
+    public static class ScoreItemValidScore{
+        private Long personId;
+        private Long scoreItemId;
+        private Long scoreItemSubId;
+        /**本次积分*/
+        private BigDecimal currentScore;
+        private BigDecimal sumScore;
+        /** 可获得的有效分数(如果没有任何限制返回null,如果已超过限制返回0,否则返回剩余可加分数) */
+        private BigDecimal validScore;
+        //没有业务含义,只用来记录分录索引号;
+        private int rowIndex;
+
+        public ScoreItemValidScore(Long personId, Long scoreItemId, Long scoreItemSubId) {
+            this.personId = personId;
+            this.scoreItemId = scoreItemId;
+            this.scoreItemSubId = scoreItemSubId;
+        }
+
+        public ScoreItemValidScore(Long personId, Long scoreItemId, Long scoreItemSubId, BigDecimal sumScore) {
+            this.personId = personId;
+            this.scoreItemId = scoreItemId;
+            this.scoreItemSubId = scoreItemSubId;
+            this.sumScore = sumScore;
+        }
+
+        public ScoreItemValidScore(Long personId, Long scoreItemId, Long scoreItemSubId, BigDecimal sumScore, BigDecimal validScore) {
+            this.personId = personId;
+            this.scoreItemId = scoreItemId;
+            this.scoreItemSubId = scoreItemSubId;
+            this.sumScore = sumScore;
+            this.validScore = validScore;
+        }
+
+        public Long getPersonId() {
+            return personId;
+        }
+
+        public void setPersonId(Long personId) {
+            this.personId = personId;
+        }
+
+        public Long getScoreItemId() {
+            return scoreItemId;
+        }
+
+        public void setScoreItemId(Long scoreItemId) {
+            this.scoreItemId = scoreItemId;
+        }
+
+        public Long getScoreItemSubId() {
+            return scoreItemSubId;
+        }
+
+        public void setScoreItemSubId(Long scoreItemSubId) {
+            this.scoreItemSubId = scoreItemSubId;
+        }
+
+        public BigDecimal getSumScore() {
+            return sumScore;
+        }
+
+        public void setSumScore(BigDecimal sumScore) {
+            this.sumScore = sumScore;
+        }
+
+        public BigDecimal getValidScore() {
+            //为空时说明不限制分数
+            BigDecimal trulyValidScore = this.currentScore;
+            if(this.validScore != null){
+                //如果可使用分数超过录入分数则使用录入分数(oriScore),否则使用可使用分数
+                trulyValidScore = this.validScore.min(this.currentScore);
+            }
+            return trulyValidScore;
+        }
+
+        public void setValidScore(BigDecimal validScore) {
+            this.validScore = validScore;
+        }
+
+        public BigDecimal getCurrentScore() {
+            return currentScore;
+        }
+
+        public void setCurrentScore(BigDecimal currentScore) {
+            this.currentScore = currentScore;
+        }
+
+        public int getRowIndex() {
+            return rowIndex;
+        }
+
+        public void setRowIndex(int rowIndex) {
+            this.rowIndex = rowIndex;
+        }
+    }
+}

+ 1 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/PositionStructureHelper.java → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/helper/PositionFileHelper.java

@@ -26,7 +26,7 @@ import java.util.Map;
  * @version 1.0
  * @date 2025/9/13 14:07
  */
-public class PositionStructureHelper {
+public class PositionFileHelper {
 
 
     /**

+ 5 - 5
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/adjust/NewDynamicAdjustmentDiaLogFormPlugin.java

@@ -17,7 +17,7 @@ import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.hr.psms.business.JobLevelCalculatorService;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.time.LocalDateTime;
 import java.util.Date;
@@ -69,14 +69,14 @@ public class NewDynamicAdjustmentDiaLogFormPlugin extends AbstractFormPlugin {
                     Date adjustDate = ConvertUtil.toDate(this.getModel().getValue(PositionStructureConstant.NCKD_ADJUSTDATE));
                     DynamicObject person = ConvertUtil.toDynamicObject(this.getModel().getValue(PositionStructureConstant.NCKD_PERSON));
                     if(adjustDate != null && person.getDataEntityType() != null){
-                        DynamicObject latsPersonPosFileByPerson = PositionStructureHelper.getLatsPersonPosFileByPerson(person.getLong(FormConstant.ID_KEY));
+                        DynamicObject latsPersonPosFileByPerson = PositionFileHelper.getLatsPersonPosFileByPerson(person.getLong(FormConstant.ID_KEY));
                         if(latsPersonPosFileByPerson == null){
                             this.getView().showErrorNotification(StrFormatter.format("当前无法为【{}】进行动态调整,因为他/她尚未建立职位档案。请前往“职位及积分初定” -> 进行初定!", person.getString(FormConstant.NAME_KEY)));
                             clearFormInfo();
                         }else{
                             try{
                                 LocalDateTime endDay = DateUtil.endOfDay(DateUtil.toLocalDateTime(adjustDate));
-                                PositionAppointmentBO positionAppointment = PositionStructureHelper.positionAppointmentQuery(person.getLong(FormConstant.ID_KEY), DateUtil.toDate(endDay));
+                                PositionAppointmentBO positionAppointment = PositionFileHelper.positionAppointmentQuery(person.getLong(FormConstant.ID_KEY), DateUtil.toDate(endDay));
                                 JobLevelCalculatorService.JobLevelResult jobLevelResult = getJobLevel(person, adjustDate,positionAppointment);
 
                                 updateFormInfo(person, adjustDate, latsPersonPosFileByPerson,jobLevelResult,positionAppointment);
@@ -100,7 +100,7 @@ public class NewDynamicAdjustmentDiaLogFormPlugin extends AbstractFormPlugin {
         String personName = person.getString(FormConstant.NAME_KEY);
         // 1、获取员工职位档案信息
         // 对应SHR:personpositionfileInfo & appraisalCollection
-        DynamicObject currentPersonPosFile = PositionStructureHelper.getLatsPersonPosFileByPerson(personId);
+        DynamicObject currentPersonPosFile = PositionFileHelper.getLatsPersonPosFileByPerson(personId);
         if (currentPersonPosFile == null || currentPersonPosFile.getDataEntityType() == null) {
             throw new ValidationException(StrFormatter.format("当前无法为【{}】进行调整,因为他/她尚未建立职位档案。请前往“职位及积分初定” -> 进行初定!", personName));
         }
@@ -147,7 +147,7 @@ public class NewDynamicAdjustmentDiaLogFormPlugin extends AbstractFormPlugin {
         // 8、检查指定年份是否存在未生效的年度调整记录
         int currentYear = DateUtil.getYear(new Date());
         int year = DateUtil.getYear(date);
-        DynamicObject[] personPosFileByPersonAndState = PositionStructureHelper.getPersonPosFileByPersonAndState(personId,
+        DynamicObject[] personPosFileByPersonAndState = PositionFileHelper.getPersonPosFileByPersonAndState(personId,
                 new String[]{"3"},
                 null,
                 new QFilter(PositionStructureConstant.NCKD_ADJUSTTYPE, QCP.not_in, new String[]{"1", "2"}).and(new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR, QCP.in, new Integer[]{currentYear, year})));

+ 6 - 4
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/annualadjust/UnAnnualAdjustListPlugin.java

@@ -62,10 +62,12 @@ public class UnAnnualAdjustListPlugin extends AbstractListPlugin implements Plug
 
         LocalDateTime lastYear = DateUtil.minusYears(localDateTime, 1);
         QFilter qFilter = new QFilter(FormConstant.IS_PRIMARY, QCP.equals, EnableEnum.YES.getCode())
-                .and(new QFilter(String.join(".", FormConstant.ASSIGNMENT, FormConstant.IS_PRIMARY), QCP.equals, EnableEnum.YES.getCode()))
-                .and(new QFilter(String.join(".", FormConstant.ASSIGNMENT, FormConstant.IS_DELETED), QCP.equals, EnableEnum.NO.getCode()))
-                .and(new QFilter(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID, PositionStructureConstant.NCKD_DISABLE), QCP.equals, EnableEnum.NO.getCode()))
-                .and(new QFilter(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID, PositionStructureConstant.NCKD_ISCURRENTNEWEST), QCP.equals, EnableEnum.YES.getCode()))
+                .and(FormConstant.IS_SEQLATESTRECORD, QCP.equals, EnableEnum.YES.getCode())
+                .and(FormConstant.IS_DELETED, QCP.equals, EnableEnum.NO.getCode())
+                .and(String.join(".", FormConstant.ASSIGNMENT, FormConstant.IS_PRIMARY), QCP.equals, EnableEnum.YES.getCode())
+                .and(String.join(".", FormConstant.ASSIGNMENT, FormConstant.IS_DELETED), QCP.equals, EnableEnum.NO.getCode())
+                .and(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID, PositionStructureConstant.NCKD_DISABLE), QCP.equals, EnableEnum.NO.getCode())
+                .and(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID, PositionStructureConstant.NCKD_ISCURRENTNEWEST), QCP.equals, EnableEnum.YES.getCode())
                 //有初定的人员
                 .and(new QFilter(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID+"init", PositionStructureConstant.NCKD_FIRSTRANK), QCP.equals, EnableEnum.YES.getCode()))
                 //初定时间不等于当年

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

@@ -0,0 +1,178 @@
+package nckd.jxccl.hr.psms.plugin.form.contribution;
+
+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.field.BasedataEdit;
+import kd.bos.form.field.events.BeforeF7SelectEvent;
+import kd.bos.form.field.events.BeforeF7SelectListener;
+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.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.hr.psms.common.ContributionEvaluationConstant;
+import nckd.jxccl.hr.psms.helper.ContributionHelper;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.EventObject;
+import java.util.List;
+import java.util.Objects;
+
+/**
+* 年度贡献积分单据-表单插件
+* 实体标识:nckd_contribbill
+* @author W.Y.C
+* @date 2025/10/25 22:57
+* @version 1.0
+*/
+public class ContribBillFormPlugin extends AbstractFormPlugin implements Plugin, BeforeF7SelectListener {
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+        // 积分具体项目字段添加值变化监听
+        BasedataEdit scoreItemSubField = this.getView().getControl(ContributionEvaluationConstant.NCKD_SCOREITEMSUB);
+        if (scoreItemSubField != null) {
+            scoreItemSubField.addBeforeF7SelectListener(this);
+        }
+
+        BasedataEdit scoreItemRankField = this.getView().getControl(ContributionEvaluationConstant.NCKD_SCOREITEMRANK);
+        if (scoreItemRankField != null) {
+            scoreItemRankField.addBeforeF7SelectListener(this);
+        }
+    }
+
+    @Override
+    public void beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent) {
+        String fieldKey = beforeF7SelectEvent.getProperty().getName();
+        if (ContributionEvaluationConstant.NCKD_SCOREITEMSUB.equalsIgnoreCase(fieldKey) || ContributionEvaluationConstant.NCKD_SCOREITEMRANK.equalsIgnoreCase(fieldKey)) {
+            DynamicObject scoreItem = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_SCOREITEM));
+            if(scoreItem == null){
+                this.getView().showTipNotification("请先选择“积分项目”");
+                beforeF7SelectEvent.setCancel( true);
+                return;
+            }
+            // 构建过滤条件:假设B字段的F7列表关联实体中有一个字段与A字段值关联(例如"relatedField")
+            QFilter filter = new QFilter(ContributionEvaluationConstant.NCKD_SCOREITEM, QCP.equals, scoreItem.getLong(FormConstant.ID_KEY));
+            // 获取F7列表的显示参数并设置过滤条件
+            ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
+            showParameter.getListFilterParameter().setFilter(filter);
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyChangedArgs e) {
+        String fieldKey = e.getProperty().getName();
+        ChangeData[] changeSet = e.getChangeSet();
+        int rowIndex = changeSet[0].getRowIndex();
+        Object oldValue = changeSet[0].getOldValue();
+        Object newValue = changeSet[0].getNewValue();
+
+        //年度、积分项目、积分子项目、人员、原始积分发生变更将触发"录入积分"重算
+        if(isScoreCalculationTriggerField(fieldKey) && !Objects.equals(oldValue, newValue)) {
+            if(rowIndex > -1) {
+                //分录内容变更
+                handleEntryRowChange(rowIndex);
+            } else {
+                //表头字段变更
+                handleHeadFieldChange();
+            }
+        }
+    }
+
+    /**
+     * 判断是否为触发积分计算的字段
+     * @param fieldKey 变更字段
+     * @return: boolean
+     * @author W.Y.C
+     * @date: 2025/10/26 19:46
+     */
+    private boolean isScoreCalculationTriggerField(String fieldKey) {
+        return ContributionEvaluationConstant.NCKD_YEAR.equalsIgnoreCase(fieldKey)
+                || ContributionEvaluationConstant.NCKD_PERSON.equalsIgnoreCase(fieldKey)
+                || ContributionEvaluationConstant.NCKD_SCOREITEMSUB.equalsIgnoreCase(fieldKey)
+                || ContributionEvaluationConstant.NCKD_SCOREITEM.equalsIgnoreCase(fieldKey)
+                || ContributionEvaluationConstant.NCKD_ORISCORE.equalsIgnoreCase(fieldKey);
+    }
+
+    /**
+     * 处理分录行变更
+     * 分录变更则针对当前分录计算积分
+     * @param rowIndex 行索引
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/10/26 19:47
+     */
+    private void handleEntryRowChange(int rowIndex) {
+        Long id = ConvertUtil.toLong(this.getModel().getValue(FormConstant.ID_KEY));
+        Date date = ConvertUtil.toDate(this.getModel().getValue(ContributionEvaluationConstant.NCKD_YEAR));
+        DynamicObject scoreItem = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_SCOREITEM));
+        DynamicObject scoreItemSub = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_SCOREITEMSUB));
+        DynamicObject person = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_PERSON, rowIndex));
+        BigDecimal oriScore = ConvertUtil.toBigDecimal(this.getModel().getValue(ContributionEvaluationConstant.NCKD_ORISCORE, rowIndex));
+
+        if (date != null && scoreItem != null && scoreItemSub != null && person != null
+                && oriScore != null && oriScore.compareTo(BigDecimal.ZERO) > 0) {
+            //计算本次可用积分
+            ContributionHelper.ScoreItemValidScore scoreItemValidScore = new ContributionHelper.ScoreItemValidScore(
+                    person.getLong(FormConstant.ID_KEY),
+                    scoreItem.getLong(FormConstant.ID_KEY),
+                    scoreItemSub.getLong(FormConstant.ID_KEY));
+            scoreItemValidScore.setCurrentScore(oriScore);
+            ContributionHelper.getScoreItemValidScore(scoreItemValidScore, date, id);
+            this.getModel().setValue(ContributionEvaluationConstant.NCKD_SCORE, scoreItemValidScore.getValidScore(), rowIndex);
+            this.getView().updateView(ContributionEvaluationConstant.NCKD_SCORE, rowIndex);
+        }
+    }
+
+    /**
+     * 处理表头字段变更
+     * 表头变更则重新计算所有分录(已维护人员和原积分的数据)的积分
+     * @param
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/10/26 19:47
+     */
+    private void handleHeadFieldChange() {
+        Long id = ConvertUtil.toLong(this.getModel().getValue(FormConstant.ID_KEY));
+        Date date = ConvertUtil.toDate(this.getModel().getValue(ContributionEvaluationConstant.NCKD_YEAR));
+        DynamicObject scoreItem = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_SCOREITEM));
+        DynamicObject scoreItemSub = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_SCOREITEMSUB));
+
+        if (date != null && scoreItem != null && scoreItemSub != null) {
+            //重置分录所有分录的"录用积分"字段
+            DynamicObjectCollection entryEntity = this.getModel().getEntryEntity(FormConstant.NCKD_ENTRYENTITY);
+            List<ContributionHelper.ScoreItemValidScore> scoreItemValidScoreList = new ArrayList<>(entryEntity.size());
+
+            for (int i = 0; i < entryEntity.size(); i++) {
+                DynamicObject person = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_PERSON, i));
+                BigDecimal oriScore = ConvertUtil.toBigDecimal(this.getModel().getValue(ContributionEvaluationConstant.NCKD_ORISCORE, i));
+
+                if(person != null && oriScore != null && oriScore.compareTo(BigDecimal.ZERO) > 0){
+                    ContributionHelper.ScoreItemValidScore scoreItemValidScore = new ContributionHelper.ScoreItemValidScore(
+                            person.getLong(FormConstant.ID_KEY),
+                            scoreItem.getLong(FormConstant.ID_KEY),
+                            scoreItemSub.getLong(FormConstant.ID_KEY));
+                    scoreItemValidScore.setCurrentScore(oriScore);
+                    scoreItemValidScore.setRowIndex(i);
+                    scoreItemValidScoreList.add(scoreItemValidScore);
+                }
+            }
+
+            if (!scoreItemValidScoreList.isEmpty()) {
+                ContributionHelper.getScoreItemValidScore(scoreItemValidScoreList, date, id);
+                for (ContributionHelper.ScoreItemValidScore scoreItemValidScore : scoreItemValidScoreList) {
+                    this.getModel().setValue(ContributionEvaluationConstant.NCKD_SCORE, scoreItemValidScore.getValidScore(), scoreItemValidScore.getRowIndex());
+                }
+                this.getView().updateView(FormConstant.NCKD_ENTRYENTITY);
+            }
+        }
+    }
+
+}

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

@@ -0,0 +1,69 @@
+package nckd.jxccl.hr.psms.plugin.form.contribution;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.datamodel.events.ChangeData;
+import kd.bos.entity.datamodel.events.PropertyChangedArgs;
+import kd.bos.form.control.EntryGrid;
+import kd.bos.form.control.events.BaseDataColumnDependFieldSetEvent;
+import kd.bos.form.field.BasedataEdit;
+import kd.bos.form.field.events.BeforeF7SelectEvent;
+import kd.bos.form.field.events.BeforeF7SelectListener;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.hr.psms.common.ContributionEvaluationConstant;
+import nckd.jxccl.hr.psms.helper.ContributionHelper;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.EventObject;
+import java.util.Objects;
+
+/**
+* 积分项目分数配置插件
+* 实体标识:nckd_scoreitemconf
+* @author W.Y.C
+* @date 2025/10/25 22:13
+* @version 1.0
+*/
+public class ScoreItemConfFormPlugin extends AbstractFormPlugin implements Plugin, BeforeF7SelectListener {
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+
+        // 为分录中的A字段添加值变化监听
+        BasedataEdit bFieldEdit = this.getView().getControl(ContributionEvaluationConstant.NCKD_SCOREITEMSUB);
+        if (bFieldEdit != null) {
+            bFieldEdit.addBeforeF7SelectListener(this);
+        }
+    }
+
+
+    @Override
+    public void beforeF7Select(BeforeF7SelectEvent e) {
+        String fieldKey = e.getProperty().getName();
+
+        //基础资料联动
+        // 仅处理B字段的F7事件
+        if (ContributionEvaluationConstant.NCKD_SCOREITEMSUB.equalsIgnoreCase(fieldKey)) {
+            // 获取当前分录行的行号
+            int currentRow = e.getRow();
+
+            if (currentRow >= 0) {
+                // 获取当前行A字段的值
+                DynamicObject fieldAValue = ConvertUtil.toDynamicObjectOrNull(this.getModel().getValue(ContributionEvaluationConstant.NCKD_SCOREITEM, currentRow));
+                if(fieldAValue == null){
+                    this.getView().showTipNotification("请先选择“积分项目”");
+                    e.setCancel( true);
+                    return;
+                }
+                QFilter filter = new QFilter(ContributionEvaluationConstant.NCKD_SCOREITEM, QCP.equals, fieldAValue.getLong(FormConstant.ID_KEY));
+                e.addCustomQFilter(filter);
+            }
+        }
+    }
+
+}

+ 2 - 6
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/NewHireInitialFormPlugin.java

@@ -1,9 +1,7 @@
 package nckd.jxccl.hr.psms.plugin.form.initial;
 
-import com.kingdee.cosmic.ctrl.kdf.formatter.StringFormatter;
 import kd.bos.common.enums.EnableEnum;
 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;
@@ -15,14 +13,12 @@ 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.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.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.time.LocalDateTime;
 import java.util.Date;
@@ -87,7 +83,7 @@ public class NewHireInitialFormPlugin extends AbstractFormPlugin implements Plug
         if(date == null){
             date = new Date();
         }
-        PositionAppointmentBO positionAppointMen = PositionStructureHelper.positionAppointmentQuery(personId, date);
+        PositionAppointmentBO positionAppointMen = PositionFileHelper.positionAppointmentQuery(personId, date);
         if(positionAppointMen != null) {
             //学历
             DynamicObject perEduExp = positionAppointMen.getPerEduExp();

+ 2 - 2
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/ServingInitialFormPlugin.java

@@ -12,7 +12,7 @@ import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.util.Date;
 import java.util.EventObject;
@@ -74,7 +74,7 @@ public class ServingInitialFormPlugin extends AbstractFormPlugin implements Plug
         if (date == null) {
             date = new Date();
         }
-        PositionAppointmentBO positionAppointMen = PositionStructureHelper.positionAppointmentQuery(personId, date);
+        PositionAppointmentBO positionAppointMen = PositionFileHelper.positionAppointmentQuery(personId, date);
         if (positionAppointMen != null) {
             // 学历
             DynamicObject perEduExp = positionAppointMen.getPerEduExp();

+ 1 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/UngradedPersonQueryListPlugin.java

@@ -45,6 +45,7 @@ public class UngradedPersonQueryListPlugin extends AbstractListPlugin implements
                 .and(FormConstant.IS_SEQLATESTRECORD, QCP.equals,EnableEnum.YES.getCode())
                 .and(FormConstant.IS_DELETED, QCP.equals,EnableEnum.NO.getCode())
                 .and(FormConstant.IS_PRIMARY, QCP.equals,EnableEnum.YES.getCode())
+
                 //只查询在职人员
                 .and(String.join(".",FormConstant.HRPI_EMPENTREL, FormConstant.LABOR_REL_STATUS,FormConstant.IS_HIRED), QCP.equals,EnableEnum.YES.getCode());
         setFilterEvent.addCustomQFilter(filter);

+ 2 - 13
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/performance/PerfrankMgmtFormPlugin.java

@@ -12,7 +12,6 @@ import kd.bos.entity.QueryEntityType;
 import kd.bos.entity.datamodel.IDataModel;
 import kd.bos.entity.datamodel.RowDataEntity;
 import kd.bos.entity.datamodel.events.AfterAddRowEventArgs;
-import kd.bos.entity.datamodel.events.AfterDeleteRowEventArgs;
 import kd.bos.entity.datamodel.events.PropertyChangedArgs;
 import kd.bos.ext.hr.service.query.QueryEntityHelper;
 import kd.bos.form.ConfirmCallBackListener;
@@ -20,11 +19,6 @@ import kd.bos.form.ConfirmTypes;
 import kd.bos.form.IClientViewProxy;
 import kd.bos.form.MessageBoxOptions;
 import kd.bos.form.MessageBoxResult;
-import kd.bos.form.control.EntryGrid;
-import kd.bos.form.control.Toolbar;
-import kd.bos.form.control.events.BeforeClickEvent;
-import kd.bos.form.control.events.ItemClickEvent;
-import kd.bos.form.control.events.ItemClickListener;
 import kd.bos.form.events.AfterDoOperationEventArgs;
 import kd.bos.form.events.BeforeDoOperationEventArgs;
 import kd.bos.form.events.MessageBoxClosedEvent;
@@ -34,7 +28,6 @@ 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 nckd.jxccl.base.common.constant.FormConstant;
@@ -43,18 +36,14 @@ import nckd.jxccl.base.common.enums.AppraisalResultEnum;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
-import nckd.jxccl.hr.hstu.business.CreateEvalQuestService;
 import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
-import org.apache.commons.lang3.StringUtils;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
-import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.EventObject;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -206,7 +195,7 @@ public class PerfrankMgmtFormPlugin extends AbstractFormPlugin implements Plugin
 
                     // -------------------------------- 3、获取人员对应的职级 --------------------------------
                     //获取职位积分档案,用于判断是否有职级;职级大于0默认勾选“职位津贴”
-                    DynamicObject[] newestPersonPosFileByPerson = PositionStructureHelper.getNewestPersonPosFileByPerson(personIds.toArray(new Long[0]));
+                    DynamicObject[] newestPersonPosFileByPerson = PositionFileHelper.getNewestPersonPosFileByPerson(personIds.toArray(new Long[0]));
                     Map<Long, Long> personJobLevelMap = Arrays.stream(newestPersonPosFileByPerson)
                             .collect(Collectors.toMap(
                                     obj -> obj.getLong(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY)),

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

@@ -25,7 +25,7 @@ import nckd.jxccl.base.pm.helper.PerformanceManagerHelper;
 import nckd.jxccl.hr.psms.business.JobLevelCalculatorService;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
@@ -108,12 +108,12 @@ public class NewDynamicAdjustmentOperationPlugIn extends AbstractOperationServic
                 if (adjustDate == null) {
                     addFatalErrorMessage(rowDataEntity,StrFormatter.format("人员【{}】调整时间不能为空",person.getString(FormConstant.NAME_KEY)));
                 }
-                DynamicObject latsPersonPosFileByPerson = PositionStructureHelper.getLatsPersonPosFileByPerson(person.getLong(FormConstant.ID_KEY));
+                DynamicObject latsPersonPosFileByPerson = PositionFileHelper.getLatsPersonPosFileByPerson(person.getLong(FormConstant.ID_KEY));
                 if(latsPersonPosFileByPerson == null){
                     addFatalErrorMessage(rowDataEntity, StrFormatter.format("当前无法为【{}】进行动态调整,因为他/她尚未建立职位档案。请前往“职位及积分初定” -> 进行初定!", person.getString(FormConstant.NAME_KEY)));
                 }
                 //判断当前年是否已执行过年度调整
-                DynamicObject[] personPosFileByAdjust = PositionStructureHelper.getPersonPosFileByPersonAndState(person.getLong(FormConstant.ID_KEY), new String[]{"4"},
+                DynamicObject[] personPosFileByAdjust = PositionFileHelper.getPersonPosFileByPersonAndState(person.getLong(FormConstant.ID_KEY), new String[]{"4"},
                         null,
                         new QFilter(PositionStructureConstant.NCKD_ADJUSSTATUS, QCP.equals, EnableEnum.NO.getCode()));
                 if(personPosFileByAdjust != null && personPosFileByAdjust.length > 0){
@@ -169,8 +169,8 @@ public class NewDynamicAdjustmentOperationPlugIn extends AbstractOperationServic
         }
 
         SaveServiceHelper.save(newPersonPosFiles.toArray(new DynamicObject[0]));
-        PositionStructureHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
-        PositionStructureHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
     }
 
     private void execute(DynamicObject data, List<Long> personIds, List<DynamicObject> newPersonPosFiles) {
@@ -189,7 +189,7 @@ public class NewDynamicAdjustmentOperationPlugIn extends AbstractOperationServic
         Date adjustDate = data.getDate(PositionStructureConstant.NCKD_ADJUSTDATE);
         LocalDateTime adjustDateEnd = DateUtil.endOfDay(DateUtil.toLocalDateTime(adjustDate));
         //查询员工在调整日期内的最新信息(职位、部门、序列、学历、职称、技能)
-        PositionAppointmentBO positionAppointment = PositionStructureHelper.positionAppointmentQuery(personId, DateUtil.toDate(adjustDateEnd));
+        PositionAppointmentBO positionAppointment = PositionFileHelper.positionAppointmentQuery(personId, DateUtil.toDate(adjustDateEnd));
         if(positionAppointment.getEmpPosOrgRel() == null){
             throw new ValidationException(StrFormatter.format("当前无法为【{}】进行调整,因为根据时间【{}】未获取到人员任职和聘任信息!", personName,DateUtil.format(adjustDateEnd,DateUtil.NORM_DATE_PATTERN)));
         }

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

@@ -21,7 +21,7 @@ import nckd.jxccl.base.pm.helper.PerformanceManagerHelper;
 import nckd.jxccl.hr.psms.business.AnnualAdjustmentService;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.time.LocalDateTime;
 import java.util.ArrayList;
@@ -117,12 +117,12 @@ public class AnnualAdjustmentOperationPlugin extends AbstractOperationServicePlu
                     addFatalErrorMessage(rowDataEntity,StrFormatter.format("人员【{}】缺少【{}】年考核结果", personName,lastYear));
                 }
 
-                PositionAppointmentBO positionAppointment = PositionStructureHelper.positionAppointmentQuery(personId, adjustDate);
+                PositionAppointmentBO positionAppointment = PositionFileHelper.positionAppointmentQuery(personId, adjustDate);
                 if(positionAppointment.getEmpPosOrgRel() == null){
                     addFatalErrorMessage(rowDataEntity,StrFormatter.format("当前无法为【{}】进行调整,因为根据时间【{}】未获取到人员任职和聘任信息!", personName, DateUtil.format(adjustDate,DateUtil.NORM_DATE_PATTERN)));
                 }
 
-                DynamicObject firstRank = PositionStructureHelper.getFirstRank(personId);
+                DynamicObject firstRank = PositionFileHelper.getFirstRank(personId);
                 if(firstRank == null){
                     addFatalErrorMessage(rowDataEntity,StrFormatter.format("当前无法为【{}】进行调整,因为他/她尚未建立职位档案。请前往“职位及积分初定” -> 进行初定!", personName));
                 }else{
@@ -132,7 +132,7 @@ public class AnnualAdjustmentOperationPlugin extends AbstractOperationServicePlu
                 }
                 int executeYear = DateUtil.getYear(adjustDate);
                 //判断当前年是否已执行过年度调整
-                DynamicObject[] personPosFileByYear = PositionStructureHelper.getPersonPosFileByPersonAndState(person.getLong(FormConstant.ID_KEY), new String[]{"3"}, null, new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR, QCP.equals, executeYear));
+                DynamicObject[] personPosFileByYear = PositionFileHelper.getPersonPosFileByPersonAndState(person.getLong(FormConstant.ID_KEY), new String[]{"3"}, null, new QFilter(PositionStructureConstant.NCKD_EXECUTEYEAR, QCP.equals, executeYear));
                 if(personPosFileByYear != null && personPosFileByYear.length > 0){
                     addFatalErrorMessage(rowDataEntity,StrFormatter.format("人员【{}】已存在【{}】年的年度调整", person.getString(FormConstant.NAME_KEY), executeYear));
                 }
@@ -173,8 +173,8 @@ public class AnnualAdjustmentOperationPlugin extends AbstractOperationServicePlu
         }
 
         SaveServiceHelper.save(newPersonPosFiles.toArray(new DynamicObject[0]));
-        PositionStructureHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
-        PositionStructureHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
         for (DynamicObject newPersonPosFile : newPersonPosFiles) {
             String adjustType = newPersonPosFile.getString(PositionStructureConstant.NCKD_ADJUSTTYPE);
             setJobLevelResult(newPersonPosFile.getDynamicObject(PositionStructureConstant.NCKD_PERSON),newPersonPosFile.getDynamicObject(PositionStructureConstant.NCKD_JOBLEVELHR),AdjustTypeEnum.getByCode(adjustType));

+ 3 - 3
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualEffectiveOpPlugin.java

@@ -20,7 +20,7 @@ import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.time.LocalDateTime;
 import java.util.ArrayList;
@@ -168,8 +168,8 @@ public class AnnualEffectiveOpPlugin extends AbstractOperationServicePlugIn impl
         }
 
         //将人员所有职位档案标记为非最新
-        PositionStructureHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
         //将当前人员最新档案(初定 或者 (年度调整 并且 已生效) 或者 (动态调整) 生效时间为最新的那一条)标记为最新的
-        PositionStructureHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
     }
 }

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

@@ -55,8 +55,8 @@ import java.util.StringJoiner;
 */
 public class AnnualLockOrUnLockedOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
 
-    private final static String INTERACTION_SPONORE = "nckd.jxccl.hr.psms.plugin.operate.annualadjust.AnnualLockOrUnLockedOpPlugin";
-    private final static String INTERACTION_SPONORE1 = "nckd.jxccl.hr.psms.plugin.operate.annualadjust.AnnualLockOrUnLockedOpPlugin#1";
+    private final static String INTERACTION_SPONORE = AnnualLockOrUnLockedOpPlugin.class.getName();
+    private final static String INTERACTION_SPONORE1 = AnnualLockOrUnLockedOpPlugin.class.getName() + "#1";
 
     private List<Long> ids;
 
@@ -124,38 +124,27 @@ public class AnnualLockOrUnLockedOpPlugin extends AbstractOperationServicePlugIn
                 .add(PositionStructureConstant.KEY_NCKD_LOCKUSER)
                 .add(PositionStructureConstant.NCKD_LOCKDATETIME);
         DynamicObject[] load = BusinessDataServiceHelper.load(PositionStructureConstant.PERSONPOSFILE_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{QFilterCommonHelper.getIdInFilter(ids)});
-        boolean isProcessFlag = false;
-        for (DynamicObject dynamicObject : load) {
-            long id = dynamicObject.getLong(FormConstant.ID_KEY);
-            if(PositionStructureConstant.ISLOCKED_OP.equals(operateKey)) {
+        boolean isProcessFlag = true;
+        if(PositionStructureConstant.ISLOCKED_OP.equals(operateKey)) {
+            for (DynamicObject dynamicObject : load) {
+                long id = dynamicObject.getLong(FormConstant.ID_KEY);
                 dynamicObject.set(PositionStructureConstant.NCKD_LOCKSTATUS, EnableEnum.YES.getCode());
                 dynamicObject.set(PositionStructureConstant.KEY_NCKD_LOCKUSER, RequestContext.get().getCurrUserId());
                 dynamicObject.set(PositionStructureConstant.NCKD_LOCKDATETIME, new Date());
-            }else{
-                //TODO 【待修改】-职位体系-解锁需要校验是否总部人员,非总部人员需要走审批
-                if(true) {
-                    //非总部人员解锁,发起解锁申请流程
-                    isProcessFlag = true;
-                }else{
-                    dynamicObject.set(PositionStructureConstant.NCKD_LOCKSTATUS, EnableEnum.NO.getCode());
-                    dynamicObject.set(PositionStructureConstant.KEY_NCKD_LOCKUSER, null);
-                    dynamicObject.set(PositionStructureConstant.NCKD_LOCKDATETIME, null);
-
-                }
             }
-        }
-        if(isProcessFlag) {
+            SaveServiceHelper.update(load);
+        }else {
             //操作原因
             String reason = this.getOption().getVariableValue("reason", "");
             //发起解锁单据流程
             DynamicObject billObj = BusinessDataServiceHelper.newDynamicObject(PositionStructureConstant.POSFILEUNLOCK_ENTITYID);
             billObj.set(FormConstant.CREATOR_KEY, UserServiceHelper.getCurrentUserId());
             billObj.set(FormConstant.CREATE_TIME_KEY, System.currentTimeMillis());
-            billObj.set(FormConstant.BILL_STATUS_KEY,BillStatus.A.toString());
+            billObj.set(FormConstant.BILL_STATUS_KEY, BillStatus.A.toString());
             DynamicObject org = BusinessDataServiceHelper.newDynamicObject(FormConstant.ADMINORGHR_ENTITYID);
             org.set(FormConstant.ID_KEY, UserServiceHelper.getUserMainOrgId(UserServiceHelper.getCurrentUserId()));
             billObj.set(FormConstant.ORG_KEY, org);
-            billObj.set(PositionStructureConstant.NCKD_REASON,reason);
+            billObj.set(PositionStructureConstant.NCKD_REASON, reason);
 
             DynamicObjectCollection entryColl = billObj.getDynamicObjectCollection(PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY);
             DynamicObjectType entryType = entryColl.getDynamicObjectType();
@@ -172,21 +161,19 @@ public class AnnualLockOrUnLockedOpPlugin extends AbstractOperationServicePlugIn
                     new DynamicObject[]{billObj},
                     option
             );
-            if(!result.isSuccess()) {
+            if (!result.isSuccess()) {
                 StringJoiner joiner = new StringJoiner(StrFormatter.LINE_SEPARATOR);
                 for (IOperateInfo iOperateInfo : result.getAllErrorOrValidateInfo()) {
                     joiner.add(iOperateInfo.getMessage());
                 }
                 throw new ValidationException(StrFormatter.format("提交解锁申请单失败,原因:{}", joiner.toString()));
 
-            }else{
+            } else {
                 if (this.getOperationResult().getCustomData() == null) {
                     this.getOperationResult().setCustomData(new HashMap<>());
                 }
                 this.getOperationResult().getCustomData().put("bill", "true");
             }
-        }else{
-            SaveServiceHelper.update(load);
         }
 
 
@@ -206,27 +193,26 @@ public class AnnualLockOrUnLockedOpPlugin extends AbstractOperationServicePlugIn
                 e.cancel = !this.showInteractionMessage();
             }
         }else if(PositionStructureConstant.UNLOCKED_OP.equals(operationKey)){
-            //TODO 【待修改】-职位体系-解锁需要校验是否总部人员,非总部人员需要走审批
-            if(true){
-                //校验选中的档案是否已经有申请单据
-                QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
-                        .addGroup(new String[]{PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY, PositionStructureConstant.NCKD_PERSONPOSFILE,FormConstant.NCKD_PERSON},
-                                FormConstant.NAME_KEY);
-                QFilter filter = new QFilter(FormConstant.BILL_STATUS_KEY, QCP.not_equals, BillStatus.C.toString())
-                        .and(new QFilter(String.join(".", PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY, PositionStructureConstant.NCKD_PERSONPOSFILE, FormConstant.ID_KEY), QCP.in, ids));
-                DynamicObjectCollection query = QueryServiceHelper.query(PositionStructureConstant.POSFILEUNLOCK_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
-                if(!query.isEmpty()){
-                    List<String> personNames = new ArrayList<>(query.size());
-                    for (DynamicObject dynamicObject : query) {
-                        String personName = dynamicObject.getString(String.join(".", PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY, PositionStructureConstant.NCKD_PERSONPOSFILE, FormConstant.NCKD_PERSON, FormConstant.NAME_KEY));
-                        personNames.add(personName);
-                    }
-                    throw new ValidationException(StrFormatter.format("人员【{}】的职位档案已存在待解锁的申请,请勿重复申请。", String.join(",", personNames)));
-                }else{
-                    e.cancel = !this.unlockNeedApprovalInteractionMessage();
+            //从流程启动条件判断非集团本部的不需要审批
+            //校验选中的档案是否已经有申请单据
+            QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                    .addGroup(new String[]{PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY, PositionStructureConstant.NCKD_PERSONPOSFILE,FormConstant.NCKD_PERSON},
+                            FormConstant.NAME_KEY);
+            QFilter filter = new QFilter(FormConstant.BILL_STATUS_KEY, QCP.not_equals, BillStatus.C.toString())
+                    .and(new QFilter(String.join(".", PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY, PositionStructureConstant.NCKD_PERSONPOSFILE, FormConstant.ID_KEY), QCP.in, ids));
+            DynamicObjectCollection query = QueryServiceHelper.query(PositionStructureConstant.POSFILEUNLOCK_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+            if(!query.isEmpty()){
+                List<String> personNames = new ArrayList<>(query.size());
+                for (DynamicObject dynamicObject : query) {
+                    String personName = dynamicObject.getString(String.join(".", PositionStructureConstant.NCKD_POSFILEUNLOCKENTRY, PositionStructureConstant.NCKD_PERSONPOSFILE, FormConstant.NCKD_PERSON, FormConstant.NAME_KEY));
+                    personNames.add(personName);
                 }
+                throw new ValidationException(StrFormatter.format("人员【{}】的职位档案已存在待解锁的申请,请勿重复申请。", String.join(",", personNames)));
+            }else{
+                e.cancel = !this.unlockNeedApprovalInteractionMessage();
             }
         }
+
     }
 
 
@@ -266,7 +252,7 @@ public class AnnualLockOrUnLockedOpPlugin extends AbstractOperationServicePlugIn
         InteractionContext interactionContext = new InteractionContext();
         interactionContext.setSimpleMessage("存在“未生效的”档案");
         OperateErrorInfo errorInfo = new OperateErrorInfo();
-        errorInfo.setMessage("解锁需要经过总部审批,审批通过之后自动解锁;点击“是”系统自动发起解锁审批流程");
+        errorInfo.setMessage("非总部解锁需要经过总部审批,审批通过之后自动解锁;点击“是”系统自动发起解锁审批流程");
         errorInfo.setLevel(ErrorLevel.Warning);
         interactionContext.addOperateInfo(errorInfo);
         throw new KDInteractionException(INTERACTION_SPONORE1, interactionContext);

+ 3 - 3
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/annualadjust/AnnualSetinActiveOpPlugin.java

@@ -21,7 +21,7 @@ import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -144,8 +144,8 @@ public class AnnualSetinActiveOpPlugin extends AbstractOperationServicePlugIn im
         }
 
         //将人员所有职位档案标记为非最新
-        PositionStructureHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsNotCurrentNewest(personIds.toArray(new Long[0]));
         //将当前人员最新档案(初定 或者 (年度调整 并且 已生效) 或者 (动态调整) 生效时间为最新的那一条)标记为最新的
-        PositionStructureHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
+        PositionFileHelper.markAsCurrentNewest(null,personIds.toArray(new Long[0]));
     }
 }

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

@@ -0,0 +1,134 @@
+package nckd.jxccl.hr.psms.plugin.operate.contribution;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.operate.OperateOptionConst;
+import kd.bos.entity.operate.interaction.InteractionConfirmResult;
+import kd.bos.entity.operate.interaction.InteractionContext;
+import kd.bos.entity.operate.interaction.KDInteractionException;
+import kd.bos.entity.operate.result.OperateErrorInfo;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.args.BeforeOperationArgs;
+import kd.bos.entity.validate.AbstractValidator;
+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.utils.StrFormatter;
+import nckd.jxccl.hr.psms.common.ContributionEvaluationConstant;
+import nckd.jxccl.hr.psms.helper.ContributionHelper;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 年度积分贡献单据保存/提交插件
+ * 实体标识:nckd_contribbill
+ * @author W.Y.C
+ * @date 2025/10/26 20:17
+ * @version 1.0
+ */
+public class ContribBillOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private final static String INTERACTION_SPONORE = ContribBillOpPlugin.class.getName();
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        e.addValidator(new AbstractValidator() {
+
+            @Override
+            public void validate() {
+                //校验参与人数
+                for (ExtendedDataEntity dataEntity : this.getDataEntities()) {
+                    DynamicObject data = dataEntity.getDataEntity();
+                    int participants = data.getInt(ContributionEvaluationConstant.NCKD_PARTICIPANTS);
+                    if (participants < 1) {
+                        this.addMessage(dataEntity, "参与人数不能小于1;");
+                    }else{
+                        DynamicObjectCollection entryEntity = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+                        if(entryEntity.isEmpty()){
+                            this.addMessage(dataEntity, "请添加参与人明细;");
+                        }else{
+                            //校验积分是否超出限制
+                            Long id = data.getLong(FormConstant.ID_KEY);
+                            Date date = data.getDate(ContributionEvaluationConstant.NCKD_YEAR);
+                            DynamicObject scoreItem = data.getDynamicObject(ContributionEvaluationConstant.NCKD_SCOREITEM);
+                            DynamicObject scoreItemSub = data.getDynamicObject(ContributionEvaluationConstant.NCKD_SCOREITEMSUB);
+                            List<ContributionHelper.ScoreItemValidScore> scoreItemValidScoreList = new ArrayList<>(entryEntity.size());
+                            for (DynamicObject entry : entryEntity) {
+                                DynamicObject person = entry.getDynamicObject(ContributionEvaluationConstant.NCKD_PERSON);
+                                BigDecimal oriScore = entry.getBigDecimal(ContributionEvaluationConstant.NCKD_ORISCORE);
+                                ContributionHelper.ScoreItemValidScore scoreItemValidScore = new ContributionHelper.ScoreItemValidScore(
+                                        person.getLong(FormConstant.ID_KEY),
+                                        scoreItem.getLong(FormConstant.ID_KEY),
+                                        scoreItemSub.getLong(FormConstant.ID_KEY));
+                                scoreItemValidScore.setCurrentScore(oriScore);
+                                scoreItemValidScoreList.add(scoreItemValidScore);
+                            }
+                            if (!scoreItemValidScoreList.isEmpty()) {
+                                ContributionHelper.getScoreItemValidScore(scoreItemValidScoreList, date, id);
+                                for (DynamicObject entry : entryEntity) {
+                                    DynamicObject person = entry.getDynamicObject(ContributionEvaluationConstant.NCKD_PERSON);
+                                    long personId = person.getLong(FormConstant.ID_KEY);
+                                    BigDecimal oriScore = entry.getBigDecimal(ContributionEvaluationConstant.NCKD_ORISCORE);
+                                    BigDecimal score = entry.getBigDecimal(ContributionEvaluationConstant.NCKD_SCORE);
+                                    for (ContributionHelper.ScoreItemValidScore scoreItemValidScore : scoreItemValidScoreList) {
+                                        if(Objects.equals(scoreItemValidScore.getPersonId(),personId)){
+                                            if(scoreItemValidScore.getValidScore() != null){
+                                                if(score.compareTo(scoreItemValidScore.getValidScore()) > 0){
+                                                    this.addMessage(dataEntity, StrFormatter.format("参与人【{}】的录入积分【{}】超出限制积分【{}】。请重新填写“原始积分”,系统将会自动重算“录入积分”;",
+                                                            person.getString(FormConstant.NAME_KEY),
+                                                            score.setScale(2, RoundingMode.HALF_UP),
+                                                            scoreItemValidScore.getValidScore().setScale(2, RoundingMode.HALF_UP)));
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
+        for (DynamicObject data : e.getDataEntities()) {
+            int participants = data.getInt(ContributionEvaluationConstant.NCKD_PARTICIPANTS);
+            DynamicObjectCollection dynamicObjectCollection = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+            if(participants != dynamicObjectCollection.size()){
+                e.cancel = !this.showInteractionMessage(participants,dynamicObjectCollection.size());
+            }
+        }
+    }
+
+
+    private boolean showInteractionMessage(int participants,int size) {
+        //交互式操作提示
+        // 检查是否为回调:避免死循环
+        String confirmResultString = this.getOption().getVariableValue(OperateOptionConst.INTERACTIONCONFIRMRESULT, "");
+        InteractionConfirmResult confirmResult = InteractionConfirmResult.fromJsonString(confirmResultString);
+        if (confirmResult.getResults().containsKey(INTERACTION_SPONORE)) {
+            // 已是回调,直接返回结果
+            MessageBoxResult result = MessageBoxResult.valueOf(confirmResult.getResults().get(INTERACTION_SPONORE));
+            return result == MessageBoxResult.Yes;
+        }
+
+        // 首次执行:抛出交互异常
+        InteractionContext interactionContext = new InteractionContext();
+        interactionContext.setSimpleMessage("参与人数不一致");
+        OperateErrorInfo errorInfo = new OperateErrorInfo();
+        errorInfo.setMessage(StrFormatter.format("参与人数【{}】与参与人明细【{}】不匹配", participants,size));
+        errorInfo.setLevel(ErrorLevel.Warning);
+        interactionContext.addOperateInfo(errorInfo);
+        throw new KDInteractionException(INTERACTION_SPONORE, interactionContext);
+    }
+}

+ 0 - 74
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/contribution/validate/ScoreItemConfValidate.java

@@ -1,74 +0,0 @@
-package nckd.jxccl.hr.psms.plugin.operate.contribution.validate;
-
-import kd.bos.dataentity.entity.DynamicObject;
-import kd.bos.dataentity.entity.DynamicObjectCollection;
-import kd.bos.entity.ExtendedDataEntity;
-import kd.bos.entity.validate.AbstractValidator;
-import nckd.jxccl.base.common.constant.FormConstant;
-import nckd.jxccl.base.common.enums.psms.AwardLevelEnum;
-import nckd.jxccl.base.common.enums.psms.ScoreItemEnum;
-import nckd.jxccl.hr.psms.common.ContributionEvaluationConstant;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * 积分项目配置-校验器
- * 实体标识:nckd_scoreitemconf
- * @author W.Y.C
- * @date 2025/10/22 21:50
- * @version 1.0
- */
-public class ScoreItemConfValidate extends AbstractValidator {
-
-    @Override
-    public void validate() {
-        for (ExtendedDataEntity dataEntity : getDataEntities()) {
-            DynamicObject data = dataEntity.getDataEntity();
-            DynamicObjectCollection entrys = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
-            if(entrys.isEmpty()){
-                addMessage(dataEntity, "请添加积分项目");
-                return;
-            }
-            Set<String> uniqueCombinations = new HashSet<>();
-            for (DynamicObject entry : entrys) {
-                //级别
-                String awardLevel = entry.getString(ContributionEvaluationConstant.NCKD_AWARDLEVEL);
-                //积分项目
-                String scoreItem = entry.getString(ContributionEvaluationConstant.NCKD_SCOREITEM);
-
-                // 检查是否已存在相同的组合
-                if (awardLevel != null && !awardLevel.isEmpty() && scoreItem != null && !scoreItem.isEmpty()) {
-                    String[] levels = awardLevel.split(",");
-                    for (String level : levels) {
-                        String trimmedLevel = level.trim();
-                        // 过滤空字符串
-                        if (!trimmedLevel.isEmpty()) {
-                            String combinationKey = scoreItem + "_" + trimmedLevel;
-                            if (!uniqueCombinations.add(combinationKey)) {
-                                addMessage(dataEntity, "同一积分项目在同一级别不能重复配置:" +
-                                        ScoreItemEnum.getByCode(scoreItem).getName() + " - " +
-                                        AwardLevelEnum.getByCode(trimmedLevel).getName());
-                            }
-                        }
-                    }
-                } else if (awardLevel == null || awardLevel.isEmpty()) {
-                    // 处理awardLevel为空的情况
-                    if (scoreItem != null && !scoreItem.isEmpty()) {
-                        String combinationKey = scoreItem + "_EMPTY";
-                        if (!uniqueCombinations.add(combinationKey)) {
-                            addMessage(dataEntity, "同一积分项目在未指定级别时不能重复配置:" +
-                                    ScoreItemEnum.getByCode(scoreItem).getName());
-                        }
-                    } else {
-                        // 如果都为空,则也认为是重复
-                        if (!uniqueCombinations.add("_")) {
-                            addMessage(dataEntity, "存在多条未指定级别的积分项目配置");
-                        }
-                    }
-                }
-            }
-
-        }
-    }
-}

+ 3 - 3
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/file/PersonPosFileDeleteOpPlugin.java

@@ -18,7 +18,7 @@ import nckd.jxccl.base.common.enums.psms.TypeStateEnum;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.HashMap;
@@ -128,8 +128,8 @@ public class PersonPosFileDeleteOpPlugin extends AbstractOperationServicePlugIn
             personIds[i] = person.getLong(FormConstant.ID_KEY);
         }
         //将人员所有职位档案标记为非最新
-        PositionStructureHelper.markAsNotCurrentNewest(personIds);
+        PositionFileHelper.markAsNotCurrentNewest(personIds);
         //将当前人员最新档案(初定 或者 (年度调整 并且 已生效) 或者 (动态调整) 生效时间为最新的那一条)标记为最新的
-        PositionStructureHelper.markAsCurrentNewest(new QFilter(FormConstant.ID_KEY, QCP.not_in,ids),personIds);
+        PositionFileHelper.markAsCurrentNewest(new QFilter(FormConstant.ID_KEY, QCP.not_in,ids),personIds);
     }
 }

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

@@ -21,7 +21,7 @@ import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 import nckd.jxccl.base.pm.helper.PerformanceManagerHelper;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.common.bo.PositionAppointmentBO;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import org.jetbrains.annotations.NotNull;
 
 import java.math.BigDecimal;
@@ -143,7 +143,7 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         data.causeRemark = initialData.getString(PositionStructureConstant.KEY_NCKD_CAUSEREMARK);
         data.person = initialData.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
 
-        PositionAppointmentBO positionAppointment = PositionStructureHelper.positionAppointmentQuery(data.person.getLong(FormConstant.ID_KEY), data.beginDate);
+        PositionAppointmentBO positionAppointment = PositionFileHelper.positionAppointmentQuery(data.person.getLong(FormConstant.ID_KEY), data.beginDate);
         // 学历
         DynamicObject perEduExp = positionAppointment.getPerEduExp();
         if (perEduExp != null) {

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

@@ -11,7 +11,7 @@ import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.hr.psms.business.JobLevelCalculatorService;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.math.BigDecimal;
 import java.util.Date;
@@ -67,7 +67,7 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
                             addFatalErrorMessage(rowDataEntity,"请选择人员");
                             return;
                         }
-                        if(PositionStructureHelper.isInitial(person.getLong(FormConstant.ID_KEY))){
+                        if(PositionFileHelper.isInitial(person.getLong(FormConstant.ID_KEY))){
                             addFatalErrorMessage(rowDataEntity,StrFormatter.format("人员【{}】已初定,不能重复初定",person.getString(FormConstant.NAME_KEY)));
                         }
                         if(newHireInitialData.empPosOrgRel == null){

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

@@ -13,7 +13,7 @@ import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.base.pm.helper.PerformanceManagerHelper;
 import nckd.jxccl.hr.psms.business.JobLevelCalculatorService;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
-import nckd.jxccl.hr.psms.helper.PositionStructureHelper;
+import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
@@ -70,7 +70,7 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
                             addFatalErrorMessage(rowDataEntity,"请选择人员");
                             return;
                         }
-                        if(PositionStructureHelper.isInitial(person.getLong(FormConstant.ID_KEY))){
+                        if(PositionFileHelper.isInitial(person.getLong(FormConstant.ID_KEY))){
                             addFatalErrorMessage(rowDataEntity,StrFormatter.format("人员【{}】已初定,不能重复初定",person.getString(FormConstant.NAME_KEY)));
                         }
                         if(servingInitialData.empPosOrgRel == null){

+ 2 - 4
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/validate/PerfRankMgmtSaveValidate.java

@@ -25,9 +25,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-/**
- * 动态表单插件
- */
 /**
 * 绩效排名管理保存验证插件
 * @author W.Y.C
@@ -36,7 +33,7 @@ import java.util.Set;
 */
 public class PerfRankMgmtSaveValidate extends AbstractValidator {
 
-    private Map<String, BigDecimal> appraisalResultRatioMap = new HashMap<>();
+    private final Map<String, BigDecimal> appraisalResultRatioMap = new HashMap<>();
     @Override
     public void validate() {
         QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
@@ -179,6 +176,7 @@ public class PerfRankMgmtSaveValidate extends AbstractValidator {
      * @param rowDataEntity 行数据实体
      * @param rowIndex 行索引
      * @param personIds 已处理人员ID集合(用于去重检查)
+     *
      * @param context 验证上下文
      * @return: void
      * @author W.Y.C

+ 2 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/report/adjust/UnAdjustedReportReportListDataPlugin.java

@@ -99,6 +99,8 @@ public class UnAdjustedReportReportListDataPlugin extends AbstractReportListData
                 .and(new QFilter(String.join(".", FormConstant.ASSIGNMENT_ENTITYID, FormConstant.IS_PRIMARY),
                         QCP.equals, EnableEnum.YES.getCode()))
                 .and(new QFilter(FormConstant.IS_PRIMARY, QCP.equals, EnableEnum.YES.getCode()))
+                .and(FormConstant.IS_SEQLATESTRECORD, QCP.equals, EnableEnum.YES.getCode())
+                .and(FormConstant.IS_DELETED, QCP.equals, EnableEnum.NO.getCode())
                 .and(QFilter.join(FormConstant.EMPLOYEE_KEY, String.join(".", FormConstant.HRPI_PERPROTITLE, FormConstant.EMPLOYEE_KEY), new QFilter(String.join(".", FormConstant.HRPI_PERPROTITLE, "iscompany"),
                                 QCP.equals, EnableEnum.YES.getCode()),
                         ORMHint.JoinHint.LEFT, Boolean.FALSE))