Jelajahi Sumber

Merge branch 'refs/heads/feat-opmc-pm_1.0'

wyc 1 Minggu lalu
induk
melakukan
ee6c00798b

+ 4 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/common/PerfRankMgmtConstant.java

@@ -95,5 +95,9 @@ public class PerfRankMgmtConstant extends FormConstant {
     public static final String NCKD_APPRAISALYEAR = "nckd_appraisalyear";
     /** 分录-是否来源全排名 */
     public static final String NCKD_ISALLRANKSOURCE = "nckd_isallranksource";
+    /** 实际周期结束年份 */
+    public static final String NCKD_ACTENDYEAR = "nckd_actendyear";
+    /** 周期状态 */
+    public static final String NCKD_THESTATUS = "nckd_thestatus";
     /*-------------------------------------- 考核周期(人员考评) end --------------------------------------*/
 }

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

@@ -10,11 +10,10 @@ import kd.bos.entity.EntityMetadataCache;
 import kd.bos.entity.QueryEntityType;
 import kd.bos.entity.constant.StatusEnum;
 import kd.bos.entity.datamodel.IDataModel;
+import kd.bos.entity.datamodel.ListSelectedRow;
+import kd.bos.entity.datamodel.ListSelectedRowCollection;
 import kd.bos.entity.datamodel.RowDataEntity;
-import kd.bos.entity.datamodel.events.AfterAddRowEventArgs;
-import kd.bos.entity.datamodel.events.BeforeImportEntryEventArgs;
-import kd.bos.entity.datamodel.events.ChangeData;
-import kd.bos.entity.datamodel.events.PropertyChangedArgs;
+import kd.bos.entity.datamodel.events.*;
 import kd.bos.ext.hr.service.query.QueryEntityHelper;
 import kd.bos.form.ConfirmCallBackListener;
 import kd.bos.form.ConfirmTypes;
@@ -22,6 +21,7 @@ import kd.bos.form.IClientViewProxy;
 import kd.bos.form.MessageBoxOptions;
 import kd.bos.form.MessageBoxResult;
 import kd.bos.form.container.Wizard;
+import kd.bos.form.control.EntryGrid;
 import kd.bos.form.control.Steps;
 import kd.bos.form.events.AfterDoOperationEventArgs;
 import kd.bos.form.events.BeforeDoOperationEventArgs;
@@ -32,6 +32,7 @@ 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 nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.constant.SystemQueryConstant;
@@ -40,21 +41,17 @@ import nckd.jxccl.base.common.enums.psms.JobSeqEnum;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
+import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
 import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant;
 import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import org.apache.commons.lang3.StringUtils;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.EventObject;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -203,12 +200,98 @@ public class PerfrankMgmtFormPlugin extends AbstractFormPlugin {
                     );
                 }
             }
-        }else if(Arrays.asList(FormConstant.SAVE_OP, FormConstant.SUBMIT_OP).contains(itemKey)){
+        } else if(Arrays.asList(FormConstant.SAVE_OP, FormConstant.SUBMIT_OP).contains(itemKey)){
             //保存或提交先计算一遍
             // calcRankCount();
+        } else if(FormConstant.DELETEENTRY_OP.equalsIgnoreCase(itemKey)){
+            //校验人员考评,若考评周期已结束,则禁止删除。
+            EntryGrid entryGrid = getView().getControl(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+            if (entryGrid != null) {
+                Integer theYear = ConvertUtil.toInt(this.getModel().getValue(PerfRankMgmtConstant.NCKD_THEYEAR));
+                LocalDate startDate = LocalDate.of(theYear, 1, 1);
+                // 获取选中行索引数组
+                int[] selectedRows = entryGrid.getSelectRows();
+                List<Long> personIds = new ArrayList<>();
+                if (selectedRows.length > 0) {
+                    for (int rowIndex : selectedRows) {
+                        DynamicObjectCollection entryEntity = this.getModel().getEntryEntity(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+                        DynamicObject rowData = entryEntity.get(rowIndex);
+                        DynamicObject person = rowData.getDynamicObject(FormConstant.NCKD_PERSON);
+                        long personId = person.getLong(FormConstant.ID_KEY);
+                        personIds.add(personId);
+                    }
+
+                    if(!personIds.isEmpty()){
+                        DynamicObject[] byDate = getByDate(DateUtil.toDate(startDate), personIds);
+                        for (DynamicObject dynamicObject : byDate) {
+                            String theStatus = dynamicObject.getString(PerfRankMgmtConstant.NCKD_THESTATUS);
+                            DynamicObject person = dynamicObject.getDynamicObject(FormConstant.NCKD_PERSON);
+                            if(!EnableEnum.YES.getCode().equals(theStatus)){
+                                DynamicObjectCollection entryList = dynamicObject.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY);
+                                for (DynamicObject object : entryList) {
+                                    LocalDateTime appraisalYear = DateUtil.toLocalDateTime(object.getDate(PerfRankMgmtConstant.NCKD_APPRAISALYEAR));
+                                    int year = appraisalYear.getYear();
+                                    if(year == theYear){
+                                        this.getView().showTipNotification(StrFormatter.format("所选人员【{}】考评周期【{}】,不能删除",person.getString(FormConstant.NAME_KEY),"2".equals(theStatus) ? "已锁定":"已结束"));
+                                        args.setCancel(true);
+                                    }
+                                }
+
+                            }
+                        }
+                    }
+                }
+            }
         }
     }
 
+
+    /**
+     * 根据日期查询范围内的考核周期
+     * 查询逻辑说明:
+     * 1. 开始时间条件:考核周期的开始年份(NCKD_BEGINYEAR)必须小于等于指定日期
+     * 2. 结束时间条件:优先使用实际结束年份(NCKD_ACTENDYEAR),如果为空则使用计划结束年份(NCKD_ENDYEAR)
+     * 3. 结束时间必须大于等于指定日期
+     * 4. 即查找满足 "NCKD_BEGINYEAR <= date <= (NCKD_ACTENDYEAR为空时取NCKD_ENDYEAR)" 条件的考核周期
+     *
+     * @param date      指定查询日期
+     * @param personIds 人员ID集合
+     * @return 符合条件的考核周期数组
+     * @author W.Y.C
+     * @date 2025/11/4 17:06
+     */
+    public static DynamicObject[] getByDate(Date date, Collection<Long> personIds) {
+        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                .add(FormConstant.ID_KEY)
+                .addIdNumberName(FormConstant.NCKD_EMPPOSORGREL)
+                .addIdNumberName(FormConstant.NCKD_PERSON)
+                .add(PerfRankMgmtConstant.NCKD_THESTATUS)
+                .addGroup(new String[]{PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY},
+                        PerfRankMgmtConstant.NCKD_APPRAISALRESULT,
+                        PerfRankMgmtConstant.NCKD_APPRAISALYEAR,
+                        PerfRankMgmtConstant.NCKD_ISALLRANKSOURCE);
+
+        // 构造查询条件:日期在[NCKD_BEGINYEAR, NCKD_ENDYEAR]范围内
+        // 考虑到NCKD_ACTENDYEAR可能为空,优先使用NCKD_ACTENDYEAR作为结束时间
+        QFilter filter = new QFilter(PerfRankMgmtConstant.NCKD_BEGINYEAR, QCP.less_equals, date)
+                .and(new QFilter(PerfRankMgmtConstant.NCKD_PERSON, QCP.in, personIds));
+
+        // 添加结束时间判断逻辑
+        QFilter endDateFilter = new QFilter(PerfRankMgmtConstant.NCKD_ACTENDYEAR, QCP.large_equals, date)
+                .or(new QFilter(PerfRankMgmtConstant.NCKD_ACTENDYEAR, QCP.is_null, null)
+                        .and(new QFilter(PerfRankMgmtConstant.NCKD_ENDYEAR, QCP.large_equals, date)));
+
+        filter.and(endDateFilter);
+
+        return BusinessDataServiceHelper.load(PerfRankMgmtConstant.PERFMANAGER_ENTITYID,
+                queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+    }
+
+    @Override
+    public void beforeDeleteRow(BeforeDeleteRowEventArgs e) {
+        super.beforeDeleteRow(e);
+    }
+
     @Override
     public void confirmCallBack(MessageBoxClosedEvent evt) {
         super.confirmCallBack(evt);
@@ -373,7 +456,7 @@ public class PerfrankMgmtFormPlugin extends AbstractFormPlugin {
 
     private void importResultStep() {
         this.getModel().setValue(PerfRankMgmtConstant.NCKD_STEP,1);
-        this.getView().setVisible(false, FormConstant.NUMBER_KEY, FormConstant.NAME_KEY, FormConstant.NCKD_ADMINORG, PerfRankMgmtConstant.NCKD_THEYEAR, PerfRankMgmtConstant.NCKD_GETRANKLIST);
+        this.getView().setVisible(false, FormConstant.NUMBER_KEY, PerfRankMgmtConstant.NCKD_GETRANKLIST);
         this.getView().setVisible(true, PerfRankMgmtConstant.NCKD_TOPRANKS, PerfRankMgmtConstant.NCKD_ALLOWANCERANKS, PerfRankMgmtConstant.NCKD_FAILS, PerfRankMgmtConstant.NCKD_BASICS, PerfRankMgmtConstant.NCKD_EXCELLENTS, "nckd_advconbaritemap6");
         DynamicObjectCollection entryEntity = this.getModel().getEntryEntity(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
         for (int i = 0; i < entryEntity.size(); i++) {

+ 83 - 18
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/PerfRankMgmtSaveOpPlugin.java

@@ -25,6 +25,7 @@ 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.hrpi.helper.EmpPosOrgRelHelper;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant;
 import nckd.jxccl.hr.psms.plugin.operate.performance.validate.PerfRankMgmtSaveValidate;
@@ -53,24 +54,64 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
         e.addValidator(new PerfRankMgmtSaveValidate());
     }
 
+    private Map<Long,List<Long>> dbPersonMap = new HashMap<>();
+
     @Override
     public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        String invoker = (String)this.getOption().getVariables().get(FormConstant.HR_INVOKER_PARAM_INVOKER);
+        boolean dataMigration = FormConstant.DATA_MIGRATION.equalsIgnoreCase(invoker);
         for (DynamicObject dataEntity : e.getDataEntities()) {
+
+            //事务开始前先查询数据库中的排名名单,找出哪些是此次被删除的人员
+            QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                    .addIdNumberName(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY,FormConstant.NCKD_PERSON);
+            QFilter qFilter = new QFilter(FormConstant.ID_KEY, QCP.equals, dataEntity.getLong(FormConstant.ID_KEY));
+            DynamicObjectCollection dbEntryList = QueryServiceHelper.query(PerfRankMgmtConstant.NCKD_PERFRANKMGMT_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{qFilter});
+
+            // 获取数据库中存在的人员ID列表
+            List<Long> dbPersonIds = dbEntryList.stream()
+                    .map(dbEntry -> dbEntry.getLong(String.join(".", PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY,FormConstant.NCKD_PERSON, FormConstant.ID_KEY)))
+                    .collect(Collectors.toList());
+            dbPersonMap.put(dataEntity.getLong(FormConstant.ID_KEY), dbPersonIds);
+
+            List<Long> personids = new ArrayList<>();
             DynamicObjectCollection entryList = dataEntity.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
             for (DynamicObject entry : entryList) {
                 DynamicObject person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
-                if(person == null){
-                    DynamicObject empPosOrgRel = entry.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL);
+                DynamicObject empPosOrgRel = entry.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL);
+                if(person == null && empPosOrgRel != null){
                     entry.set(FormConstant.NCKD_PERSON, empPosOrgRel.getDynamicObject(FormConstant.EMPLOYEE_KEY));
                 }
+                person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
+                if(person != null) {
+                    personids.add(person.getLong(FormConstant.ID_KEY));
+                }
+            }
+            if(dataMigration){
+                //数据迁移逻辑
+                DynamicObject[] dbEmpPosOrgRelList = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployees(personids);
+                for (DynamicObject entry : entryList) {
+                    DynamicObject person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
+                    DynamicObject empPosOrgRel = entry.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL);
+                    if(empPosOrgRel == null){
+                        long personId = person.getLong(FormConstant.ID_KEY);
+                        for (DynamicObject ebEmpPosOrgRel : dbEmpPosOrgRelList) {
+                            long employeeId = ebEmpPosOrgRel.getDynamicObject(FormConstant.EMPLOYEE_KEY).getLong(FormConstant.ID_KEY);
+                            if(Objects.equals(personId, employeeId)){
+                                entry.set(FormConstant.NCKD_EMPPOSORGREL, ebEmpPosOrgRel);
+                                break;
+                            }
+                        }
+                    }
+                }
             }
-
         }
 
     }
 
     @Override
     public void endOperationTransaction(EndOperationTransactionArgs e) {
+        //-------------------------------- 同步人员考评 begin --------------------------------
         //先查询人员对应考核周期
         for (DynamicObject data : e.getDataEntities()) {
             int theYear = data.getInt(PerfRankMgmtConstant.NCKD_THEYEAR);
@@ -94,9 +135,17 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
                                 entry -> entry.getDynamicObject(PerfRankMgmtConstant.NCKD_APPRAISALRESULT)
                         ));
 
+
+                List<Long> dbPersonIds = dbPersonMap.get(data.getLong(FormConstant.ID_KEY));
+                // 找出在数据库中存在但在当前列表中不存在的人员ID(即被删除的人员)
+                List<Long> deletedPersonIds = dbPersonIds.stream()
+                        .filter(dbPersonId -> !personIds.contains(dbPersonId))
+                        .collect(Collectors.toList());
+                if(!deletedPersonIds.isEmpty()){
+                    personIds.addAll(deletedPersonIds);
+                }
                 //获取考核周期
                 List<Long> perfManagerIds = findPerfManager(theYear, personIds);
-
                 QFilter filter = QFilterCommonHelper.getIdInFilter(perfManagerIds);
                 MainEntityType dataEntityType = MetadataServiceHelper.getDataEntityType(PerfRankMgmtConstant.PERFMANAGER_ENTITYID);
                 DynamicObject[] perfManagerArray = BusinessDataServiceHelper.load(perfManagerIds.toArray(new Long[0]), dataEntityType);
@@ -106,23 +155,38 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
                 for (DynamicObject perfManager : perfManagerArray) {
                     DynamicObject person = perfManager.getDynamicObject(FormConstant.NCKD_PERSON);
                     long personId = person.getLong(FormConstant.ID_KEY);
-                    DynamicObjectCollection perfManagerEntryColl = perfManager.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY);
-                    boolean isExist = false;
-                    for (DynamicObject perfManagerEntry : perfManagerEntryColl) {
-                        LocalDateTime appraisalYear = DateUtil.toLocalDateTime(perfManagerEntry.getDate(PerfRankMgmtConstant.NCKD_APPRAISALYEAR));
-                        int year = appraisalYear.getYear();
-                        if(year == theYear){
+                    if(deletedPersonIds.contains(personId)){
+                        //此次删除的人员同步删除人员考评的考核结果
+                        DynamicObjectCollection perfManagerEntryColl = perfManager.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY);
+                        Iterator<DynamicObject> iterator = perfManagerEntryColl.iterator();
+                        while (iterator.hasNext()) {
+                            DynamicObject perfManagerEntry = iterator.next();
+                            LocalDateTime appraisalYear = DateUtil.toLocalDateTime(perfManagerEntry.getDate(PerfRankMgmtConstant.NCKD_APPRAISALYEAR));
+                            int year = appraisalYear.getYear();
+                            if(year == theYear){
+                                iterator.remove();
+                            }
+                        }
+                    }else{
+                        DynamicObjectCollection perfManagerEntryColl = perfManager.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY);
+                        boolean isExist = false;
+                        for (DynamicObject perfManagerEntry : perfManagerEntryColl) {
+                            LocalDateTime appraisalYear = DateUtil.toLocalDateTime(perfManagerEntry.getDate(PerfRankMgmtConstant.NCKD_APPRAISALYEAR));
+                            int year = appraisalYear.getYear();
+                            if(year == theYear){
+                                perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALRESULT, personAppraisalMap.get(personId));
+                                isExist = true;
+                                break;
+                            }
+                        }
+                        if(!isExist){
+                            DynamicObject perfManagerEntry = perfManagerEntryColl.addNew();
+                            perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALYEAR,appraisalYearDate);
                             perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALRESULT, personAppraisalMap.get(personId));
-                            isExist = true;
-                            break;
+                            perfManagerEntry.set(PerfRankMgmtConstant.NCKD_ISALLRANKSOURCE, EnableEnum.YES.getCode());
                         }
                     }
-                    if(!isExist){
-                        DynamicObject perfManagerEntry = perfManagerEntryColl.addNew();
-                        perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALYEAR,appraisalYearDate);
-                        perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALRESULT, personAppraisalMap.get(personId));
-                        perfManagerEntry.set(PerfRankMgmtConstant.NCKD_ISALLRANKSOURCE, EnableEnum.YES.getCode());
-                    }
+
                 }
                 OperateOption option = OperateOption.create();
                 option.setVariableValue(OperateOptionConst.IGNOREINTERACTION, Boolean.TRUE+"");
@@ -142,6 +206,7 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
                 }
             }
         }
+        //-------------------------------- 同步人员考评 end --------------------------------
     }
 
 

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

@@ -262,8 +262,13 @@ public class PerfRankMgmtSaveValidate extends AbstractValidator {
      */
     private void validateEntry(DynamicObject entry, ExtendedDataEntity rowDataEntity,
                                int rowIndex, Set<Long> personIds, ValidationContext context) {
+        String invoker = (String)this.getOption().getVariables().get(FormConstant.HR_INVOKER_PARAM_INVOKER);
+        boolean dataMigration = FormConstant.DATA_MIGRATION.equalsIgnoreCase(invoker);
+        DynamicObject empPosOrgRel = entry.getDynamicObject(PerfRankMgmtConstant.NCKD_EMPPOSORGREL);
         DynamicObject person = entry.getDynamicObject(PerfRankMgmtConstant.NCKD_PERSON);
-        if (person == null) {
+        if(!dataMigration && empPosOrgRel == null){
+            this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("第{}行,请选择人员\n", rowIndex));
+        }else if (person == null) {
             this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("第{}行,请选择人员\n", rowIndex));
         } else {
             // 人员重复校验