1
0

13 کامیت‌ها cba705216d ... 570ab4414c

نویسنده SHA1 پیام تاریخ
  wyc 570ab4414c feat(hr): 实现新入职与在职人员初定导入插件- 新增 ScoreInitialImportPlugin 插件类,支持初定导入模板筛选 3 روز پیش
  wyc ea39793654 Merge branch 'refs/heads/feat-hr-psms_1.0' 4 روز پیش
  Tyx 54ebff7fb8 feat(report): 新增外部系统人员详情数据查询功能 4 روز پیش
  Tyx 823370e065 feat(report): 人员薪酬分类表单插件 && 外部数据比对报表插件 5 روز پیش
  Tyx 7a5fcbdfa0 feat(agency-bill): 新增单位代发单表单插件 5 روز پیش
  Tyx 2e2eef262d feat(build): 新增wtc zip打包任务 5 روز پیش
  turborao e137c5cd1c feat(business):优化基础医疗津贴计算逻辑并增强日志记录新增日志记录功能,用于输出员工岗位相关信息。 5 روز پیش
  turborao 26b39806d0 ``` 6 روز پیش
  turborao 3dd313077e ``` 6 روز پیش
  turborao d3b0faeef9 feat(plugin): 新增基础医疗津贴计算后台任务插件 6 روز پیش
  turborao 9e32259bfe feat(BaseMedicalAllowanceServiceImpl): 新增医疗津贴条 6 روز پیش
  turborao 92e37a94d3 Merge remote-tracking branch 'origin/master' 6 روز پیش
  turborao 52582e778a ``` 6 روز پیش
14فایلهای تغییر یافته به همراه789 افزوده شده و 53 حذف شده
  1. 10 1
      build.gradle
  2. 76 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/impt/ScoreInitialImportPlugin.java
  3. 8 8
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/BaseInitialOperationPlugIn.java
  4. 25 14
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/NewHireInitialOperationPlugIn.java
  5. 23 14
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/initial/ServingInitialOperationPlugIn.java
  6. 45 6
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/rptdata/DetailCompareReportDataPlugin.java
  7. 79 6
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/utils/ReportUtils.java
  8. 112 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/hcdm/formplugin/agencybill/AgencyBillEdit.java
  9. 21 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/hsbs/formplugin/web/basedata/salarygroup/PerSalaryGroupEdit.java
  10. 11 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/business/BaseMedicalAllowanceService.java
  11. 294 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/business/BaseMedicalAllowanceServiceImpl.java
  12. 48 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/plugin/operate/BaseMedicalAllowanceOpPlugin.java
  13. 34 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/plugin/other/BaseMedicalAllowanceTask.java
  14. 3 4
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/plugin/other/DelayedRetirementDateCalcTask.java

+ 10 - 1
build.gradle

@@ -171,12 +171,21 @@ subprojects {
   
     task rptzip(type: Zip) {
       group 'build'
-      description '生成swc zip包'
+      description '生成rpt zip包'
       from outputdir
       include 'nckd-jxccl-rpt*.jar'
       destinationDirectory = file(zip)
       archiveFileName = "nckd-rpt.zip"
     }
+
+	task wtczip(type: Zip) {
+		group 'build'
+		description '生成wtc zip包'
+		from outputdir
+		include 'nckd-jxccl-wtc*.jar'
+		destinationDirectory = file(zip)
+		archiveFileName = "nckd-wtc.zip"
+	}
 	 
 	test.ignoreFailures true
 	

+ 76 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/initial/impt/ScoreInitialImportPlugin.java

@@ -0,0 +1,76 @@
+package nckd.jxccl.hr.psms.plugin.form.initial.impt;
+
+import com.google.common.collect.Lists;
+import kd.bos.dataentity.OperateOption;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.hr.hbp.formplugin.web.HRDataBaseList;
+import kd.hr.impt.common.dto.ImportBillData;
+import kd.hr.impt.common.dto.ImptPluginContext;
+import kd.hr.impt.common.plugin.AfterLoadStartPageEventArgs;
+import kd.hr.impt.common.plugin.BeforeCallOperationEventArgs;
+import kd.hr.impt.common.plugin.BeforeShowTemplateSelectListEventArgs;
+import kd.hr.impt.common.plugin.HRImportPlugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.hr.psms.common.PositionStructureConstant;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+* 新入职人员初定/在职人员初定导入插件
+* 实体标识:gradedpersonquery
+* @author W.Y.C
+* @date 2025/10/31 14:04
+* @version 1.0
+*/
+public class ScoreInitialImportPlugin extends HRDataBaseList implements HRImportPlugin {
+
+    private static String SETTINGJOBGRADE_TPL = "settingjobgradetpl";
+    private static String SETTINGJOBGRADENEW_TPL = "settingjobgradenewtpl";
+    public ScoreInitialImportPlugin() {
+    }
+
+    //kd.hrmp.hbpm.formplugin.web.impt.PositionReviseHRImportPlugin,校验例子
+    //kd.hr.haos.formplugin.web.impo.OrgBatchHRImportPlugin,校验例子
+
+
+    @Override
+    public void afterLoadStartPage(AfterLoadStartPageEventArgs args) {
+        // 启用串行模式:先校验所有数据,再统一入库
+        // 开启之后如有校验失败,前端会提示:数据校验失败
+        args.setSerialModel(true);
+    }
+
+    @Override
+    public void beforeShowTemplateSelectList(BeforeShowTemplateSelectListEventArgs args) {
+        List<QFilter> fileter = args.getqFilterList();
+        if(fileter == null){
+            fileter = Lists.newArrayList();
+        }
+        //模板列表只显示:新入职人员初定/在职人员初定导入模板
+        fileter.add(new QFilter(FormConstant.NUMBER_KEY, QCP.in, new String[]{SETTINGJOBGRADE_TPL,SETTINGJOBGRADENEW_TPL}));
+        args.setqFilterList(fileter);
+    }
+
+    @Override
+    public void beforeCallOperation(BeforeCallOperationEventArgs args) {
+        String mainEntityId = ((ImportBillData)args.getImportBillDatas().get(0)).getMainEntityId();
+        OperateOption operateOption = (OperateOption)args.getOperateOptions().get(mainEntityId);
+        Map<String, String> submitOPs = args.getSubmitOPs();
+        String targetKey = PositionStructureConstant.NCKD_PERSONPOSFILE.toLowerCase();
+        //删除默认save方法
+        submitOPs.entrySet().removeIf(entry -> entry.getKey().toLowerCase().equals(targetKey));
+
+        ImptPluginContext context = args.getContext();
+        String tplNumber = context.getTplNumber();
+
+        if(tplNumber.equalsIgnoreCase(SETTINGJOBGRADE_TPL)){
+            //调用在职人员初定OP
+            submitOPs.put(PositionStructureConstant.NCKD_PERSONPOSFILE.toLowerCase(),"servinginitial");
+        }else if(tplNumber.equalsIgnoreCase(SETTINGJOBGRADENEW_TPL)){
+            //调用新入职人员初定OP
+            submitOPs.put(PositionStructureConstant.NCKD_PERSONPOSFILE.toLowerCase(),"newhireinitial");
+        }
+    }
+}

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

@@ -1,5 +1,6 @@
 package nckd.jxccl.hr.psms.plugin.operate.initial;
 
+import com.google.common.collect.Lists;
 import kd.bos.common.enums.EnableEnum;
 import kd.bos.context.RequestContext;
 import kd.bos.dataentity.entity.DynamicObject;
@@ -43,7 +44,7 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
     
     protected final static Log logger = LogFactory.getLog(BaseInitialOperationPlugIn.class);
 
-    public List<BaseInitialData> baseInitialData;
+    public List<BaseInitialData> baseInitialData = Lists.newArrayList();
 
     /**
      * 基本信息数据对象
@@ -71,6 +72,8 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         DynamicObject dep;
         /** 职位序列 */
         DynamicObject jobSeq;
+        /** 职位序列(转换后) */
+        DynamicObject convertJobSeq;
         /** 职位序列-编码 */
         String jobSeqNumber;
         /** 职位序列-名称 */
@@ -116,9 +119,6 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
      * @date: 2025/10/12 14:20
      */
     protected List<BaseInitialData> extractBasicInfo(DynamicObject initialData) {
-        if(baseInitialData != null){
-            return baseInitialData;
-        }
         List<BaseInitialData> dataList = new ArrayList<>();
         if(initialData.containsProperty(FormConstant.NCKD_ENTRYENTITY)){
             DynamicObjectCollection dynamicObjectCollection = initialData.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
@@ -126,14 +126,14 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
                 //批量初定
                 BaseInitialData data = getBaseInitialData(dynamicObject);
                 dataList.add(data);
+                baseInitialData.add(data);
             }
         }else{
             BaseInitialData data = getBaseInitialData(initialData);
             dataList.add(data);
+            baseInitialData.add(data);
         }
-
-        baseInitialData = dataList;
-        return baseInitialData;
+        return dataList;
     }
 
     @NotNull
@@ -366,7 +366,7 @@ public abstract class BaseInitialOperationPlugIn extends AbstractOperationServic
         personPosFile.set(PositionStructureConstant.NCKD_FIRSTRANK, EnableEnum.YES.getCode());
         personPosFile.set(PositionStructureConstant.NCKD_BEGINDATE, data.beginDate);
         personPosFile.set(PositionStructureConstant.NCKD_APPRAISALRESULT, data.lastYearAppraisalResult);
-        personPosFile.set(PositionStructureConstant.NCKD_JOBSEQHR, data.jobSeq);
+        personPosFile.set(PositionStructureConstant.NCKD_JOBSEQHR, data.convertJobSeq);
         personPosFile.set(PositionStructureConstant.NCKD_POSITIONHR, data.positionHr);
         /*personPosFile.set(PositionStructureConstant.USEORG_KEY, data.company);
         personPosFile.set(PositionStructureConstant.CREATEORG_KEY, data.dep);

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

@@ -8,6 +8,7 @@ import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
 import kd.bos.entity.plugin.args.RollbackOperationArgs;
 import kd.bos.entity.validate.AbstractValidator;
 import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.exception.ValidationException;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.hr.psms.business.JobLevelCalculatorService;
@@ -15,9 +16,12 @@ import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 
 import java.math.BigDecimal;
 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;
 
 /**
  * 新入职人员初定-确认定级操作OP
@@ -38,26 +42,35 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
                     return;
                 }
                 Date currentDate = new Date();
+                Set<Long> personIds = new HashSet<>();
+                Map<Long,Integer> personDataEntityMap = new HashMap<>();
                 for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
                     DynamicObject data = rowDataEntity.getDataEntity();
                     //提取信息
                     List<BaseInitialData> newHireInitialDataList =  extractBasicInfo(data);
 
+                    int dataEntityIndex = rowDataEntity.getDataEntityIndex();
                     // 检查人员ID重复
-                    Set<Long> personIds = new HashSet<>();
                     for (BaseInitialData newHireInitialData : newHireInitialDataList) {
                         if (newHireInitialData.person != null) {
                             Long personId = newHireInitialData.person.getLong(FormConstant.ID_KEY);
                             if (!personIds.add(personId)) {
+                                Integer i = personDataEntityMap.get(personId);
+                                if(i != null){
+                                    //将上一个重复人员也标记为错误
+                                    addFatalErrorMessage(getDataEntities()[i],
+                                            StrFormatter.format("人员【{}】在列表中重复,请保留一条信息",
+                                                    newHireInitialData.person.getString(FormConstant.NAME_KEY)));
+                                }
                                 addFatalErrorMessage(rowDataEntity,
                                         StrFormatter.format("人员【{}】在列表中重复,请保留一条信息",
                                                 newHireInitialData.person.getString(FormConstant.NAME_KEY)));
                             }
+                            personDataEntityMap.put(personId,dataEntityIndex);
                         }
                     }
-                    if(!this.getValidateResult().isSuccess()){
-                        return;
-                    }
+
+
 
                     for (BaseInitialData newHireInitialData : newHireInitialDataList) {
                         Date beginDate = newHireInitialData.beginDate;
@@ -106,9 +119,7 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
         if(this.getOperationResult().isSuccess()) {
             //对应SHR:com.kingdee.shr.customer.web.handler.ContributeScore.PersonpositionfileListHandler#addNewPersonpositionfileInfo
             logger.info("【职位体系】-新入职人员初定-开始");
-            for (DynamicObject servingInitial : e.getDataEntities()) {
-                processNewHireInitialData(servingInitial);
-            }
+            processNewHireInitialData();
         }
     }
 
@@ -124,13 +135,10 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
 
     /**
      * 处理单个在职人员初定
-     * @param newHireInitial 新入职人员初定数据对象
      */
-    private void processNewHireInitialData(DynamicObject newHireInitial) {
+    private void processNewHireInitialData() {
 
-        //提取信息
-        List<BaseInitialData> dataList =  extractBasicInfo(newHireInitial);
-        for (BaseInitialData data : dataList) {
+        for (BaseInitialData data : baseInitialData) {
 
             String logPrefix = StrFormatter.format("【职位体系】-新入职人员初定-人员【{}({})】",
                     data.person.getString(FormConstant.NAME_KEY),
@@ -159,13 +167,16 @@ public class NewHireInitialOperationPlugIn extends BaseInitialOperationPlugIn {
             // 计算职级
             //当考核结果为无时,职级定为最低级
             boolean useMinLevel = data.lastYearAppraisalResultEnum == nckd.jxccl.base.common.enums.AppraisalResultEnum.NONE;
+            // 如果是管理序列,则按职能序列进行初定
+            data.convertJobSeq = JobLevelCalculatorService.handleJobSeq(data.jobSeq);
             //【三期需求】-不满足三要素(聘任职称/技能、考核结果、积分)按"无职级"初定
             String perProTitleNumber = scoreData.dbProTitleLevel != null ? scoreData.dbProTitleLevel.getString(FormConstant.NUMBER_KEY) : null;
             String quaLevelNumber = scoreData.dbOcpQualLevel != null ? scoreData.dbOcpQualLevel.getString(FormConstant.NUMBER_KEY) : null;
-            boolean threeElementMeet = JobLevelCalculatorService.checkThreeElementsRequirement(data.jobSeq, allSumScore, scoreData.dbProTitleLevel,
+            boolean threeElementMeet = JobLevelCalculatorService.checkThreeElementsRequirement(data.convertJobSeq, allSumScore, scoreData.dbProTitleLevel,
                     scoreData.dbOcpQualLevel, data.lastYearAppraisalResultEnum);
+
             DynamicObject jobLeve = JobLevelCalculatorService.getJobLevel(
-                    data.jobSeq, allSumScore, perProTitleNumber,
+                    data.convertJobSeq, allSumScore, perProTitleNumber,
                     quaLevelNumber,data.downgradeNum,useMinLevel,!threeElementMeet);
             if(jobLeve != null) {
                 // 构建职位档案并存入数据库

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

@@ -18,8 +18,10 @@ import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -40,26 +42,33 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
                     return;
                 }
                 Date currentDate = new Date();
+
+                Set<Long> personIds = new HashSet<>();
+                Map<Long,Integer> personDataEntityMap = new HashMap<>();
                 for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
                     DynamicObject data = rowDataEntity.getDataEntity();
                     //提取信息
                     List<BaseInitialData> servingInitialDataList = extractBasicInfo(data);
-
+                    int dataEntityIndex = rowDataEntity.getDataEntityIndex();
                     // 检查人员ID重复
-                    Set<Long> personIds = new HashSet<>();
                     for (BaseInitialData servingInitialData : servingInitialDataList) {
                         if (servingInitialData.person != null) {
                             Long personId = servingInitialData.person.getLong(FormConstant.ID_KEY);
                             if (!personIds.add(personId)) {
+                                Integer i = personDataEntityMap.get(personId);
+                                if(i != null){
+                                    //将上一个重复人员也标记为错误
+                                    addFatalErrorMessage(getDataEntities()[i],
+                                            StrFormatter.format("人员【{}】在列表中重复,请保留一条信息",
+                                                    servingInitialData.person.getString(FormConstant.NAME_KEY)));
+                                }
                                 addFatalErrorMessage(rowDataEntity,
                                         StrFormatter.format("人员【{}】在列表中重复,请保留一条信息",
                                                 servingInitialData.person.getString(FormConstant.NAME_KEY)));
-                                return;
                             }
+                            personDataEntityMap.put(personId,dataEntityIndex);
                         }
-                    }
-                    if(!this.getValidateResult().isSuccess()){
-                        return;
+
                     }
 
                     for (BaseInitialData servingInitialData : servingInitialDataList) {
@@ -117,9 +126,8 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
         if(this.getOperationResult().isSuccess()) {
             //对应SHR:com.kingdee.shr.customer.web.handler.ContributeScore.PersonpositionfileListHandler#addNewPersonpositionfileInfo_older
             logger.info("【职位体系】-在职人员初定-开始");
-            for (DynamicObject servingInitial : e.getDataEntities()) {
-                processServingInitial(servingInitial);
-            }
+            processServingInitial();
+
         }
     }
 
@@ -135,12 +143,10 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
 
     /**
      * 处理单个在职人员初定
-     * @param servingInitial 在职人员初定数据对象
      */
-    private void processServingInitial(DynamicObject servingInitial) {
+    private void processServingInitial() {
         // 提取基本信息
-        List<BaseInitialData> dataList = extractBasicInfo(servingInitial);
-        for (BaseInitialData data : dataList) {
+        for (BaseInitialData data : baseInitialData) {
             String logPrefix = StrFormatter.format("【职位体系】-在职人员初定-人员【{}({})】",
                     data.person.getString(FormConstant.NAME_KEY),
                     data.person.getString(FormConstant.EMP_NUMBER_KEY));
@@ -160,13 +166,16 @@ public class ServingInitialOperationPlugIn extends BaseInitialOperationPlugIn {
             // 计算累计积分池(生涯积分)
             BigDecimal sumScore = calculateSumScore(data.allSumScore, scoreData, logPrefix);
 
+            // 如果是管理序列,则按职能序列进行初定
+            data.convertJobSeq = JobLevelCalculatorService.handleJobSeq(data.jobSeq);
+
             // 计算职级
             //当考核结果为无时,职级定为最低级
             boolean useMinLevel = data.lastYearAppraisalResultEnum == nckd.jxccl.base.common.enums.AppraisalResultEnum.NONE;
             String perProTitleNumber = scoreData.dbProTitleLevel != null ? scoreData.dbProTitleLevel.getString(FormConstant.NUMBER_KEY) : null;
             String quaLevelNumber = scoreData.dbOcpQualLevel != null ? scoreData.dbOcpQualLevel.getString(FormConstant.NUMBER_KEY) : null;
             DynamicObject jobLeve = JobLevelCalculatorService.getJobLevel(
-                    data.jobSeq, data.allSumScore, perProTitleNumber,
+                    data.convertJobSeq, data.allSumScore, perProTitleNumber,
                     quaLevelNumber,  data.downgradeNum,useMinLevel,Boolean.FALSE);
 
             if(jobLeve != null) {

+ 45 - 6
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/sit/hcsi/rptdata/DetailCompareReportDataPlugin.java

@@ -1,6 +1,8 @@
 package nckd.jxccl.sit.hcsi.rptdata;
 
 import kd.bos.algo.DataSet;
+import kd.bos.algo.GroupbyDataSet;
+import kd.bos.algo.JoinDataSet;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.entity.report.AbstractReportListDataPlugin;
@@ -51,14 +53,25 @@ public class DetailCompareReportDataPlugin extends AbstractReportListDataPlugin
         List<Long> taskIds = taskCols.stream().map(obj -> obj.getLong("id")).collect(Collectors.toList());
         // 根据计算任务Id+险种获取到计算结果明细数据
         DataSet calPersonDataSet = queryCalPersonDetail(reportQueryParam, taskIds);
-        // 按照个人和单位分组汇总 type = 1为个人,type = 2为单位
+        // 按照个人和单位分组汇总 type = 1为个人,type = 2为单位,这里仅为系统内数据
+        DataSet groupDataSet = groupCalPersonDetail(calPersonDataSet);
+        // 再关联外部数据导入
+        DataSet outsidePersonDetail = ReportUtils.queryOutsidePersonDetail(reportQueryParam);
+        // 按照个人和单位分组汇总 type = 1为个人,type = 2为单位,这里仅为系统内数据
+        DataSet groupDataSetOut = groupCalPersonDetailOut(outsidePersonDetail);
 
-        return null;
+        // 再join
+        String[] leftFields = new String[]{"welfarepayer", "welfaretypeid", "empnumber", "empname", "empidcard", "type", "personSysValue", "companySysValue"};
+        String[] rightFields =  new String[]{"personOutValue", "companyOutValue"};
+        DataSet finalDataSet = groupDataSet.join(groupDataSetOut).on("welfarepayer", "welfarepayer").on("welfaretypeid", "welfaretypeid").
+                on("empnumber", "empnumber").on("empname", "empname").
+                on("empidcard", "empidcard").select(leftFields, rightFields).finish();
+        return finalDataSet;
     }
 
     public DataSet queryDataSet(ReportQueryParam reportQueryParam, QFilter filter, String entityName, String selectFields) {
         HRBaseServiceHelper helper = new HRBaseServiceHelper(entityName);
-        DataSet dataSet = helper.queryDataSet("AttendanceRateReportQuery-Sbsent", selectFields, new QFilter[]{filter});
+        DataSet dataSet = helper.queryDataSet("AttendanceRateReportQuery-Absent", selectFields, new QFilter[]{filter});
         return dataSet;
     }
 
@@ -83,13 +96,39 @@ public class DetailCompareReportDataPlugin extends AbstractReportListDataPlugin
 
     /**
      * 分组汇总人员明细
-     *
      * @param calPersonDataSet
      * @return
      */
     public DataSet groupCalPersonDetail (DataSet calPersonDataSet) {
-        //calPersonDataSet.groupBy(new String[]{"welfarepayer","welfaretypeid","empnumber","empname","empidcard","type"}).sum
-        return calPersonDataSet;
+        calPersonDataSet.groupBy(new String[]{"welfarepayer","welfaretypeid","empnumber","empname","empidcard","type"}).sum("value");
+        DataSet dataSet1 = calPersonDataSet.copy();
+        DataSet dataSet2 = calPersonDataSet.copy();
+
+        // 按照类型分组汇总
+        DataSet sumSet1 = dataSet1.filter("type = '1'").groupBy(new String[]{"welfarepayer", "welfaretypeid", "empnumber", "empname", "empidcard", "type"}).sum("value").finish();
+        DataSet sumSet2 = dataSet2.filter("type = '2'").groupBy(new String[]{"welfarepayer","welfaretypeid","empnumber","empname","empidcard","type"}).sum("value").finish();
+
+        // join
+        JoinDataSet joinDataSet = sumSet1.join(sumSet2).on("welfarepayer", "welfarepayer").on("welfaretypeid", "welfaretypeid").on("empnumber", "empnumber").on("empname", "empname").on("empidcard", "empidcard");
+        DataSet dataSet = joinDataSet.select(new String[]{"welfarepayer", "welfaretypeid", "empnumber", "empname", "empidcard", "type", "value as personSysValue"}, new String[]{"value as companySysValue"}).finish();
+
+        return dataSet;
+    }
+
+    public DataSet groupCalPersonDetailOut (DataSet calPersonDataSet) {
+        calPersonDataSet.groupBy(new String[]{"welfarepayer","welfaretypeid","empnumber","empname","empidcard","type"}).sum("value");
+        DataSet dataSet1 = calPersonDataSet.copy();
+        DataSet dataSet2 = calPersonDataSet.copy();
+
+        // 按照类型分组汇总
+        DataSet sumSet1 = dataSet1.filter("type = '1'").groupBy(new String[]{"welfarepayer", "welfaretypeid", "empnumber", "empname", "empidcard", "type"}).sum("value").finish();
+        DataSet sumSet2 = dataSet2.filter("type = '2'").groupBy(new String[]{"welfarepayer","welfaretypeid","empnumber","empname","empidcard","type"}).sum("value").finish();
+
+        // join
+        JoinDataSet joinDataSet = sumSet1.join(sumSet2).on("welfarepayer", "welfarepayer").on("welfaretypeid", "welfaretypeid").on("empnumber", "empnumber").on("empname", "empname").on("empidcard", "empidcard");
+        DataSet dataSet = joinDataSet.select(new String[]{"welfarepayer", "welfaretypeid", "empnumber", "empname", "empidcard", "type", "value as personOutValue"}, new String[]{"value as companyOutValue"}).finish();
+
+        return dataSet;
     }
 
     /**

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

@@ -1,7 +1,10 @@
 package nckd.jxccl.sit.hcsi.utils;
 
 import kd.bos.algo.DataSet;
+import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.report.FilterInfo;
+import kd.bos.entity.report.ReportQueryParam;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
@@ -13,9 +16,14 @@ public class ReportUtils {
 
     private static final String CALPERSON_ENTITY = "hcsi_calperson";
     private static final String INSURANCEITEM_ENTITY = "sitbs_insuranceitem";
+    private static final String TEMPDATA_ENTITY = "nckd_sinsurtempdata";
+    private static final String TEMPDATA_FIELDS = "nckd_importtask.nckd_welfarepayer.id as welfarepayer,"
+            +"nckd_empnumber as empnumber,nckd_empname as empname, nckd_idcard as empidcard, entryentity.nckd_itemid as itemid,"
+            +"entryentity.nckd_itemvalue as value";
+
     //参保单位,险种,工号,姓名,证件号,单位缴费金额 = 单位固定+单位缴费+单位补缴,个人缴费金额=个人固定+个人缴费+个人补缴
     private static String CALPERSON_FIELDS = "welfarepayer.id as welfarepayer,entryentity.insuranceitem.group.id as welfaretypeid,"
-            +"empnumberdb as empnumber,namedb as empname,percre.number as empidcard,entryentity.famountvalue as value,"
+            +"empnumberdb as empnumber,namedb as empname,percre.number as empidcard,entryentity.amountvalue as value,"
             +"case when entryentity.insuranceitem.insurancetypeattr.number in ('1005_S','1009_S','1011_S') then '1'"
             +"     when entryentity.insuranceitem.insurancetypeattr.number in ('1006_S','1010_S','1012_S') then '2' end as type";
     private static final String[] INSURANCEPROP = new String[]{"1005_S","1006_S","1009_S","1010_S","1011_S","1012_S"};
@@ -25,7 +33,7 @@ public class ReportUtils {
 
     }
     /**
-     * 获取人员计算详情数据
+     * 获取人员计算详情数据-系统内数据
      * @param welfareTypeIds
      * @param taskIds
      */
@@ -34,13 +42,56 @@ public class ReportUtils {
         QFilter filter = new QFilter("sinsurtask.id", QCP.in, taskIds);
         filter.and("entryentity.insuranceitem.id", QCP.in, itemIds);
         HRBaseServiceHelper helper = new HRBaseServiceHelper(CALPERSON_ENTITY);
-        CALPERSON_FIELDS = "welfarepayer.id as welfarepayer,entryentity.insuranceitem.group.id as welfaretypeid,"
-                +"empnumberdb as empnumber,namedb as empname,percre.number as empidcard,entryentity.amountvalue as value,"
-                +"case when entryentity.insuranceitem.insurancetypeattr.number in ('1005_S','1009_S','1011_S') then '1'"
-                +"     when entryentity.insuranceitem.insurancetypeattr.number in ('1006_S','1010_S','1012_S') then '2' end as type";
         return helper.queryDataSet("DetailComReport", CALPERSON_FIELDS, new QFilter[]{filter});
     }
 
+    /**
+     * 获取人员计算详情数据-系统外数据
+     * 先根据参保单位和期间获取外部系统导入任务
+     * @return
+     */
+    public static DataSet queryOutsidePersonDetail(ReportQueryParam reportQueryParam) {
+        FilterInfo filterInfo = reportQueryParam.getFilter();
+        DynamicObject period = (DynamicObject) filterInfo.getFilterItem("nckd_period").getValue();
+        DynamicObject walfarepayer = (DynamicObject) filterInfo.getFilterItem("nckd_welfarepayer").getValue();
+        // 险种
+        DynamicObjectCollection welfareTypeCols = (DynamicObjectCollection)filterInfo.getFilterItem("nckd_welfaretype").getValue();
+        List<Long> welfareTypeIds = welfareTypeCols.stream().map(obj -> obj.getLong("id")).collect(Collectors.toList());
+        List<Long> itemIds = queryInsuranceItem(welfareTypeIds);
+
+        QFilter filter = buildOutsideFilter(period, walfarepayer, itemIds);
+        HRBaseServiceHelper helper = new HRBaseServiceHelper(TEMPDATA_ENTITY);
+        // 查询出外部系统数据
+        DataSet outsideDataSet = helper.queryDataSet("DetailComReport_TEMPDATA", TEMPDATA_FIELDS, new QFilter[]{filter});
+        // 中间表中没直接存险种项目的基础资料只存了ID,这里再关联一下,需要获取到险种属性
+        DataSet insuranceItemDataSet = queryInsuranceItemDataSet(itemIds);
+        DataSet dataSet = outsideDataSet.join(insuranceItemDataSet).on("itemid","id").select(
+                new String[]{"welfarepayer","empnumber","empname","empidcard","cast(value as Decimal(10,2)) as value"},
+                new String[]{"welfaretypeid", "case when attrnumber in ('1005_S','1009_S','1011_S') then '1' when attrnumber in ('1006_S','1010_S','1012_S') then '2' end as type"}).finish();
+        return dataSet;
+    }
+
+    /**
+     * 获取人员计算详情数据-系统外数据
+     * 先根据参保单位和期间获取外部系统导入任务
+     * @return
+     */
+    public static DataSet queryOutsidePersonDetail(DynamicObject period, DynamicObject walfarepayer, DynamicObjectCollection welfareTypeCols) {
+        List<Long> welfareTypeIds = welfareTypeCols.stream().map(obj -> obj.getLong("id")).collect(Collectors.toList());
+        List<Long> itemIds = queryInsuranceItem(welfareTypeIds);
+
+        QFilter filter = buildOutsideFilter(period, walfarepayer, itemIds);
+        HRBaseServiceHelper helper = new HRBaseServiceHelper(TEMPDATA_ENTITY);
+        // 查询出外部系统数据
+        DataSet outsideDataSet = helper.queryDataSet("DetailComReport_TEMPDATA", TEMPDATA_FIELDS, new QFilter[]{filter});
+        // 中间表中没直接存险种项目的基础资料只存了ID,这里再关联一下,需要获取到险种属性
+        DataSet insuranceItemDataSet = queryInsuranceItemDataSet(itemIds);
+        DataSet dataSet = outsideDataSet.join(insuranceItemDataSet).on("itemid","id").select(
+                new String[]{"welfarepayer","empnumber","empname","empidcard","cast(value as Decimal(10,2)) as value"},
+                new String[]{"welfaretypeid", "case when attrnumber in ('1005_S','1009_S','1011_S') then '1' when attrnumber in ('1006_S','1010_S','1012_S') then '2' end as type"}).finish();
+        return dataSet;
+    }
+
     /**
      * 根据险种ID获取险种项目
      * @param welfareTypeIds
@@ -55,4 +106,26 @@ public class ReportUtils {
         return itemIds;
     }
 
+    public static DataSet queryInsuranceItemDataSet(List<Long> itemIds) {
+        HRBaseServiceHelper helper = new HRBaseServiceHelper(INSURANCEITEM_ENTITY);
+        QFilter filter = new QFilter("id", QCP.in, itemIds);
+        filter.and("insurancetypeattr.number", QCP.in, INSURANCEPROP);
+        return helper.queryDataSet("DetailComReport_INSURANCEITEM", "id, insurancetypeattr.number as attrnumber, group.id as welfaretypeid", new QFilter[]{filter});
+    }
+
+    /**
+     * 构建查询外部数据的Filter
+     *
+     * @param period
+     * @param walfarepayer
+     * @param itemIds
+     * @return
+     */
+    public static QFilter buildOutsideFilter(DynamicObject period, DynamicObject walfarepayer, List<Long> itemIds) {
+        QFilter filter = new QFilter("nckd_importtask.nckd_period.id", QCP.equals, period.getPkValue());
+        filter.and("nckd_importtask.nckd_welfarepayer.id", QCP.equals, walfarepayer.getPkValue());
+        filter.and("entryentity.nckd_itemid", QCP.in, itemIds);
+        return filter;
+    }
+
 }

+ 112 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/hcdm/formplugin/agencybill/AgencyBillEdit.java

@@ -0,0 +1,112 @@
+package nckd.jxccl.swc.hcdm.formplugin.agencybill;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.metadata.IMetadata;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.datamodel.IDataModel;
+import kd.bos.entity.datamodel.ListSelectedRowCollection;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.ShowFormHelper;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.list.ListFilterParameter;
+import kd.bos.list.ListShowParameter;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.orm.util.CollectionUtils;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.sdk.plugin.Plugin;
+import kd.swc.hcdm.business.domain.applybill.helper.ApplyBillPermCommonHelper;
+import kd.swc.hsbp.common.util.SWCDateTimeUtils;
+import kd.swc.hsbp.formplugin.web.SWCBaseFormPlugin;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Tyx 2025-10-29
+ * 单位代发单表单插件
+ */
+public class AgencyBillEdit extends SWCBaseFormPlugin implements Plugin {
+
+    private static final String CALLBACK_CLOSE_ADD_ADJFILE = "CALLBACK_CLOSE_ADD_ADJFILE";
+    private static final HRBaseServiceHelper SALARYFILE_HELPER = new HRBaseServiceHelper("hsas_salaryfile");
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+        this.addItemClickListeners("nckd_advcontoolbarap");
+    }
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs afterDoOperationEventArgs) {
+        super.afterDoOperation(afterDoOperationEventArgs);
+        FormOperate source = (FormOperate)afterDoOperationEventArgs.getSource();
+        switch (source.getOperateKey()) {
+            case "add_adjfile":
+                this.showAdjFileF7(afterDoOperationEventArgs);
+        }
+    }
+
+    private void showAdjFileF7(AfterDoOperationEventArgs args) {
+        ListShowParameter formShowParameter = ShowFormHelper.createShowListForm("hsas_salaryfilef7", true);
+        ListFilterParameter listFilterParameter = formShowParameter.getListFilterParameter();
+        formShowParameter.setMultiSelect(true);
+        List<QFilter> qFilters = listFilterParameter.getQFilters();
+        qFilters.add(new QFilter("iscurrentversion", QCP.equals, "1"));
+        List<QFilter> adjFileInfoPerm = ApplyBillPermCommonHelper.getAdjFileInfoPerm(this.getCheckRightAppId("0VO5EV13=I9W"));
+        if (!CollectionUtils.isEmpty(adjFileInfoPerm)) {
+            qFilters.addAll(adjFileInfoPerm);
+        }
+
+        Date effectiveDate = new Date();
+        long orgId = this.getModel().getDataEntity().getLong("org.id");
+        qFilters.add(new QFilter("org.id", QCP.equals, orgId));
+        if (effectiveDate != null) {
+            formShowParameter.setCustomParam("effectiveDate", SWCDateTimeUtils.format(effectiveDate, "yyyy-MM-dd"));
+        }
+
+        formShowParameter.setListFilterParameter(listFilterParameter);
+        formShowParameter.setCloseCallBack(new CloseCallBack(this, "CALLBACK_CLOSE_ADD_ADJFILE"));
+        formShowParameter.setCaption(ResManager.loadKDString("请添加代发人员", "ApplyBillEdit_1", "swc-hcdm-formplugin", new Object[0]));
+//        Long billId = (Long)this.getModel().getDataEntity().getPkValue();
+//        formShowParameter.setCustomParam("billid", String.valueOf(billId));
+//        formShowParameter.setCustomParam("addPersonFlag", Boolean.TRUE.toString());
+//        formShowParameter.setCustomParam("isHistoryPage", Boolean.TRUE.toString());
+//        formShowParameter.setCustomParam("hisPage", "versionListPage");
+//        formShowParameter.setCustomParam("option", "hisversioninfo");
+        this.getView().showForm(formShowParameter);
+    }
+
+    @Override
+    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
+        super.closedCallBack(closedCallBackEvent);
+        String actionId = closedCallBackEvent.getActionId();
+        Object returnData = closedCallBackEvent.getReturnData();
+        if (CALLBACK_CLOSE_ADD_ADJFILE.equals(actionId) && returnData != null) {
+            this.onCloseCallbackAddAdjFile(closedCallBackEvent);
+        }
+    }
+
+    private void onCloseCallbackAddAdjFile(ClosedCallBackEvent args) {
+        IDataModel model = this.getModel();
+        ListSelectedRowCollection selectedRows = (ListSelectedRowCollection) args.getReturnData();
+        Object[] primaryKeyObjs = selectedRows.getPrimaryKeyValues();
+        List<Long> ids = Arrays.stream(primaryKeyObjs).map(obj -> (Long)obj).collect(Collectors.toList());
+        QFilter filter = new QFilter("id", QCP.in, ids);
+        String selectFields = "employee.id, employee.name, employee.empnumber, empposorgrel.adminorg.id";
+        DynamicObject[] adjFiles = SALARYFILE_HELPER.load(selectFields, new QFilter[]{filter});
+        DynamicObjectCollection entryCols = model.getDataEntity(true).getDynamicObjectCollection("nckd_entryentity");
+        model.beginInit();
+        for (DynamicObject adjFile : adjFiles) {
+            DynamicObject entry = entryCols.addNew();
+            entry.set("nckd_employee", adjFile.getDynamicObject("employee"));
+            entry.set("nckd_adminorg", adjFile.getDynamicObject("empposorgrel.adminorg"));
+        }
+        model.endInit();
+        this.getView().updateView("nckd_entryentity");
+    }
+}

+ 21 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/hsbs/formplugin/web/basedata/salarygroup/PerSalaryGroupEdit.java

@@ -0,0 +1,21 @@
+package nckd.jxccl.swc.hsbs.formplugin.web.basedata.salarygroup;
+
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.sdk.plugin.Plugin;
+
+import java.util.EventObject;
+
+/**
+ * Tyx 2025-10-30
+ * 人员薪酬分类表单插件 【nckd_persalarygroup】
+ */
+public class PerSalaryGroupEdit extends AbstractFormPlugin implements Plugin {
+
+    @Override
+    public void afterCreateNewData(EventObject e) {
+        Object employeeIdObj = this.getView().getParentView().getFormShowParameter().getCustomParam("employeeId");
+        if (null != employeeIdObj) {
+            this.getView().getModel().setValue("nckd_employee", Long.parseLong(String.valueOf(employeeIdObj)));
+        }
+    }
+}

+ 11 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/business/BaseMedicalAllowanceService.java

@@ -0,0 +1,11 @@
+package nckd.jxccl.swc.init.business;
+
+import java.util.List;
+import java.util.Map;
+
+public interface BaseMedicalAllowanceService {
+
+    public abstract Map<String, String> calcBaseMedicalAllowanceForPersons(List<Long> personIds);
+
+    public abstract Map<String, String> calcBaseMedicalAllowanceForAll();
+}

+ 294 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/business/BaseMedicalAllowanceServiceImpl.java

@@ -0,0 +1,294 @@
+package nckd.jxccl.swc.init.business;
+
+import kd.bos.algo.DataSet;
+import kd.bos.algo.Row;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.db.DB;
+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 java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * 员工信息维护(社保专用)列表界面提供一个功能按钮,可以进行即时计算,
+ * 后台提供定时任务(每年12月31日24点执行一次),当年度待遇根据上年度12月31日的人员状态和记录计算补助待遇,
+ * 按照年度生成多行记录,记录历史。当专员手动执行前端更新按钮时(需选中人员),
+ * 系统需根据手动的当前时间获取人员状态和记录计算补助待遇,包括对当前记录进行更新,
+ * 新增人员待遇记录生成。(离职人员不做处理)
+ * 金额调整
+ * 2400--->4800
+ * 1800--->3600
+ * 1200--->2400
+ * 840--->1800
+ * author: turborao
+ * date: 2025/10/27 13:05
+ */
+public class BaseMedicalAllowanceServiceImpl implements BaseMedicalAllowanceService{
+
+    private static final Log logger = LogFactory.getLog(BaseMedicalAllowanceServiceImpl.class);
+    public Map<String, String> calcBaseMedicalAllowanceForAll() {
+
+        //取员工档案
+        String billKey = "hcsi_sinsurfile";
+        QFilter filter1 = new QFilter("iscurrentversion", QCP.equals, true); // 启用
+        QFilter filter2 = new QFilter("datastatus", QCP.equals, "1"); // 启用
+
+        String selectFields="id,employee.id,employee.number,nckd_benefitentry.nckd_effeyear,nckd_benefitentry.nckd_suppbenefit";
+        DynamicObject[] datas = BusinessDataServiceHelper.load(billKey, selectFields, new QFilter[]{filter1.and(filter2)});
+
+        Map<String, String> result = calcBaseMedicalAllowance(datas, true);
+
+        return result;
+    }
+
+    public Map<String, String> calcBaseMedicalAllowanceForPersons(List<Long> billIds) {
+
+        //取员工档案
+        String billKey = "hcsi_sinsurfile";
+        QFilter filter1 = new QFilter("iscurrentversion", QCP.equals, true); // 启用
+        QFilter filter2 = new QFilter("datastatus", QCP.equals, "1"); // 启用
+        QFilter filter3 = new QFilter("id", QCP.in, billIds); // 启用
+
+        String selectFields="id,employee.id,employee.number,nckd_benefitentry.nckd_effeyear,nckd_benefitentry.nckd_suppbenefit";
+        DynamicObject[] datas = BusinessDataServiceHelper.load(billKey, selectFields, new QFilter[]{filter1.and(filter2).and(filter3)});
+
+        Map<String, String> result = calcBaseMedicalAllowance(datas,false);
+
+        return result;
+
+    }
+
+
+    public Map<String, String> calcBaseMedicalAllowance(DynamicObject[] datas, boolean isAll) {
+
+        // 获取当前日期
+        LocalDate currentDate = LocalDate.now();
+
+        // 获取上一年的年份
+        //int previousYear = currentDate.minusYears(1).getYear();
+        int previousYear = currentDate.getYear();
+
+        Map<Long, DynamicObject> employeeFileMaps = Arrays.stream(datas).collect(
+                Collectors.toMap(
+                        obj -> obj.getLong("employee.id"),
+                        obj -> obj,
+                        (k1, k2) -> k1
+                )
+        );
+        //将Map转换为List
+        List<Long> employeeIDs = employeeFileMaps.keySet().stream().collect(Collectors.toList());
+        ArrayList<DynamicObject> dynList = new ArrayList<>();
+        /***
+         * 获取员工基本信息
+         */
+        QFilter qFilter1 = new QFilter("id",QCP.in, employeeIDs);
+        QFilter qFilter11 = new QFilter("iscurrentversion", QCP.equals, true); // 启用
+        QFilter qFilter12 = new QFilter("datastatus", QCP.equals, "1"); // 启用
+        DataSet employeeDS = QueryServiceHelper.queryDataSet(this.getClass().getName(),"hrpi_employee", "id,number,name", new QFilter[]{qFilter1,qFilter11,qFilter12},null);
+        employeeDS.print(true);
+        /***
+         * 获取员工档案 任职经历  岗位
+         */
+        QFilter qFilter2 = new QFilter("employee.id",QCP.in, employeeIDs);
+        QFilter qFilter21 = new QFilter("iscurrentdata", QCP.equals, true); // 启用
+        QFilter qFilter22 = new QFilter("isprimary", QCP.equals, "1");  //主任职
+        QFilter qFilter23 = new QFilter("postype.id", QCP.equals, 1010L); //主任职
+        DataSet empOrgRelDS = QueryServiceHelper.queryDataSet(this.getClass().getName(),"hrpi_empposorgrel", "id,employee.id,company.id,company.name,position.id,position.number,position.name,adminorg.number", new QFilter[]{qFilter2,qFilter21,qFilter22,qFilter23},null);
+        empOrgRelDS.print(true);
+        /***
+         * 获取员工档案 雇佣信息  用工关系状态
+         */
+        QFilter qFilter3 = new QFilter("employee.id",QCP.in, employeeIDs);
+        QFilter qFilter31 = new QFilter("iscurrentdata", QCP.equals, true); // 启用
+        QFilter qFilter32 = new QFilter("ishired", QCP.equals, "1"); // 是否在职
+        DataSet empentrelDS = QueryServiceHelper.queryDataSet(this.getClass().getName(),"hrpi_empentrel", "id,employee.id,laborrelstatus.number", new QFilter[]{qFilter3,qFilter31,qFilter32},null);
+
+        /***
+         * 获取员工档案 党政职务  职务级别
+         */
+        QFilter qFilter4 = new QFilter("employee.id",QCP.in, employeeIDs);
+        QFilter qFilter41 = new QFilter("iscurrentdata", QCP.equals, true); // 启用
+        DataSet posgradeDS = QueryServiceHelper.queryDataSet(this.getClass().getName(),"nckd_hrpi_partyposh", "id,employee.id,nckd_posgrade.number", new QFilter[]{qFilter4,qFilter41},null);
+
+        /***
+         * 获取员工档案 职称信息 职称级别  hrpi_perprotitle
+         */
+        QFilter qFilter5 = new QFilter("employee.id",QCP.in, employeeIDs);
+        QFilter qFilter51 = new QFilter("ishigh", QCP.equals, "1"); // 启用
+        DataSet perprotitleDS = QueryServiceHelper.queryDataSet(this.getClass().getName(),"hrpi_perprotitle", "id,employee.id,prolevel.number", new QFilter[]{qFilter5,qFilter51},null);
+
+        /***
+         * 获取员工档案 职业资格 职业资格等级  hrpi_perocpqual
+         */
+        QFilter qFilter6 = new QFilter("employee.id",QCP.in, employeeIDs);
+        QFilter qFilter61 = new QFilter("ismajor", QCP.equals, "1"); // 启用
+        DataSet perocpqualeDS = QueryServiceHelper.queryDataSet(this.getClass().getName(),"hrpi_perocpqual", "id,employee.id,qualevel.number", new QFilter[]{qFilter6,qFilter61},null);
+
+
+        DataSet reDataset = null;
+        reDataset = employeeDS.leftJoin(empOrgRelDS).on("id", "employee.id")
+                .select(employeeDS.getRowMeta().getFieldNames(),new String[] {"company.id as compId","company.name as compName","position.id as positionId","position.number as positionNum","position.name as positionName","adminorg.number as adminorgNum"})
+                .finish();
+        reDataset.print(true);
+
+        reDataset = reDataset.leftJoin(empentrelDS).on("id", "employee.id")
+                .select(reDataset.getRowMeta().getFieldNames(),new String[] {"laborrelstatus.number as laborrelstatusNum"})
+                .finish();
+        reDataset.print(true);
+
+        reDataset = reDataset.leftJoin(posgradeDS).on("id", "employee.id")
+                .select(reDataset.getRowMeta().getFieldNames(),new String[] {"nckd_posgrade.number as posgradeNum"})
+                .finish();
+        reDataset.print(true);
+
+        reDataset = reDataset.leftJoin(perprotitleDS).on("id", "employee.id")
+                .select(reDataset.getRowMeta().getFieldNames(),new String[] {"prolevel.number as prolevelNum"})
+                .finish();
+        reDataset.print(true);
+
+        reDataset = reDataset.leftJoin(perocpqualeDS).on("id", "employee.id")
+                .select(reDataset.getRowMeta().getFieldNames(),new String[] {"qualevel.number as qualevelNum"})
+                .finish();
+        reDataset.print(true);
+
+        Iterator<Row> iterator = reDataset.iterator();
+        while (iterator.hasNext()) {
+            Row row = iterator.next();
+            DynamicObject employeeFile = employeeFileMaps.get(row.getLong("id"));
+            String personNum = row.getString("number") == null ? "" : row.getString("number");
+            String personName = row.getString("name") == null ? "" : row.getString("name");
+            String adminorgNum = row.getString("adminorgNum") == null ? "" : row.getString("adminorgNum");
+            String positionNum = row.getString("positionNum") == null ? "" : row.getString("positionNum");
+            String positionName = row.getString("positionName") == null ? "" : row.getString("positionName");
+            String posgradeNum = row.getString("posgradeNum")  == null ? "" : row.getString("posgradeNum");
+            String laborrelstatusNum = row.getString("laborrelstatusNum") == null ? "" : row.getString("laborrelstatusNum");
+            String prolevelNum = row.getString("prolevelNum") == null ? "" : row.getString("prolevelNum");
+            String qualevelNum = row.getString("qualevelNum")  == null ? "" : row.getString("qualevelNum");
+
+            if(!isAll) {
+                logger.info("员工编号:{},员工姓名:{},部门:{},岗位:{},职务级别:{},职称级别:{},职业资格等级:{},用工关系状态:{}",
+                        personNum, personName, adminorgNum, positionName, posgradeNum, prolevelNum, qualevelNum, laborrelstatusNum);
+            }
+
+            int money = 0;
+            List<String> L4800 = Arrays.asList("1", "2");
+            List<String> L3600 = Arrays.asList("3", "4", "5");
+            List<String> L2400 = Arrays.asList("6", "7", "8", "9");
+            List<String> prolevelHigeList = Arrays.asList("001", "011");
+            List<String> prolevelMiddList = Arrays.asList("002", "010");
+            /**
+             * 公司领导班子成员:对应组织为集团本部-股份公司领导-公司领导和集团本部-集团公司领导在内的所有正式员工【4800/年】
+             */
+            if(laborrelstatusNum.equals("1010_S") && (adminorgNum.equals("01010201") || adminorgNum.equals("01010101"))){
+                money = 4800;
+            }
+            /**
+             * 监事会主席:对应职位编码为ZW01010377的正式员工 【4800/年】
+             * 专职外部董事:对应职位编码为ZW01010173的正式员工 【4800/年】
+             */
+            else if (laborrelstatusNum.equals("1010_S")  && (positionNum.equals("ZW01010377") || positionNum.equals("ZW01010173"))) {
+                money = 4800;
+            }
+            /**
+             * 专职监事正副职:对应职位编码为ZW01010378和ZW01010379的正式员工【3600/年】
+             */
+            else if (laborrelstatusNum.equals("1010_S")  && (positionNum.equals("ZW01010378") || positionNum.equals("ZW01010379"))) {
+                money = 3600;
+            }
+            /**
+             * 职务级别为"厅级、副厅级"的正式员工 4800
+             */
+            else if (laborrelstatusNum.equals("1010_S")  &&  L4800.contains(posgradeNum) ) {
+                money = 4800;
+            }
+            /**
+             * 职务级别为"中层正职
+             * 中层副职
+             * 中层副职(托管)"的正式员工 3600
+             */
+            else if (laborrelstatusNum.equals("1010_S")  &&  L3600.contains(posgradeNum) ) {
+                money = 3600;
+            }
+            /**
+             * 已聘任正高级职称或特级技师:对应职称级别为正高级、正高级(虚拟);技能等级为特级技师的正式员工 3600
+             */
+            else if (laborrelstatusNum.equals("1010_S")  && (prolevelHigeList.contains(prolevelNum)  ||  qualevelNum.equals("0"))) {
+                money = 3600;
+            }
+            /**
+             * 已聘任副高级职称或高级技师:对应职称级别为副高级、副高级(虚拟);技能等级为高级技师的正式员工 2400
+             */
+            else if (laborrelstatusNum.equals("1010_S")  && (prolevelMiddList.contains(prolevelNum)  ||  qualevelNum.equals("1"))) {
+                money = 2400;
+            }
+            /**
+             * 职务级别为"基层正职
+             * 基层正职(托管)
+             * 基层副职
+             * 基层副职(托管)"的正式员工 2400
+             */
+            else if (laborrelstatusNum.equals("1010_S")  &&  L2400.contains(posgradeNum) ) {
+                money = 2400;
+            }
+            /**
+             * 协理员:职位名称包含“协理员”的所有正式员工 【2400/年】
+             */
+            else if (laborrelstatusNum.equals("1010_S")  &&  positionName.contains("协理员") ) {
+                money = 2400;
+            }
+
+            /**
+             * 职务级别为"其他"的正式员工 1800
+             */
+            else if (laborrelstatusNum.equals("1010_S")  &&  posgradeNum.equals("10") ) {
+                money = 1800;
+            }else if (laborrelstatusNum.equals("1010_S")) {
+                money = 1800;
+            }
+
+
+            DynamicObjectCollection benefitEntrys = employeeFile.getDynamicObjectCollection("nckd_benefitentry");
+
+            List<DynamicObject> currYearDyn =
+                    benefitEntrys.stream().filter(e -> e.getInt("nckd_effeyear") == previousYear).collect(Collectors.toList());
+            DynamicObject benefitEntry = null;
+            if(currYearDyn.size() == 0){
+                benefitEntry = benefitEntrys.addNew() ;
+                Long entryid = DB.genGlobalLongId();
+                benefitEntry.set("id", entryid);
+            }else{
+                benefitEntry = currYearDyn.get(0);
+            }
+
+            benefitEntry.set("nckd_effeyear", previousYear);
+            benefitEntry.set("nckd_suppbenefit", money);
+
+            dynList.add(employeeFile);
+        }
+
+        Map<String, String> result = new HashMap<>();
+        int length = 0;
+        if(dynList.size() == 0) {
+            result.put("code", "200");
+            result.put("msg", "当年度待遇标准计算(补充医疗保险),执行成功,但本次没有人员数据!" );
+        }else{
+            //保存
+            Object[] update = SaveServiceHelper.save(dynList.toArray(new DynamicObject[0]));
+            length = update.length;
+            result.put("code", "200");
+            result.put("msg", "当年度待遇标准计算(补充医疗保险),执行成功,本次计算人员数量" + length);
+        }
+
+        return result;
+    }
+
+
+}

+ 48 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/plugin/operate/BaseMedicalAllowanceOpPlugin.java

@@ -0,0 +1,48 @@
+package nckd.jxccl.swc.init.plugin.operate;
+
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.args.AfterOperationArgs;
+import kd.bos.entity.plugin.args.BeforeOperationArgs;
+import kd.bos.entity.validate.ErrorLevel;
+import kd.bos.entity.validate.ValidationErrorInfo;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.swc.init.business.BaseMedicalAllowanceServiceImpl;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 单据操作插件
+ * author: turborao
+ * date: 2025/10/27 13:05
+ */
+public class BaseMedicalAllowanceOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    @Override
+    public void afterExecuteOperationTransaction(AfterOperationArgs e) {
+        //获取列表中选择的单据内码
+        List<Long> billids = (List) Arrays.asList(e.getDataEntities()).stream().map((entityx) -> {
+            return entityx.getLong("id");
+        }).collect(Collectors.toList());
+
+        if(billids != null || billids.size() > 0) {
+            BaseMedicalAllowanceServiceImpl baseMedicalAllowanceService = new BaseMedicalAllowanceServiceImpl();
+            Map<String, String> result= baseMedicalAllowanceService.calcBaseMedicalAllowanceForPersons(billids);
+
+            if(result.get("code").equals("200")){
+                this.operationResult.setShowMessage(true);
+                this.operationResult.setSuccess(true);
+                this.operationResult.setMessage(result.get("msg"));
+            }else{
+                this.operationResult.addErrorInfo(new ValidationErrorInfo("", null,
+                        0, 0, "同步失败", "提示信息", result.get("msg"), ErrorLevel.Error));
+            }
+        }else{
+            this.operationResult.setShowMessage(true);
+            this.operationResult.setSuccess(false);
+            this.operationResult.setMessage("没选中数据!");
+        }
+    }
+}

+ 34 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/plugin/other/BaseMedicalAllowanceTask.java

@@ -0,0 +1,34 @@
+package nckd.jxccl.swc.init.plugin.other;
+
+import kd.bos.context.RequestContext;
+import kd.bos.entity.validate.ErrorLevel;
+import kd.bos.entity.validate.ValidationErrorInfo;
+import kd.bos.exception.KDException;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.swc.init.business.BaseMedicalAllowanceServiceImpl;
+
+import java.util.Map;
+
+/**
+ * 后台任务插件  当年度待遇标准计算任务
+ * 后台提供定时任务(每年12月31日24点执行一次),当年度待遇根据上年度12月31日的人员状态和记录计算补助待遇,
+ * 按照年度生成多行记录,记录历史。当专员手动执行前端更新按钮时(需选中人员),
+ * 系统需根据手动的当前时间获取人员状态和记录计算补助待遇,包括对当前记录进行更新,
+ * author: turborao
+ * date: 2025/10/27 13:05
+ */
+public class BaseMedicalAllowanceTask extends AbstractTask implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(BaseMedicalAllowanceTask.class);
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+
+        BaseMedicalAllowanceServiceImpl baseMedicalAllowanceService = new BaseMedicalAllowanceServiceImpl();
+        Map<String, String> result= baseMedicalAllowanceService.calcBaseMedicalAllowanceForAll();
+
+        logger.info("当年度待遇标准计算任务,信息:" + result.get("msg"));
+    }
+}

+ 3 - 4
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/init/plugin/other/DelayedRetirementDateCalcTask.java

@@ -13,8 +13,6 @@ import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.bos.util.StringUtils;
-import kd.hrmp.hrpi.common.HRPIConstants;
-import kd.sdk.hr.hspm.business.helper.HSPMBusinessDataServiceHelper;
 import kd.sdk.plugin.Plugin;
 
 
@@ -98,11 +96,12 @@ public class DelayedRetirementDateCalcTask  extends AbstractTask implements Plug
 
         ///查询 公司信息
         QFilter filter7 = new QFilter("iscurrentdata", QCP.equals, true); // 启用
-        //QFilter filter8 = new QFilter("datastatus", QCP.equals, "1"); // 启用
+        QFilter filter8 = new QFilter("isprimary", QCP.equals, "1");  //主任职
         QFilter filter9 = new QFilter("employee.id", QCP.in, employeeIDs);
+        QFilter filter10 = new QFilter("postype.id", QCP.equals, 1010L); //主任职
 
         String selectFields1 = "id,employee.id,company.id";
-        DynamicObjectCollection empposorgreDyns = QueryServiceHelper.query("hrpi_empposorgrel", selectFields1, new QFilter[]{filter7 ,filter9});
+        DynamicObjectCollection empposorgreDyns = QueryServiceHelper.query("hrpi_empposorgrel", selectFields1, new QFilter[]{filter7 ,filter8,filter9,filter10});
 
         Map<Long, DynamicObject> empposorgreMap = (Map)empposorgreDyns.stream().collect(Collectors.toMap((obj) -> {
             return obj.getLong("employee.id");