Prechádzať zdrojové kódy

feat(hr): 添加内部人力资源市场反审批功能并优化日志记录

- 新增 IntJobPostUnAuditedOpPlugin 实现反审批操作插件
- 在 IntJobPostAuditedOpPlugin 中添加详细日志记录用于追踪处理过程
- 修复上年度数据字段映射错误,正确引用当前年度差异字段
- 修正年度日期范围查询逻辑,使用 endOfYear 替代 endOfDay
- 优化 Group Total Wage Budget SubForm 中的在岗职工统计逻辑
- 修复 Group Salary Settlement Approval Form 中的单位分组统计问题
- 更新年度显示格式化方式,统一使用 DateUtil.getYear 方法
wyc 3 dní pred
rodič
commit
dafa4f351f

+ 0 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/ijp/plugin/operate/.gitkeep


+ 26 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/ijp/plugin/operate/IntJobPostAuditedOpPlugin.java

@@ -15,6 +15,8 @@ import kd.bos.entity.plugin.AddValidatorsEventArgs;
 import kd.bos.entity.plugin.PreparePropertysEventArgs;
 import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
 import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
@@ -52,6 +54,8 @@ import java.util.stream.Collectors;
 */
 public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
 
+    private static final Log logger = LogFactory.getLog(IntJobPostAuditedOpPlugin.class);
+
     @Override
     public void onPreparePropertys(PreparePropertysEventArgs e) {
         e.getFieldKeys().addAll(billEntityType.getAllFields().keySet());
@@ -98,6 +102,7 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
     @Override
     public void beginOperationTransaction(BeginOperationTransactionArgs e) {
 
+        logger.info("开始执行内部人力资源市场审批通过操作");
         List<Long> personIds = new ArrayList<>();
         List<Long> entityIds = new ArrayList<>();
         for (DynamicObject dataEntity : e.getDataEntities()) {
@@ -111,7 +116,9 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                 entityIds.add(entry.getLong(IntJobPostConstant.ID_KEY));
             }
         }
+        logger.info("需要处理的人员ID数量: {}, 分录ID数量: {}", personIds.size(), entityIds.size());
         Map<Long, DynamicObject> empPosOrgRelMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
+        logger.info("获取到的员工岗位组织关系数量: {}", empPosOrgRelMap.size());
 
         // --- A. 处理旧记录 ---
         // 1. 查询该员工最近的一条记录(排除当前单据产生的记录,按创建时间倒序取第一条)
@@ -120,8 +127,13 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
         //由于轨迹需要关联本次新增的记录,需要等记录保存成功后再set内部人力资源市场记录。 以分录id作为key,记录待新增的轨迹。
         Map<Long, DynamicObject> savedLocusMap = new HashMap<>();
         List<DynamicObject> savedLocus = new ArrayList<>();
+        logger.info("开始查询人员最新记录");
         Map<Long, DynamicObject> latestRecordMap = getLatestRecordIdsByPersons(personIds, entityIds);
+        logger.info("获取到人员最新记录数量: {}", latestRecordMap.size());
+
+        logger.info("开始查询人员最新轨迹");
         Map<Long, DynamicObject> latestLocusMap = findLatestLocusByPerson(personIds);
+        logger.info("获取到人员最新轨迹数量: {}", latestLocusMap.size());
         for (DynamicObject dataEntity : e.getDataEntities()) {
             Date auditDate = dataEntity.getDate(IntJobPostConstant.AUDIT_DATE_KEY);
             String talentType = dataEntity.getString(IntJobPostConstant.NCKD_TALENTTYPE);
@@ -131,7 +143,9 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                 long id = entry.getLong(IntJobPostConstant.ID_KEY);
                 boolean isEnter = entry.getBoolean(IntJobPostConstant.NCKD_ISENTER);
                 long personId = entry.getLong(String.join(".", IntJobPostConstant.NCKD_PERSON, IntJobPostConstant.ID_KEY));
+                String name = entry.getString(String.join(".", IntJobPostConstant.NCKD_PERSON, IntJobPostConstant.NAME_KEY));
                 if(isEnter){
+                    logger.info("处理进入市场的人员: {}, 人员ID: {}", name, personId);
                     DynamicObject latestRecord = latestRecordMap.get(personId);
                     if(latestRecord != null) {
                         // 2. 备份旧值
@@ -144,6 +158,7 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                         latestRecord.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST, Boolean.FALSE);
                         latestRecord.set(IntJobPostConstant.NCKD_BACKUP, StrFormatter.format("以【{}】身份新进入市场,退出原市场。",talentTypeEnum.getName()));
                         savedRecords.add(latestRecord);
+                        logger.info("已添加旧记录至更新列表,人员: {}, 旧状态: 1(在市场中) -> 新状态: 4(退出市场)",name);
                     }
 
                     // --- B. 插入新记录 ---
@@ -166,8 +181,10 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                         //优秀员工-预计退出时间
                         Date date = DateUtil.addYears(auditDate, 1);
                         newRecord.set(IntJobPostConstant.NCKD_PREDICTTOFOURDATE, date);
+                        logger.info("A类人才,设置预计退出时间为: {}", date);
                     }
                     savedRecords.add(newRecord);
+                    logger.info("已添加新记录至保存列表,人员: {}, 状态: 1(进入市场)", name);
 
                     // --- C. 处理轨迹 (Locus) ---
                     // 1. 查询最近的轨迹
@@ -189,15 +206,21 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                     newLocus.set(IntJobPostConstant.NCKD_STATE, "1");
                     newLocus.set(FormConstant.CREATOR_KEY,currUserId);
                     savedLocusMap.put(id, newLocus);
+                    logger.info("已添加新轨迹至保存映射,分录ID: {}, 人员: {}", id, name);
                 }
             }
         }
+        logger.info("准备保存记录总数: {}, 轨迹总数: {}", savedRecords.size(), savedLocusMap.size());
+
         if(!savedRecords.isEmpty()){
+            logger.info("开始保存内部人力资源市场记录,记录数量: {}", savedRecords.size());
             //保存记录
             OperationResult operationResult = SaveServiceHelper.saveOperate(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID, savedRecords.toArray(new DynamicObject[0]), OperateOption.create());
             if(operationResult.isSuccess()){
+                logger.info("内部人力资源市场记录保存成功");
                 //新增实体
                 savedLocus.addAll(savedLocusMap.values());
+                logger.info("准备保存轨迹记录,数量: {}", savedLocus.size());
                 OperationResult locusOperationResult = SaveServiceHelper.saveOperate(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID, savedLocus.toArray(new DynamicObject[0]), OperateOption.create());
                 if(!locusOperationResult.isSuccess()){
                     StringJoiner errorMsg = new StringJoiner("\n");
@@ -207,8 +230,10 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                     if (!ObjectUtils.isEmpty(locusOperationResult.getMessage())) {
                         errorMsg.add(locusOperationResult.getMessage());
                     }
+                    logger.error("保存轨迹记录失败,原因:{}", errorMsg.toString());
                     throw new ValidationException("保存职位档案失败,原因:" + errorMsg.toString());
                 }
+                logger.info("轨迹记录保存成功");
 
             }else{
                 StringJoiner errorMsg = new StringJoiner("\n");
@@ -218,6 +243,7 @@ public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn im
                 if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
                     errorMsg.add(operationResult.getMessage());
                 }
+                logger.error("保存内部人力资源市场记录失败,原因:{}", errorMsg.toString());
                 throw new ValidationException("保存职位档案失败,原因:" + errorMsg.toString());
             }
         }

+ 213 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/ijp/plugin/operate/IntJobPostUnAuditedOpPlugin.java

@@ -0,0 +1,213 @@
+package nckd.jxccl.hr.ijp.plugin.operate;
+
+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.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+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.bos.servicehelper.operation.SaveServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.ijp.TalentTypeEnum;
+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;
+import nckd.jxccl.base.entity.helper.EntityHelper;
+import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
+import nckd.jxccl.hr.ijp.common.IntJobPostConstant;
+import nckd.jxccl.hr.psms.common.PositionStructureConstant;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+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;
+
+/**
+* 内部人力资源市场-三类人员记录生成-反审批
+* 实体标识:nckd_intjobpost
+* @author W.Y.C
+* @date 2026/1/8 21:34
+* @version 1.0
+*/
+public class IntJobPostUnAuditedOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(IntJobPostUnAuditedOpPlugin.class);
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        e.getFieldKeys().addAll(billEntityType.getAllFields().keySet());
+    }
+
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        List<Long> personIds = new ArrayList<>();
+        List<Long> entityIds = new ArrayList<>();
+        for (DynamicObject dataEntity : e.getDataEntities()) {
+            DynamicObjectCollection entryEntity = dataEntity.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+            for (DynamicObject entry : entryEntity) {
+                DynamicObject person = entry.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
+                boolean isEnter = entry.getBoolean(IntJobPostConstant.NCKD_ISENTER);
+                if(isEnter){
+                    personIds.add(person.getLong(IntJobPostConstant.ID_KEY));
+                }
+                entityIds.add(entry.getLong(IntJobPostConstant.ID_KEY));
+            }
+        }
+        Map<Long, DynamicObject> empPosOrgRelMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
+        Map<Long, DynamicObject> latestRecordMap = getLatestRecordIdsByPersons(personIds, entityIds);
+        Map<Long, DynamicObject> latestLocusByPerson = findLatestLocusByPerson(personIds);
+        List<DynamicObject> savedRecords = new ArrayList<>();
+        List<DynamicObject> savedLocus = new ArrayList<>();
+        for (DynamicObject dataEntity : e.getDataEntities()) {
+            Date auditDate = dataEntity.getDate(IntJobPostConstant.AUDIT_DATE_KEY);
+            String talentType = dataEntity.getString(IntJobPostConstant.NCKD_TALENTTYPE);
+            TalentTypeEnum talentTypeEnum = TalentTypeEnum.getByCode(talentType);
+            DynamicObjectCollection entryEntity = dataEntity.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+            for (DynamicObject entry : entryEntity) {
+                long id = entry.getLong(IntJobPostConstant.ID_KEY);
+                boolean isEnter = entry.getBoolean(IntJobPostConstant.NCKD_ISENTER);
+                long personId = entry.getLong(String.join(".", IntJobPostConstant.NCKD_PERSON, IntJobPostConstant.ID_KEY));
+                String name = entry.getString(String.join(".", IntJobPostConstant.NCKD_PERSON, IntJobPostConstant.NAME_KEY));
+                // --- A. 恢复旧记录 ---
+                // 逻辑:找到该单据对应的“上一条”记录。
+                // 实际上就是找那些被“此单据”截断的记录。
+                DynamicObject prevRecord = latestRecordMap.get(personId);
+                if(prevRecord != null) {
+                    // 还原备份的值
+                    prevRecord.set(IntJobPostConstant.NCKD_TOFOURDATE,prevRecord.get(IntJobPostConstant.NCKD_OLDTOFOURDATE));
+                    // 只有当备份状态不为空时才还原,否则保持原样 (NVL逻辑)
+                    if (prevRecord.get(IntJobPostConstant.NCKD_OLDSTATE) != null) {
+                        prevRecord.set(IntJobPostConstant.NCKD_STATE, prevRecord.get(IntJobPostConstant.NCKD_OLDSTATE));
+                    }
+                    prevRecord.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST, Boolean.TRUE);
+                    savedRecords.add(prevRecord);
+                }
+
+                // --- B. 恢复旧轨迹 ---
+                DynamicObject prevLocus  = latestLocusByPerson.get(personId);
+                if (prevLocus != null) {
+                    prevLocus.set(IntJobPostConstant.NCKD_ENDDATE,prevLocus.get(IntJobPostConstant.NCKD_OLDENDDAY));
+                    prevLocus.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST,Boolean.TRUE);
+                    savedLocus.add(prevLocus);
+                }
+
+            }
+        }
+
+        // --- A. 恢复旧记录 ---
+        // 逻辑:找到该单据对应的“上一条”记录。
+        // 实际上就是找那些被“此单据”截断的记录。
+
+
+
+
+
+
+
+        // --- A. 处理旧记录 ---
+        // 1. 查询该员工最近的一条记录(排除当前单据产生的记录,按创建时间倒序取第一条)
+
+
+        //1、阶段1:备份原有记录
+        // 条件:单据中要进入市场(CFIsenter=1)的员工 + 他们最新的记录 + 记录来源不是当前单据
+        //目的:为反审批时恢复数据做准备
+
+        //阶段2:关闭原记录
+        //逻辑:一个员工只能有一条活跃记录(FIsSingle=1)
+        //状态变化:1(在市场中) → 4(退出市场)
+
+        //阶段3:创建新记录
+        //新记录状态:FIsSingle=1, CFInsidehrRecordState='1'
+
+        //阶段3:特殊处理
+        //A类员工:有预计退出时间(1年后)
+        //非A类员工:预计退出时间为null
+
+    }
+
+    /**
+     * 获取每个人员最新一条记录
+     * @param personIds 人员ID
+     * @param entityIds 分录ID
+     * @return: java.util.Map<java.lang.Long, java.util.List < kd.bos.dataentity.entity.DynamicObject>>
+     * @author W.Y.C
+     * @date: 2026/01/13 15:56
+     */
+    public Map<Long, DynamicObject> getLatestRecordIdsByPersons(List<Long> personIds,List<Long> entityIds) {
+        QueryFieldBuilder intJobPostRecord = QueryFieldBuilder.create().add(IntJobPostConstant.ID_KEY)
+                .add(FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY,FormConstant.ID_KEY)
+                .add(IntJobPostConstant.NCKD_ISCURRENTNEWEST)
+                .orderDesc(IntJobPostConstant.CREATE_TIME_KEY);
+        QFilter filter = new QFilter(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY), QCP.in, personIds)
+                .and(IntJobPostConstant.NCKD_INTJOBPOSTENTRY,QCP.not_in,entityIds);
+        DynamicObjectCollection records = QueryServiceHelper.query(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID, intJobPostRecord.buildSelect(), new QFilter[]{filter});
+        Set<Long> uniquePersonIds = new HashSet<>();
+        List<Long> result = new ArrayList<>();
+        for (DynamicObject record : records) {
+            Long personId = record.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY));
+            if (uniquePersonIds.add(personId)) { // 如果是新的personId,添加到结果中
+                result.add(record.getLong(IntJobPostConstant.ID_KEY));
+            }
+        }
+        MainEntityType intJobPostRecordEntityType = EntityMetadataCache.getDataEntityType(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID);
+        DynamicObject[] load = BusinessDataServiceHelper.load(result.toArray(new Long[0]), intJobPostRecordEntityType);
+        return Arrays.stream(load)
+                .collect(Collectors.toMap(
+                        obj -> obj.getLong(String.join(".", FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)),
+                        obj -> obj
+                ));
+    }
+
+    /**
+     * 查询最近的轨迹
+     * @param personIds 人员ID
+     * @return: java.util.Map<java.lang.Long, java.util.List < kd.bos.dataentity.entity.DynamicObject>>
+     * @author W.Y.C
+     * @date: 2026/01/13 15:56
+     */
+    public Map<Long, DynamicObject> findLatestLocusByPerson(List<Long> personIds) {
+        QueryFieldBuilder intJobPostLocus = QueryFieldBuilder.create().add(IntJobPostConstant.ID_KEY)
+                .add(FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY,FormConstant.ID_KEY)
+                .add(IntJobPostConstant.NCKD_ISCURRENTNEWEST)
+                .orderDesc(IntJobPostConstant.CREATE_TIME_KEY);
+        QFilter filter = new QFilter(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY), QCP.in, personIds);
+        DynamicObjectCollection records = QueryServiceHelper.query(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID, intJobPostLocus.buildSelect(), new QFilter[]{filter});
+        Set<Long> uniquePersonIds = new HashSet<>();
+        List<Long> result = new ArrayList<>();
+        for (DynamicObject record : records) {
+            Long personId = record.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY));
+            if (uniquePersonIds.add(personId)) { // 如果是新的personId,添加到结果中
+                result.add(record.getLong(IntJobPostConstant.ID_KEY));
+            }
+        }
+        MainEntityType intJobPostLocusEntityType = EntityMetadataCache.getDataEntityType(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID);
+        DynamicObject[] load = BusinessDataServiceHelper.load(result.toArray(new Long[0]), intJobPostLocusEntityType);
+        return Arrays.stream(load)
+                .collect(Collectors.toMap(
+                        obj -> obj.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)),
+                        obj -> obj
+                ));
+    }
+}

+ 26 - 15
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/stm/plugin/form/appr/GrpSalStlApprFormPlugin.java

@@ -101,20 +101,31 @@ public class GrpSalStlApprFormPlugin extends AbstractFormPlugin implements Plugi
                         List<DynamicObject> lastYearDataList = lastYearDataMap.get(unitId);
                         if(lastYearDataList != null && !lastYearDataList.isEmpty()){
                             DynamicObject lastYearData = lastYearDataList.get(0);
-                            if(lastYearData.containsProperty(StmConstant.NCKD_ENTRYENTITY)) {
-                                //上年实际计提工资总额与应提工资总额差额
-                                entry.set(StmConstant.NCKD_LYRACTVSEXPDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_LYRACTVSEXPDIFF)));
-                                //上年补提或冲回以前年度差额
-                                entry.set(StmConstant.NCKD_LYRPRIORADJDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_LYRPRIORADJDIFF)));
-                                //上年年薪人员差额
-                                entry.set(StmConstant.NCKD_LYRANNSALDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_LYRANNSALDIFF)));
-                                //上年任期激励差额
-                                entry.set(StmConstant.NCKD_LYRTERMBONUSDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_LYRTERMBONUSDIFF)));
-                                //上年组织绩效差额
-                                entry.set(StmConstant.NCKD_LYRORGPERFDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_LYRORGPERFDIFF)));
-                                //上年单项工资差额
-                                entry.set(StmConstant.NCKD_LYRITEMWGDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_LYRITEMWGDIFF)));
+                            //上年实际计提工资总额与应提工资总额差额
+                            if(lastYearData.containsProperty(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYACTVSEXPDIFF))) {
+                                entry.set(StmConstant.NCKD_LYRACTVSEXPDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYACTVSEXPDIFF)));
                             }
+                            //上年补提或冲回以前年度差额
+                            if(lastYearData.containsProperty(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYPRIORADJDIFF2))) {
+                                entry.set(StmConstant.NCKD_LYRPRIORADJDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYPRIORADJDIFF2)));
+                            }
+                            //上年年薪人员差额
+                            if(lastYearData.containsProperty(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYANNSALDIFF))) {
+                                entry.set(StmConstant.NCKD_LYRANNSALDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYANNSALDIFF)));
+                            }
+                            //上年任期激励差额
+                            if(lastYearData.containsProperty(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYTERMBONUSDIFF))) {
+                                entry.set(StmConstant.NCKD_LYRTERMBONUSDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYTERMBONUSDIFF)));
+                            }
+                            //上年组织绩效差额
+                            if(lastYearData.containsProperty(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYORGPERFDIFF))) {
+                                entry.set(StmConstant.NCKD_LYRORGPERFDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYORGPERFDIFF)));
+                            }
+                            //上年单项工资差额
+                            if(lastYearData.containsProperty(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYITEMWGDIFF))) {
+                                entry.set(StmConstant.NCKD_LYRITEMWGDIFF, lastYearData.getBigDecimal(String.join(".", StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_CYITEMWGDIFF)));
+                            }
+
                         }
                         Result avgMasPeopleNum = avgMasPeopleNumMap.get(unitId);
                         if(avgMasPeopleNum != null) {
@@ -274,7 +285,7 @@ public class GrpSalStlApprFormPlugin extends AbstractFormPlugin implements Plugi
     private Map<Long,List<DynamicObject>> getLastYearData(Date year, List<Long> unitIds){
         Date lastYear = DateUtil.minusYears(year, 1);
         Date beginDate = DateUtil.beginOfYear(lastYear);
-        Date endDate = DateUtil.endOfDay(lastYear);
+        Date endDate = DateUtil.endOfYear(lastYear);
         QFilter qFilter = new QFilter(StmConstant.NCKD_YEAR, QCP.large_equals,beginDate)
                 .and(StmConstant.NCKD_YEAR, QCP.less_equals, endDate)
                 .and(String.join(".",StmConstant.NCKD_ENTRYENTITY, StmConstant.NCKD_UNIT), QCP.in, unitIds);
@@ -462,7 +473,7 @@ public class GrpSalStlApprFormPlugin extends AbstractFormPlugin implements Plugi
             // 按单位分组并汇总任期激励金额
             return query.stream()
                     .collect(Collectors.groupingBy(
-                            obj -> obj.getLong(String.join(".", FormConstant.NCKD_ENTRYENTITY, MasConstant.NCKD_PAYUNIT, FormConstant.ID_KEY)),
+                            obj -> obj.getLong(String.join(".",  MasConstant.NCKD_PAYUNIT, FormConstant.ID_KEY)),
                             Collectors.reducing(
                                     BigDecimal.ZERO,
                                     obj -> obj.getBigDecimal(String.join(".", FormConstant.NCKD_ENTRYENTITY, MasConstant.NCKD_TOTALBONUSAMT)),

+ 7 - 2
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/stm/plugin/form/grpttlwg/GrpTtlWgBgtSubFormPlugin.java

@@ -90,6 +90,8 @@ public class GrpTtlWgBgtSubFormPlugin extends AbstractFormPlugin implements Plug
                 java.math.BigDecimal onpStNum = java.math.BigDecimal.ZERO;
                 // nckd_onpstwg:应发工资总额(万元)-其中:在岗职工
                 java.math.BigDecimal onpStWg = java.math.BigDecimal.ZERO;
+                // nckd_onpstwg:应发工资总额(万元)-其中:在岗职工
+                java.math.BigDecimal offpStNum = java.math.BigDecimal.ZERO;
                 // nckd_offpstliv:不在岗职工生活费
                 java.math.BigDecimal offpStLiv = java.math.BigDecimal.ZERO;
                 if (unitStBudgetApplyColl == null || unitStBudgetApplyColl.isEmpty()) {
@@ -106,8 +108,9 @@ public class GrpTtlWgBgtSubFormPlugin extends AbstractFormPlugin implements Plug
                         onpStNum = onpStNum.add(obj.getBigDecimal(StmConstant.NCKD_DMTEAMMEM) != null ? obj.getBigDecimal(StmConstant.NCKD_DMTEAMMEM) : java.math.BigDecimal.ZERO)
                                 .add(obj.getBigDecimal(StmConstant.NCKD_DMOTHER) != null ? obj.getBigDecimal(StmConstant.NCKD_DMOTHER) : java.math.BigDecimal.ZERO)
                                 .add(obj.getBigDecimal(StmConstant.NCKD_PROFMGR) != null ? obj.getBigDecimal(StmConstant.NCKD_PROFMGR) : java.math.BigDecimal.ZERO)
-                                .add(obj.getBigDecimal(StmConstant.NCKD_NONDIRONPOST) != null ? obj.getBigDecimal(StmConstant.NCKD_NONDIRONPOST) : java.math.BigDecimal.ZERO)
-                                .add(obj.getBigDecimal(StmConstant.NCKD_OFFPOST) != null ? obj.getBigDecimal(StmConstant.NCKD_OFFPOST) : java.math.BigDecimal.ZERO);
+                                .add(obj.getBigDecimal(StmConstant.NCKD_NONDIRONPOST) != null ? obj.getBigDecimal(StmConstant.NCKD_NONDIRONPOST) : java.math.BigDecimal.ZERO);
+//                                .add(obj.getBigDecimal(StmConstant.NCKD_OFFPOST) != null ? obj.getBigDecimal(StmConstant.NCKD_OFFPOST) : java.math.BigDecimal.ZERO);
+                        offpStNum =  offpStNum.add(obj.getBigDecimal(StmConstant.NCKD_OFFPOST) != null ? obj.getBigDecimal(StmConstant.NCKD_OFFPOST) : java.math.BigDecimal.ZERO);
 
                         /*15+21+25+29
                         工资总额:nckd_totalwage
@@ -131,9 +134,11 @@ public class GrpTtlWgBgtSubFormPlugin extends AbstractFormPlugin implements Plug
 
                 // 设置汇总值到界面
                 this.getModel().setValue(StmConstant.NCKD_ONPSTNUM, onpStNum);
+                this.getModel().setValue(StmConstant.NCKD_OFFPSTNUM, offpStNum);
                 this.getModel().setValue(StmConstant.NCKD_ONPSTWG, onpStWg);
                 this.getModel().setValue(StmConstant.NCKD_OFFPSTLIV, offpStLiv);
                 this.getView().updateView(StmConstant.NCKD_ONPSTNUM);
+                this.getView().updateView(StmConstant.NCKD_OFFPSTNUM);
                 this.getView().updateView(StmConstant.NCKD_ONPSTWG);
                 this.getView().updateView(StmConstant.NCKD_OFFPSTLIV);
 

+ 1 - 1
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/stm/plugin/form/unitst/UnitStBudgetApplyFormPlugin.java

@@ -178,7 +178,7 @@ public class UnitStBudgetApplyFormPlugin extends AbstractFormPlugin implements P
                             .distinct()
                             .collect(Collectors.joining(","));
                 }else{
-                    this.getView().showTipNotification(StrFormatter.format("【{}】直属下级单位没有【{}】年度预算数据", payUnit.getString(FormConstant.NAME_KEY),beginOfYear.getYear()));
+                    this.getView().showTipNotification(StrFormatter.format("【{}】直属下级单位没有【{}】年度预算数据", payUnit.getString(FormConstant.NAME_KEY),DateUtil.getYear(beginOfYear)));
                 }
                 if(!summaryMap.isEmpty()) {
                     List<String> summaryList = new ArrayList<>();