Просмотр исходного кода

feat(hr): 添加优秀生津贴功能

- 在FormConstant中新增NCKD_MONEY常量
- 重命名EXCELLENTSSALLOWANCE_ENTITYID常量以提高可读性
- 新增ExcellentssAllowanceValiDate验证器实现人员定薪档案验证
- 新增PushAdjustOpPlugin插件实现推送调薪功能
- 实现定调薪申请单的自动创建和数据推送
- 添加审批状态和推送时间字段的自动更新
wyc 1 неделя назад
Родитель
Сommit
6f5b230745

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

@@ -490,5 +490,7 @@ public class FormConstant {
     public static final String NCKD_ISHIGHDEG = "nckd_ishighdeg";
     /**全日制*/
     public static final String ISFULLTIME = "isfulltime";
+    /**全日制*/
+    public static final String NCKD_MONEY = "nckd_money";
 
 }

+ 1 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/excells/common/ExcellsConstant.java

@@ -11,7 +11,7 @@ import nckd.jxccl.base.common.constant.FormConstant;
  */
 public class ExcellsConstant extends FormConstant {
     /** 优秀生津贴-实体标识 */
-    public static final String ENTITYID = "nckd_excellentssallowance";
+    public static final String EXCELLENTSSALLOWANCE_ENTITYID = "nckd_excellentssallowance";
     /** 金额 */
     public static final String NCKD_MONEY = "nckd_money";
     /** 生效日期 */

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


+ 230 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/excells/plugin/operate/PushAdjustOpPlugin.java

@@ -0,0 +1,230 @@
+package nckd.jxccl.hr.excells.plugin.operate;
+
+import com.alibaba.fastjson.JSON;
+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.db.tx.TX;
+import kd.bos.db.tx.TXHandle;
+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.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.entity.validate.BillStatus;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.DispatchServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.sdk.plugin.Plugin;
+import kd.sdk.swc.hcdm.business.helper.HCDMApplyBillServiceHelper;
+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.StrFormatter;
+import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
+import nckd.jxccl.hr.excells.common.ExcellsConstant;
+import nckd.jxccl.hr.psms.common.PositionStructureConstant;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 优秀生-推送调薪
+* 实体标识:nckd_excellentssallowance
+* @author W.Y.C
+* @date 2026/1/3 15:11
+* @version 1.0
+*/
+public class PushAdjustOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(PushAdjustOpPlugin.class);
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+    }
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        e.getFieldKeys().addAll(this.billEntityType.getAllFields().keySet());
+    }
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        List<Long> ids = new ArrayList<>();
+        List<Long> personIds = new ArrayList<>();
+        for (DynamicObject data : e.getDataEntities()) {
+            DynamicObjectCollection entitys = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+            for (DynamicObject entity : entitys) {
+                personIds.add(entity.getLong(String.join(".",FormConstant.NCKD_PERSON,FormConstant.ID_KEY)));
+            }
+            ids.add(data.getLong(FormConstant.ID_KEY));
+        }
+
+        //获取员工最新任职
+        Map<Long, DynamicObject> empPosOrgRelByEmployeesMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
+        List<Long> allEmpPosOrgRelIds = empPosOrgRelByEmployeesMap.values().stream()
+                .map(result -> result.getLong(FormConstant.ID_KEY))
+                .collect(Collectors.toList());
+
+        Map<String, Object> adjFileParams = new HashMap<>();
+        adjFileParams.put("employees", personIds);
+        List<String> status = new ArrayList<>();
+        status.add(BillStatus.C.toString());
+        adjFileParams.put("status", status);
+        //获取人员定薪档案
+        Map<String, Object> adjFileResult = DispatchServiceHelper.invokeBizService("swc", "hcdm", "IAdjFileInfoService", "queryAdjFileBoByEmp", adjFileParams);
+        Map<Long,Long> adjFileIdMap = new HashMap<>();
+        //key:定调薪档案ID,Value:发薪组织ID
+        Map<Long,Long> adjFileOrgIdMap = new HashMap<>();
+        if (ConvertUtil.toBoolean(adjFileResult.get("success"))) {
+            List<Map> list = ConvertUtil.toList(adjFileResult.get("data"), ArrayList::new);
+            for (Map map : list) {
+                Long id = ConvertUtil.toLong(map.get(FormConstant.ID_KEY));
+                //根据员工任职匹配
+                Long empPosOrgRelId = ConvertUtil.toLong(map.get("empposorgrel_id"));
+                if (allEmpPosOrgRelIds.contains(empPosOrgRelId)) {
+                    adjFileIdMap.put(ConvertUtil.toLong(map.get("employee_id")),id);
+                    adjFileOrgIdMap.put(id,ConvertUtil.toLong(map.get("org_id")));
+                }
+            }
+        }
+        //多人可能存在不同发薪组织,按单据和组织拆分定调薪单据。key:单据id-组织ID,value:申请单数据
+        Map<String,Map<String, Object>> applyBillMap = new HashMap<>();
+        for (DynamicObject data : e.getDataEntities()) {
+            boolean isSalAdjPush = data.getBoolean(PositionStructureConstant.NCKD_ISSALADJPUSH);
+            if(isSalAdjPush){
+                logger.warn("优秀生津贴单据号【{}】已推送过优秀生津贴申请单,忽略此次执行。",data.getString(FormConstant.BILL_NO_KEY));
+                continue;
+            }
+            long id = data.getLong(FormConstant.ID_KEY);
+            DynamicObject org = data.getDynamicObject(FormConstant.NCKD_ORG);
+            DynamicObject creator = data.getDynamicObject(FormConstant.CREATOR_KEY);
+
+            DynamicObjectCollection entitys = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+            for (DynamicObject entity : entitys) {
+                DynamicObject person = entity.getDynamicObject(FormConstant.NCKD_PERSON);
+                Long employeeId = person.getLong(FormConstant.ID_KEY);
+                Long adjFileId = adjFileIdMap.get(employeeId);
+                Long orgId = adjFileOrgIdMap.get(adjFileId);
+                Map<String, Object> applyBill = applyBillMap.computeIfAbsent(id+"-"+orgId, k -> new HashMap<>());
+                applyBill.put("billname", StrFormatter.format("【{}】申请的优秀生津贴,申请单号:【{}】",creator.getString(FormConstant.NAME_KEY),data.getString(FormConstant.BILL_NO_KEY)));
+                applyBill.put("_uniquecode", data.getLong(FormConstant.ID_KEY));
+                applyBill.put("org", orgId);
+                //定调薪明细字段显示方案   调薪明细字段
+                applyBill.put("billtype", 2215975998602655744L);
+                //国家
+                applyBill.put("billcountry", 1000001L);
+                //定调薪类型(优秀生津贴)
+                applyBill.put("salaryadjrsn", 2352338051369287680L);
+                //默认币种
+                applyBill.put("billcurrency", 1L);
+                //定调薪方案
+                applyBill.put("salaryadjscm", 2322515162646457344L);
+                //汇率日期
+                applyBill.put("exchangeratedate", new Date());
+                //汇率表
+                applyBill.put("exctable", 2321965096026258432L);
+                //默认生效日期
+                applyBill.put("effectivedate", data.getDate(FormConstant.CREATE_TIME_KEY));
+                //草稿状态
+                applyBill.put("isdraft", "1");
+                //审核状态
+                applyBill.put("auditstatus", "A");
+                //申请单数据来源   //1:手工新增  2:接口写入
+                applyBill.put("datasource", "2");
+                applyBill.put("description",  StrFormatter.format("【{}】申请的优秀生津贴,申请单号:【{}】,申请日期:【{}】",creator.getString(FormConstant.NAME_KEY),data.getString(FormConstant.BILL_NO_KEY), DateUtil.format(data.getDate(FormConstant.CREATE_TIME_KEY),DateUtil.NORM_DATETIME_PATTERN)));
+                List<Map<String, Object>> applyBillEntryData = (List<Map<String, Object>>) applyBill.computeIfAbsent("applybillent", k -> new ArrayList<Map<String, Object>>());
+
+                DynamicObject position = entity.getDynamicObject(FormConstant.NCKD_POSITION_KEY);
+                Map<String, Object> applyBillEntry = new HashMap<>();
+                applyBillEntry.put("adjfile", adjFileId);
+                applyBillEntry.put("employee", employeeId);
+                applyBillEntry.put("standarditem", 2321901326927149056L);    //定调薪项目
+                applyBillEntry.put("frequency", 1095454108284088320L);       //频度  月
+                applyBillEntry.put("amount", entity.getBigDecimal(FormConstant.NCKD_MONEY));
+                applyBillEntry.put("position", position.getLong(FormConstant.ID_KEY));
+                applyBillEntry.put("reason", entity.getString(ExcellsConstant.NCKD_DESC));
+                applyBillEntryData.add(applyBillEntry);
+                applyBill.put("applybillent", applyBillEntryData);
+                applyBillMap.put(id+"-"+orgId, applyBill);
+            }
+        }
+        if(!applyBillMap.isEmpty()) {
+            List<DynamicObject> saveDynamicObjects = new ArrayList<>();
+
+            Map<String, Object> papams = new HashMap<>();
+            List<Map<String, Object>> applybillList = new ArrayList<>();
+            for (Map.Entry<String, Map<String, Object>> stringMapEntry : applyBillMap.entrySet()) {
+                applybillList.add(stringMapEntry.getValue());
+            }
+            papams.put("data", applybillList);
+            papams.put("isUseMatchAmount", Boolean.TRUE);
+            Map<String, Object> result = HCDMApplyBillServiceHelper.saveDraftApplyBill(papams);
+            logger.info("推送定调薪结果:{}", JSON.toJSONString(result));
+
+            if (!ConvertUtil.toBoolean(result.get("success")) || result.get("data") == null || ConvertUtil.toList(result.get("data")).isEmpty()) {
+                logger.error("推送定调薪失败,原因:{}", JSON.toJSONString(result));
+                throw new ValidationException("推送定调薪失败,原因:" + JSON.toJSONString(result));
+            } else {
+                MainEntityType depEmpEntityType = EntityMetadataCache.getDataEntityType(ExcellsConstant.EXCELLENTSSALLOWANCE_ENTITYID);
+                DynamicObject[] load = BusinessDataServiceHelper.load(ids.toArray(new Long[0]), depEmpEntityType);
+                List<Map<String, Object>> list = ConvertUtil.toList(result.get("data"));
+                for (DynamicObject dynamicObject : load) {
+                    long id = dynamicObject.getLong(FormConstant.ID_KEY);
+                    for (Map<String, Object> dataMap : list) {
+                        Long uniqueCode = ConvertUtil.toLong(dataMap.get("_uniquecode"));
+                        if (id == uniqueCode) {
+                            dynamicObject.set(PositionStructureConstant.NCKD_ISSALADJPUSH, Boolean.TRUE);
+                            dynamicObject.set(PositionStructureConstant.NCKD_SALADJPUSHTIME, new Date());
+                            dynamicObject.set(PositionStructureConstant.NCKD_SALADJID, ConvertUtil.toMap(dataMap.get("id")));
+                        }
+                        logger.info("成功推送的定调薪申请单,申请单ID: {}",uniqueCode);
+                        saveDynamicObjects.add(dynamicObject);
+                    }
+                }
+//                SaveServiceHelper.update(load);
+            }
+            //独立事务隔离跨库操作
+            if (!saveDynamicObjects.isEmpty()) {
+                TXHandle tx = TX.requiresNew();
+                try {
+                    OperationResult operationResult = SaveServiceHelper.saveOperate(ExcellsConstant.EXCELLENTSSALLOWANCE_ENTITYID, saveDynamicObjects.toArray(new DynamicObject[0]), OperateOption.create());
+                    if (!operationResult.isSuccess()) {
+                        StringJoiner errorMsg = new StringJoiner("\n");
+                        for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+                            errorMsg.add(error.getMessage());
+                        }
+                        if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
+                            errorMsg.add(operationResult.getMessage());
+                        }
+                        logger.error("保存职位津贴失败,原因:{}", errorMsg.toString());
+                        tx.markRollback();
+                        throw new ValidationException("保存职位津贴失败,原因:" + errorMsg.toString());
+                    } else {
+                        tx.commit();
+                        logger.info("成功保存 {} 条职位津贴记录", saveDynamicObjects.size());
+                    }
+                } catch (Exception ex) {
+                    tx.markRollback();
+                    throw ex;
+                } finally {
+                    tx.close();
+                }
+            }
+        }
+    }
+}

+ 83 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/excells/plugin/operate/validate/ExcellentssAllowanceValiDate.java

@@ -0,0 +1,83 @@
+package nckd.jxccl.hr.excells.plugin.operate.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 kd.bos.entity.validate.BillStatus;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.servicehelper.DispatchServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+* 优秀生津贴验证
+* 实体标识:nckd_excellentssallowance
+* @author W.Y.C
+* @date 2026/1/3 16:34
+* @version 1.0
+*/
+public class ExcellentssAllowanceValiDate extends AbstractValidator {
+
+    @Override
+    public void validate() {
+        List<Long> personIds = new ArrayList<>();
+        for (ExtendedDataEntity dataEntity : this.getDataEntities()) {
+            DynamicObject data = dataEntity.getDataEntity();
+            DynamicObjectCollection entrys = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+            for (DynamicObject entry : entrys) {
+                personIds.add(entry.getLong(String.join( ".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY)));
+            }
+        }
+        if(!personIds.isEmpty()) {
+            //获取员工最新任职
+            Map<Long, DynamicObject> empPosOrgRelByEmployeesMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
+            List<Long> allEmpPosOrgRelIds = empPosOrgRelByEmployeesMap.values().stream()
+                    .map(result -> result.getLong(FormConstant.ID_KEY))
+                    .collect(Collectors.toList());
+
+            Map<String, Object> adjFileParams = new HashMap<>();
+            adjFileParams.put("employees", personIds);
+            List<String> status = new ArrayList<>();
+            status.add(BillStatus.C.toString());
+            adjFileParams.put("status", status);
+            //获取人员定薪档案
+            Map<String, Object> adjFileResult = DispatchServiceHelper.invokeBizService("swc", "hcdm", "IAdjFileInfoService", "queryAdjFileBoByEmp", adjFileParams);
+            Map<Long, Long> adjFileIdMap = new HashMap<>();
+            if (ConvertUtil.toBoolean(adjFileResult.get("success"))) {
+                List<Map> list = ConvertUtil.toList(adjFileResult.get("data"), ArrayList::new);
+                for (Map map : list) {
+                    Long id = ConvertUtil.toLong(map.get(FormConstant.ID_KEY));
+                    //根据员工任职匹配
+                    Long empPosOrgRelId = ConvertUtil.toLong(map.get("empposorgrel_id"));
+                    if (allEmpPosOrgRelIds.contains(empPosOrgRelId)) {
+                        adjFileIdMap.put(ConvertUtil.toLong(map.get("employee_id")), id);
+                    }
+                }
+            }
+            for (ExtendedDataEntity dataEntity : this.getDataEntities()) {
+                DynamicObject data = dataEntity.getDataEntity();
+                DynamicObjectCollection entrys = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+                for (DynamicObject entry : entrys) {
+                    DynamicObject person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
+                    if(person != null) {
+                        long personId = person.getLong(FormConstant.ID_KEY);
+                        String personName = person.getString(FormConstant.NAME_KEY);
+                        if (adjFileIdMap.get(personId) == null) {
+                            this.addFatalErrorMessage(dataEntity, StrFormatter.format("人员【{}】定薪档案不存在", personName));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}