Browse Source

MDM同步代码

Tyx 4 days ago
parent
commit
5b342e91d3

+ 98 - 71
code/jyyy/nckd-jimin-jyyy-hr/src/main/java/nckd/jimin/jyyy/hr/haos/staff/plugin/task/SyncAdminOrgTask.java

@@ -16,6 +16,7 @@ import kd.bos.util.StringUtils;
 import kd.sdk.plugin.Plugin;
 import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
 
+import java.io.IOException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
@@ -47,71 +48,77 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
          * startTime : 手工配置开始时间 yyyy-MM-dd hh24:mi:ss
          * endTime : 手工配置结束时间 yyyy-MM-dd hh24:mi:ss
          */
-        log.info("-------- SyncAdminOrgTask 开始执行同步行政组织 --------");
-        //最后调MDM的jsonObject
-        JSONObject ob = new JSONObject();
-        initDateRange(map);
-        HRBaseServiceHelper helper = new HRBaseServiceHelper(orgChgRecord_entity);
-        String selectProperties = "adminorg,orgchgentry.changescene.number,createtime";
-        //查出发生过变化的组织
-        DynamicObjectCollection changeOperateCol = helper.queryOriginalCollection(selectProperties, this.getQFilters());
-        //查询出来为空直接返回
-        if(CollectionUtils.isEmpty(changeOperateCol)) {
-            log.info("-------- 未查询到变化组织 -------- ");
-            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, "未查询到变化组织", "未调用", SyncUtil.SyncOrg);
-        }
-        else {
-            //发生变化的组织Map
-            //按照变动场景编码分成不同的List,后续根据场景分开处理
-            //ToDo 如果查询时间内,某个组织先发生组织调整,再修改除名称外其他信息怎么处理?
-            //按照组织分组,只取时间段内最新的一条记录
-            //暂时只处理(10,20,30,40,50);
-            //ToDo(80,90)目前前台界面做不了该业务,后续考虑;
-            //ToDo 60尚不明确,需确认;
-            //1010_S	    组织新设
-            //1020_S	    上级调整
-            //1030_S	    组织更名
-            //1040_S	    组织停用
-            //1050_S	    初始化新增
-            //1060_S	    初始化禁用
-            //1080_S	    组织合并
-            //1090_S	    组织拆分
-            //CS_1110_SY01	组织修订
+        try {
+            log.info("-------- SyncAdminOrgTask 开始执行同步行政组织 --------");
+            //最后调MDM的jsonObject
+            JSONObject ob = new JSONObject();
+            initDateRange(map);
+            HRBaseServiceHelper helper = new HRBaseServiceHelper(orgChgRecord_entity);
+            String selectProperties = "adminorg,orgchgentry.changescene.number,createtime";
+            //查出发生过变化的组织
+            DynamicObjectCollection changeOperateCol = helper.queryOriginalCollection(selectProperties, this.getQFilters());
+            //查询出来为空直接返回
+            if(CollectionUtils.isEmpty(changeOperateCol)) {
+                log.info("-------- 未查询到变化组织 -------- ");
+                SyncUtil.createLog(SyncUtil.v_success, startTime, endTime, "未查询到变化组织", "未调用", SyncUtil.SyncOrg);
+            }
+            else {
+                //发生变化的组织Map
+                //按照变动场景编码分成不同的List,后续根据场景分开处理
+                //ToDo 如果查询时间内,某个组织先发生组织调整,再修改除名称外其他信息怎么处理?
+                //按照组织分组,只取时间段内最新的一条记录
+                //暂时只处理(10,20,30,40,50);
+                //ToDo(80,90)目前前台界面做不了该业务,后续考虑;
+                //ToDo 60尚不明确,需确认;
+                //1010_S	    组织新设
+                //1020_S	    上级调整
+                //1030_S	    组织更名
+                //1040_S	    组织停用
+                //1050_S	    初始化新增
+                //1060_S	    初始化禁用
+                //1080_S	    组织合并
+                //1090_S	    组织拆分
+                //CS_1110_SY01	组织修订
 //            Map<String, List<DynamicObject>> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.groupingBy(
 //                            dyx -> dyx.getString("orgchgentry.changescene.number")
 //                    ));
-            //按组织ID汇总
-            Map<Long, DynamicObject> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.toMap((dyx) -> {
-                return dyx.getLong("adminorg");
-            }, (dyx) -> {
-                return dyx;
-            }, (key1, key2) -> {
-                return key2;
-            }));
-            log.info("-------- 变化组织数(不去重):" + changeOperateCol.size() + " --------");
-            log.info("-------- 变化组织数(去重):" + changeOperateMap.keySet().size() + " --------");
-            log.info("-------- 变化组织Id:" + changeOperateMap.keySet() + " --------");
+                //按组织ID汇总
+                Map<Long, DynamicObject> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.toMap((dyx) -> {
+                    return dyx.getLong("adminorg");
+                }, (dyx) -> {
+                    return dyx;
+                }, (key1, key2) -> {
+                    return key2;
+                }));
+                log.info("-------- 变化组织数(不去重):" + changeOperateCol.size() + " --------");
+                log.info("-------- 变化组织数(去重):" + changeOperateMap.keySet().size() + " --------");
+                log.info("-------- 变化组织Id:" + changeOperateMap.keySet() + " --------");
 
-            // ToDo 根据变动操作字段获取发生了组织调整的组织,后续需要根据这些组织同步下级岗位和人员
-            //组织历史查询,如果查询时间内发生多次变化,
-            //haos_adminorgdetail 组织历史查询 所属表t_haos_adminorg Id与t_org_org一样
-            selectProperties = "id,boid,number,name,orglongname,level,nckd_easid,parentorg.id,parentorg.name,parentorg.number,establishmentdate,bsed,enable,adminorgtype.name,disabledate,modifytime";
-            QFilter idQFilter = new QFilter("id", "in", changeOperateMap.keySet());
-            DynamicObject[] orgDyArr = new HRBaseServiceHelper(adminOrgDetail_entity).query(selectProperties, new QFilter[]{idQFilter});
-            //处理下长编码/长名称,星瀚内是4VTX1ACRU8A9!4VU/45/K1PJZ!4W5LG9NNW9EW这种格式 -- 直接取行政组织结构里面的长编码
-            Map<Long, DynamicObject> bosOrgMap = SyncUtil.initOrgInfo();
-            log.info("-------- 查询完组织详细信息数:" + orgDyArr.length + " --------");
-            //构建入参
-            buildJSON(ob, orgDyArr, changeOperateMap, bosOrgMap);
-            //获取调用接口地址
-            String url = SyncUtil.getUrl("org_url");
-            log.info("-------- 组织同步调用url : " + url + " --------");
-            //调用接口
-            JSONObject response = SyncUtil.doPostByHttpClient(url, ob);
-            //处理返回结果
-            String status = SyncUtil.dealResponseStatus(response);
-            //记录日志
-            SyncUtil.createLog(status, startTime, endTime, ob.toJSONString(), response.toJSONString(), SyncUtil.SyncOrg);
+                // ToDo 根据变动操作字段获取发生了组织调整的组织,后续需要根据这些组织同步下级岗位和人员
+                //组织历史查询,如果查询时间内发生多次变化,
+                //haos_adminorgdetail 组织历史查询 所属表t_haos_adminorg Id与t_org_org一样
+                selectProperties = "id,boid,number,name,orglongname,level,nckd_easid,parentorg.id,parentorg.name,parentorg.number,parentorg.nckd_easid,establishmentdate,bsed,enable,adminorgtype.name,disabledate,modifytime,creator.name";
+                QFilter idQFilter = new QFilter("id", "in", changeOperateMap.keySet());
+                DynamicObject[] orgDyArr = new HRBaseServiceHelper(adminOrgDetail_entity).query(selectProperties, new QFilter[]{idQFilter});
+                //处理下长编码/长名称,星瀚内是4VTX1ACRU8A9!4VU/45/K1PJZ!4W5LG9NNW9EW这种格式 -- 直接取行政组织结构里面的长编码
+                Map<Long, DynamicObject> bosOrgMap = SyncUtil.initOrgInfo();
+                log.info("-------- 查询完组织详细信息数:" + orgDyArr.length + " --------");
+                //构建入参
+                buildJSON(ob, orgDyArr, changeOperateMap, bosOrgMap);
+                //获取调用接口地址
+                String url = SyncUtil.getUrl("org_url");
+                log.info("-------- 组织同步调用url : " + url + " --------");
+                //调用接口
+                JSONObject response = SyncUtil.doPostByHttpClient(url, ob);
+                //处理返回结果
+                String status = SyncUtil.dealResponseStatus(response);
+                //记录日志
+                SyncUtil.createLog(status, startTime, endTime, ob.toJSONString(), response.toJSONString(), SyncUtil.SyncOrg);
+            }
+        } catch (ParseException e) {
+            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, e.getMessage(), "未调用", SyncUtil.SyncOrg);
+        } catch (IOException e) {
+            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, e.getMessage(), "未调用", SyncUtil.SyncOrg);
         }
     }
 
@@ -122,6 +129,7 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
     public void buildJSON(JSONObject ob, DynamicObject[] orgDyArr, Map<Long, DynamicObject> changeOperateMap, Map<Long, DynamicObject> bosOrgMap) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         JSONArray obj = new JSONArray();
+        Map<Long, DynamicObject> costCenterMap = SyncUtil.getCostCenter();
         for(DynamicObject org : orgDyArr) {
             JSONObject data = new JSONObject(true);
             //主体标签 默认JY
@@ -134,7 +142,7 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
             //组织名称
             data.put("MD_DESCRIPTION", org.getString("name"));
             //上级行政组织ID 看是否有easid 有就传EASID 否则传星瀚ID
-            data.put("ADM_PARENT_NUMBER", org.getString("parentorg.id"));
+            data.put("ADM_PARENT_NUMER", org.getString("parentorg.nckd_easid"));
             //上级组织名称
             data.put("ADM_PARENT_NAME", org.getString("parentorg.name"));
             //行政组织长名称 orglongname没值 去平台那边取
@@ -155,6 +163,7 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
             }
             //创建时间 取行政组织的创建时间
             Date createDate = bosOrgMap.get(org.getLong("id")).getDate("createtime");
+            data.put("ADM_CREATOR", org.getString("creator.name"));
             data.put("ADM_CREATION_TIME", sdf.format(createDate));
             //最后修改时间
             data.put("ADM_LAST_UPTIME", sdf.format(org.getDate("modifytime")));
@@ -170,13 +179,32 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
                 data.put("ADM_SEALUP", "否");
                 data.put("ADM_STORAGE_TIME", null);
             }
+            DynamicObject costCenter = costCenterMap.get(org.getLong("id"));
+            if(costCenter == null) {
+                //是否成本中心实体组织
+                data.put("ADM_ENTITY_COST_CENTER", "否");
+                //是否成本中心组织
+                data.put("ADM_COST_CENTER", "否");
+                //成本中心是否封存
+                data.put("ADM_COST_CENTER_SEALUP", "否");
+            }
+            else {
+                data.put("ADM_COST_CENTER", "是");
+                if(costCenter.getBoolean("costcenter.isleaf")) {
+                    data.put("ADM_ENTITY_COST_CENTER", "是");
+                }
+                else {
+                    data.put("ADM_ENTITY_COST_CENTER", "否");
+                }
+                int ccEnable = costCenter.getInt("costcenter.enable");
+                if(ccEnable == 1) {
+                    data.put("ADM_COST_CENTER_SEALUP", "否");
+                }
+                else {
+                    data.put("ADM_COST_CENTER_SEALUP", "是");
+                }
+            }
 
-            //是否成本中心实体组织 TODO
-            data.put("ADM_ENTITY_COST_CENTER", null);
-            //是否成本中心组织 TODO
-            data.put("ADM_COST_CENTER", null);
-            //成本中心是否封存 TODO
-            data.put("ADM_COST_CENTER_SEALUP", null);
             obj.add(data);
         }
         SyncUtil.setJSONArraySorted(obj, "MD_LEVEL");
@@ -188,7 +216,7 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
      * 根据调度作业上配置的参数初始化时间范围
      * @param map
      */
-    public void initDateRange(Map<String, Object> map) {
+    public void initDateRange(Map<String, Object> map) throws ParseException {
         boolean isAuto = Boolean.valueOf(map.get("isAuto").toString());
         if(!isAuto) {
             startTime = map.get("startTime").toString();
@@ -197,8 +225,7 @@ public class SyncAdminOrgTask extends AbstractTask implements Plugin {
         //取最近一次日志的时间
         else {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            // ToDo
-            //startTime = "";
+            startTime = sdf.format(SyncUtil.getLastSyncEndTime(SyncUtil.SyncOrg));
             endTime = sdf.format(new Date());
         }
     }

+ 182 - 2
code/jyyy/nckd-jimin-jyyy-hr/src/main/java/nckd/jimin/jyyy/hr/haos/staff/plugin/task/SyncPersonTask.java

@@ -1,20 +1,200 @@
 package nckd.jimin.jyyy.hr.haos.staff.plugin.task;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import kd.bos.algo.DataSet;
+import kd.bos.algo.Row;
 import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.db.DB;
+import kd.bos.db.DBRoute;
 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 java.util.Map;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
 
 /**
  * 2025-04-16 Tyx
  * 人员变动数据同步MDM
  */
 public class SyncPersonTask extends AbstractTask implements Plugin {
-
+    private static final Log log = LogFactory.getLog(SyncPersonTask.class);
+    private static String person_entity = "hrpi_person";                //人员主表
+    private static String perNonTsProp_entity = "hrpi_pernontsprop";    //人员非时序性属性 维护完一般不会变动的数据,民族性别血型等;
+    private static String perTsProp_entity = "hrpi_pertsprop";          //人员时序性属性 维护完会发生变动的数据,婚姻/生育/健康状况等;
+    private static String empPosOrg_entity = "hrpi_empposorgrel";       //员工任职经历 取岗位组织等信息
+    private static String perRegion_entity = "hrpi_perregion";          //员工区域信息 籍贯等信息
+    private static String perContact_entity = "hrpi_percontact";        //员工联系方式,用于取电话号码和邮箱等
+    private static String quitBill_entity = "htm_quithandle";           //离职办理单,用于取离职日期及离职单号
+    private static String perCre_entity = "hrpi_percre";                //员工证件信息,用于取身份证/证照
+    private static String startTime = "";
+    private static String endTime = "";
+    private static Set changePersonSet = new HashSet<>();
     @Override
     public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        log.info("-------- SyncPositionTask 开始执行同步人员 --------");
+        try {
+            JSONObject ob = new JSONObject();
+            initDateRange(map);
+            //sql查出来数据
+            DataSet dataSet = getChangePerson();
+            //dataSet.print(true);
+            //处理组织长名称
+            Map<Long, DynamicObject> orgDyxMap = SyncUtil.initOrgInfo();
+            //获取调用接口地址
+            String url = SyncUtil.getUrl("person_url");
+            log.info("-------- 人员同步调用url : " + url + " --------");
+            //处理兼职
+            Map<Long, JSONArray> partTimeMap = getPartTimeInfo(orgDyxMap);
+            //构建入参
+            buildJSON(ob, dataSet, orgDyxMap, partTimeMap);
+            if(ob.getJSONArray("obj") == null) {
+                SyncUtil.createLog(SyncUtil.v_success, startTime, endTime, "未查询到变化人员", "未调用", SyncUtil.SyncPerson);
+            }
+            //调用接口
+            JSONObject response = SyncUtil.doPostByHttpClient(url, ob);
+            //处理返回结果
+            String status = SyncUtil.dealResponseStatus(response);
+            //记录日志
+            SyncUtil.createLog(status, startTime, endTime, ob.toJSONString(), response.toJSONString(), SyncUtil.SyncPerson);
+        } catch (ParseException e) {
+            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, null, e.getMessage(), SyncUtil.SyncPerson);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void buildJSON(JSONObject ob, DataSet dataSet, Map<Long, DynamicObject> orgDyxMap, Map<Long, JSONArray> partTimeMap) {
+        JSONArray obj = new JSONArray();
+        String[] fieldNames = dataSet.getRowMeta().getFieldNames();
+        while(dataSet.hasNext()) {
+            JSONObject data = new JSONObject(true);
+            Row rowData = dataSet.next();
+            //循环put数据
+            for (String field : fieldNames) {
+                data.put(field.toUpperCase(), rowData.get(field));
+            }
+            //处理组织长名称
+            data.put("EMP_W_DEPLNAME", orgDyxMap.get(rowData.getLong("orgid")).getString("structure.fullname"));
+            data.put("EMP_W_EMPLOYNUMBER", "test-20250401-0011");
+            changePersonSet.add(rowData.getLong("PERSONID"));
+
+            //处理兼职
+            JSONArray partJob = partTimeMap.get(rowData.getLong("PERSONID"));
+            if(partJob != null) {
+                data.put("partJob", partJob);
+            }
+            obj.add(data);
+        }
+        ob.put("obj", obj);
+    }
+
+
+        /**
+         * 受不了了直接写sql语句de
+         * @return
+         */
+    public DataSet getChangePerson() {
+        //获取人员查询sql
+        StringBuilder sb = SyncUtil.getPersonQuerySql();
+        //修改日期
+        sb.append("   and (");
+        sb.append("   (to_char(person.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(person.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(a.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(a.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(b.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(b.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(c.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(c.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(d.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(d.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(e.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(e.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(f.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(f.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(g.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(g.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(g1.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(g1.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(h.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(h.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) or \n");
+        sb.append("   (to_char(m.fmodifytime,'yyyy-MM-dd hh24:mi:ss') <= '"+endTime+"' and to_char(m.fmodifytime,'yyyy-MM-dd hh24:mi:ss') >=  '"+startTime+"' ) \n");
+        sb.append("   )");
+        log.info("-------- 查询人员sql :" + sb.toString() + " -------- ");
+        DataSet dataSet = DB.queryDataSet(this.getClass().getName(), DBRoute.of("hr"), sb.toString());
+        return dataSet;
+    }
+
+    /**
+     * 获取兼职档案, 人员ID - JSONArray数据
+     *
+     * @return
+     */
+    public Map<Long, JSONArray> getPartTimeInfo (Map<Long, DynamicObject> orgDyxMap) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("/*dialect*/ select a.fpersonId personId, \n");
+        sb.append("        pos.fid EMP_P_PRIMARY_KEY, \n");
+        sb.append("        to_char(a.fstartdate,'yyyy-MM-dd') EMP_P_STARTDATE, \n");
+        sb.append("        to_char(a.fenddate,'yyyy-MM-dd') EMP_P_ENDDATE, \n");
+        sb.append("        '上海济煜' EMP_P_SUBCOMPANY, \n");
+        sb.append("        org.fid ORGID, \n");
+        sb.append("        case when org.fk_nckd_easid = ' ' then org.fid::VARCHAR else org.fk_nckd_easid end EMP_P_DEPCODE, \n");
+        sb.append("        org.fname EMP_P_DEPNAME, \n");
+        sb.append("        pos.fnumber EMP_P_POSICODE, \n");
+        sb.append("        pos.fname EMP_P_POSINAME, \n");
+        sb.append("        pos1.fnumber EMP_P_PARPOSICODE, \n");
+        sb.append("        pos1.fname EMP_P_PARPOSINAME, \n");
+        sb.append("        '2' EMP_P_FORTYPE, \n");
+        sb.append("        '否' EMP_P_DELETLOGO \n");
+        sb.append(" from t_hrpi_ermanfile a \n");
+        sb.append(" left join t_hrpi_erfiletype b on a.ffiletypeid = b.fid \n");
+        sb.append(" left join t_hbss_postype c on b.fpostypeid = c.fid \n");
+        sb.append(" left join t_hrpi_empposorgrel d on d.fid = a.fempposrelid \n");
+        sb.append(" left join t_hbpm_position pos on pos.fid = d.fpositionid \n");
+        sb.append(" left join t_hbpm_position pos1 on pos1.fid = pos.fparentid  \n");
+        sb.append(" left join t_haos_adminorg org on org.fid = d.fadminorgid \n");
+        sb.append(" where c.fnumber = '1020_S' \n");
+        sb.append("    and a.fiscurrentversion = '1' \n");
+        log.info("-------- 查询人员兼职sql :" + sb.toString() + " -------- ");
+        DataSet dataSet = DB.queryDataSet(this.getClass().getName(), DBRoute.of("hr"), sb.toString());
+
+        Map<Long, JSONArray> partTimeMap = new HashMap<Long, JSONArray>();
+        String[] fieldNames = dataSet.getRowMeta().getFieldNames();
+        while(dataSet.hasNext()) {
+            JSONObject data = new JSONObject(true);
+            Row rowData = dataSet.next();
+            //循环put数据
+            for (String field : fieldNames) {
+                data.put(field.toUpperCase(), rowData.get(field));
+            }
+            data.put("EMP_P_DEPLNAME",orgDyxMap.get(rowData.getLong("ORGID")).getString("structure.fullname"));
+            JSONArray partTimeArr = partTimeMap.get(rowData.getLong("PERSONID"));
+            if(partTimeArr != null) {
+                partTimeArr.add(data);
+            }
+            else {
+                partTimeArr = new JSONArray();
+                partTimeArr.add(data);
+            }
+            partTimeMap.put(rowData.getLong("PERSONID"), partTimeArr);
+        }
+        return partTimeMap;
+    }
+
+
 
+    /**
+     * 根据调度作业上配置的参数初始化时间范围
+     * @param map
+     */
+    public void initDateRange(Map<String, Object> map) throws ParseException {
+        boolean isAuto = Boolean.valueOf(map.get("isAuto").toString());
+        if(!isAuto) {
+            startTime = map.get("startTime").toString();
+            endTime = map.get("endTime").toString();
+        }
+        //取最近一次日志的时间
+        else {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            startTime = sdf.format(SyncUtil.getLastSyncEndTime(SyncUtil.SyncPerson));
+            endTime = sdf.format(new Date());
+        }
     }
 }

+ 77 - 59
code/jyyy/nckd-jimin-jyyy-hr/src/main/java/nckd/jimin/jyyy/hr/haos/staff/plugin/task/SyncPositionTask.java

@@ -17,6 +17,7 @@ import kd.bos.util.StringUtils;
 import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
 import kd.sdk.plugin.Plugin;
 
+import java.io.IOException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -35,58 +36,64 @@ public class SyncPositionTask extends AbstractTask implements Plugin {
     private static String endTime = "";
     @Override
     public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
-        log.info("-------- SyncPositionTask 开始执行同步岗位 --------");
-        JSONObject ob = new JSONObject();
-        initDateRange(map);
-        HRBaseServiceHelper helper = new HRBaseServiceHelper(posChgRecord_entity);
-        String selectProperties = "position,evententry.changescene.number,createtime";
-        //String selectProperties = "aaa";
-        //查出发生过变化的岗位
-        DynamicObjectCollection changeOperateCol = helper.queryOriginalCollection(selectProperties, this.getQFilters());
-        //查询出来为空直接返回
-        if(CollectionUtils.isEmpty(changeOperateCol)) {
-            log.info("-------- 未查询到变化岗位 -------- ");
-            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, "未查询到变化岗位", "未调用", SyncUtil.SyncPosition);
-        }
-        else {
-            //按岗位ID汇总,查询时间段内发生变化的岗位
-            Map<Long, DynamicObject> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.toMap((dyx) -> {
-                return dyx.getLong("position");
-            }, (dyx) -> {
-                return dyx;
-            }, (key1, key2) -> {
-                return key2;
-            }));
-            log.info("-------- 变化岗位数(不去重):" + changeOperateCol.size() + " --------");
-            log.info("-------- 变化岗位数(去重):" + changeOperateMap.keySet().size() + " --------");
-            log.info("-------- 变化岗位Id:" + changeOperateMap.keySet() + " --------");
+        try {
+            log.info("-------- SyncPositionTask 开始执行同步岗位 --------");
+            JSONObject ob = new JSONObject();
+            initDateRange(map);
+            HRBaseServiceHelper helper = new HRBaseServiceHelper(posChgRecord_entity);
+            String selectProperties = "position,evententry.changescene.number,createtime";
+            //String selectProperties = "aaa";
+            //查出发生过变化的岗位
+            DynamicObjectCollection changeOperateCol = helper.queryOriginalCollection(selectProperties, this.getQFilters());
+            //查询出来为空直接返回
+            if(CollectionUtils.isEmpty(changeOperateCol)) {
+                log.info("-------- 未查询到变化岗位 -------- ");
+                SyncUtil.createLog(SyncUtil.v_success, startTime, endTime, "未查询到变化岗位", "未调用", SyncUtil.SyncPosition);
+            }
+            else {
+                //按岗位ID汇总,查询时间段内发生变化的岗位
+                Map<Long, DynamicObject> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.toMap((dyx) -> {
+                    return dyx.getLong("position");
+                }, (dyx) -> {
+                    return dyx;
+                }, (key1, key2) -> {
+                    return key2;
+                }));
+                log.info("-------- 变化岗位数(不去重):" + changeOperateCol.size() + " --------");
+                log.info("-------- 变化岗位数(去重):" + changeOperateMap.keySet().size() + " --------");
+                log.info("-------- 变化岗位Id:" + changeOperateMap.keySet() + " --------");
 
-            //查询出变化岗位之后,找到对应岗位数据以及所属组织数据
-            selectProperties = "id,adminorg.id,adminorg.name,adminorg.number,adminorg.nckd_easid,parent.name,parent.id,parent.number,number,name,enable,isleader,modifytime";
-            QFilter idQFilter = new QFilter("id", "in", changeOperateMap.keySet());
-            DynamicObjectCollection posDyArr = new HRBaseServiceHelper(posDetail_entity).queryOriginalCollection(selectProperties, new QFilter[]{idQFilter});
-            log.info("-------- 查询完岗位详细信息数:" + posDyArr.size() + " --------");
-            //处理下组织长名称
-            Map<Long, DynamicObject> orgMap = (Map)posDyArr.stream().collect(Collectors.toMap((dyx) -> {
-                return dyx.getLong("adminorg.id");
-            }, (dyx) -> {
-                return dyx;
-            }, (key1, key2) -> {
-                return key2;
-            }));
-            //工具类查询组织相关信息返回Map key为组织ID
-            Map<Long, DynamicObject> orgDyxMap = SyncUtil.initOrgInfo(orgMap);
-            //获取调用接口地址
-            String url = SyncUtil.getUrl("position_url");
-            log.info("-------- 岗位同步调用url : " + url + " --------");
-            //构建入参
-            buildJSON(ob, posDyArr, changeOperateMap, orgDyxMap);
-            //调用接口
-            JSONObject response = SyncUtil.doPostByHttpClient(url, ob);
-            //处理返回结果
-            String status = SyncUtil.dealResponseStatus(response);
-            //记录日志
-            SyncUtil.createLog(status, startTime, endTime, ob.toJSONString(), response.toJSONString(), SyncUtil.SyncPosition);
+                //查询出变化岗位之后,找到对应岗位数据以及所属组织数据
+                selectProperties = "id,adminorg.id,adminorg.name,adminorg.number,adminorg.nckd_easid,parent.name,parent.id,parent.number,number,name,enable,isleader,modifytime,issensitive,nckd_isgxp";
+                QFilter idQFilter = new QFilter("id", "in", changeOperateMap.keySet());
+                DynamicObjectCollection posDyArr = new HRBaseServiceHelper(posDetail_entity).queryOriginalCollection(selectProperties, new QFilter[]{idQFilter});
+                log.info("-------- 查询完岗位详细信息数:" + posDyArr.size() + " --------");
+                //处理下组织长名称
+                Map<Long, DynamicObject> orgMap = (Map)posDyArr.stream().collect(Collectors.toMap((dyx) -> {
+                    return dyx.getLong("adminorg.id");
+                }, (dyx) -> {
+                    return dyx;
+                }, (key1, key2) -> {
+                    return key2;
+                }));
+                //工具类查询组织相关信息返回Map key为组织ID
+                Map<Long, DynamicObject> orgDyxMap = SyncUtil.initOrgInfo(orgMap);
+                //获取调用接口地址
+                String url = SyncUtil.getUrl("position_url");
+                log.info("-------- 岗位同步调用url : " + url + " --------");
+                //构建入参
+                buildJSON(ob, posDyArr, changeOperateMap, orgDyxMap);
+                //调用接口
+                JSONObject response = SyncUtil.doPostByHttpClient(url, ob);
+                //处理返回结果
+                String status = SyncUtil.dealResponseStatus(response);
+                //记录日志
+                SyncUtil.createLog(status, startTime, endTime, ob.toJSONString(), response.toJSONString(), SyncUtil.SyncPosition);
+            }
+        } catch (ParseException e) {
+            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, e.getMessage(), "未调用", SyncUtil.SyncPosition);
+        } catch (IOException e) {
+            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, e.getMessage(), "未调用", SyncUtil.SyncPosition);
         }
     }
 
@@ -134,7 +141,6 @@ public class SyncPositionTask extends AbstractTask implements Plugin {
             else {
                 data.put("POSI_STATE","0");
             }
-
             //是否负责人职位
             int isLeader = pos.getInt("isleader");
             if(isLeader == 1) {
@@ -143,6 +149,22 @@ public class SyncPositionTask extends AbstractTask implements Plugin {
             else {
                 data.put("POSI_POSIT_CHARGE","否");
             }
+            //是否涉密岗位
+            int isSecret = pos.getInt("issensitive");
+            if(isSecret == 1) {
+                data.put("POSI_IS_SECRET","是");
+            }
+            else {
+                data.put("POSI_IS_SECRET","否");
+            }
+            //是否GXP
+            int isGxp = pos.getInt("nckd_isgxp");
+            if(isGxp == 1) {
+                data.put("POSI_IS_GXP","是");
+            }
+            else {
+                data.put("POSI_IS_GXP","否");
+            }
             //最后更新时间
             data.put("POSI_LAST_UPTIME",sdf.format(pos.getDate("modifytime")));
             obj.add(data);
@@ -153,11 +175,8 @@ public class SyncPositionTask extends AbstractTask implements Plugin {
     }
 
 
-    /**
-     * 根据调度作业上配置的参数初始化时间范围
-     * @param map
-     */
-    public void initDateRange(Map<String, Object> map) {
+
+    public void initDateRange(Map<String, Object> map) throws ParseException {
         boolean isAuto = Boolean.valueOf(map.get("isAuto").toString());
         if(!isAuto) {
             startTime = map.get("startTime").toString();
@@ -166,8 +185,7 @@ public class SyncPositionTask extends AbstractTask implements Plugin {
         //取最近一次日志的时间
         else {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            // ToDo
-            //startTime = "";
+            startTime = sdf.format(SyncUtil.getLastSyncEndTime(SyncUtil.SyncPosition));
             endTime = sdf.format(new Date());
         }
     }

+ 120 - 16
code/jyyy/nckd-jimin-jyyy-hr/src/main/java/nckd/jimin/jyyy/hr/haos/staff/plugin/task/SyncUtil.java

@@ -17,6 +17,8 @@ import kd.bos.workflow.exception.WFErrorCode;
 import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
 
 import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -187,22 +189,18 @@ public class SyncUtil {
      * @param bodyData
      * @return
      */
-    public static JSONObject doPostByHttpClient(String url, JSONObject bodyData) {
-        try {
-            Map<String, String> headers = new HashMap();
-            headers.put("Content-Type", "application/json");
-            headers.put("Accept", "*/*");
-            logger.info(String.format("url[%s],data[%s]", url, bodyData.toJSONString()));
-            System.out.println(String.format("url[%s],data[%s]", url, bodyData.toJSONString()));
-
-            String responseEntify = HttpClientUtils.postjson(url, headers, bodyData.toJSONString());
-
-            logger.info(responseEntify);
-            JSONObject result = (JSONObject)JSONObject.parse(responseEntify);
-            return result;
-        } catch (IOException var5) {
-            throw new KDException(var5, WFErrorCode.httpRequestException(), new Object[]{var5.getMessage()});
-        }
+    public static JSONObject doPostByHttpClient(String url, JSONObject bodyData) throws IOException {
+        Map<String, String> headers = new HashMap();
+        headers.put("Content-Type", "application/json");
+        headers.put("Accept", "*/*");
+        logger.info(String.format("url[%s],data[%s]", url, bodyData.toJSONString()));
+        System.out.println(String.format("url[%s],data[%s]", url, bodyData.toJSONString()));
+
+        String responseEntify = HttpClientUtils.postjson(url, headers, bodyData.toJSONString());
+
+        logger.info(responseEntify);
+        JSONObject result = (JSONObject)JSONObject.parse(responseEntify);
+        return result;
     }
 
     /**
@@ -242,6 +240,46 @@ public class SyncUtil {
         return status;
     }
 
+    /**
+     * 查询成本中心信息
+     * 基础资料-财务数据-成本中心映射配置
+     * @return
+     */
+    public static Map<Long, DynamicObject> getCostCenter() {
+        String selectFields = "costcenter.isleaf,costcenter.enable,entryentity.sourcetype,entryentity.sourcedata.id,entryentity.sourcedata.number";
+        QFilter filter1 = new QFilter("entryentity.sourcetype", QCP.equals, "bos_adminorg");
+        DynamicObjectCollection cols = QueryServiceHelper.query("bos_costcentersourcemap", selectFields, new QFilter[]{filter1});
+        Map<Long, DynamicObject> costCenterMap = (Map)cols.stream().collect(Collectors.toMap((dyx) -> {
+            return dyx.getLong("entryentity.sourcedata.id");
+        }, (dyx) -> {
+            return dyx;
+        }, (key1, key2) -> {
+            return key2;
+        }));
+        return costCenterMap;
+    }
+
+
+
+
+    /**
+     * 获取上一次同步时间
+     * @param type
+     */
+    public static Date getLastSyncEndTime(String type) throws ParseException {
+        QFilter filter = new QFilter("nckd_synctype", QCP.equals, type);
+        filter.and("nckd_status", QCP.equals, "A");
+        DynamicObjectCollection logInfos = QueryServiceHelper.query(KEY_ENTITY_LOG, "nckd_endtime", new QFilter[]{filter}, "nckd_endtime desc", 1);
+        if(logInfos.size() > 0) {
+            return logInfos.get(0).getDate("nckd_endtime");
+        }
+        else {
+            String dateStr = "1900-01-01";
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            return sdf.parse(dateStr);
+        }
+    }
+
     /**
      * 创建同步日志
      * @param status 同步状态 A-成功 B-部分成功 C-失败
@@ -278,5 +316,71 @@ public class SyncUtil {
         logger.info("-------- 保存日志 --------");
     }
 
+    public static StringBuilder getPersonQuerySql() {
+        StringBuilder sb = new StringBuilder();
+        // 人员ID,主体标签,人员姓名,人员工号,部门ID,部门编码,部门名称
+        sb.append("/*dialect*/ select a.fid PERSONID,'JY' MAIN_BODY_ID, a.fname MD_DESCRIPTION ,a.fnumber MD_CODE,org.fid ORGID,case when org.fk_nckd_easid = ' ' then org.fid::VARCHAR else org.fk_nckd_easid end EMP_W_DEPCODE ,org.fname EMP_W_DEPNAME,\n");
+        // 年龄,职位名称,职位编码,上级职位名称,上级职位编码
+        sb.append("             b.fage EMP_B_AGE,pos.fname EMP_W_JOBNAME,pos.fnumber EMP_W_JOBCODE,pos1.fname EMP_W_PARJOBNAME,pos1.fnumber EMP_W_PARJOBCODE,\n");
+        // TODO sb.append("             -- 长名称、户籍地址\n");
+        sb.append("             r.fnumber EMP_B_PERS_PROPERTY, \n");
+        //性别
+        sb.append("             case when sex.fid = '1010' then 1 when sex.fid = '1020' then 2 else 0 end EMP_B_GENDER,\n");
+        // TODO 离退休日期 离职单审批日期
+        //所属公司
+        sb.append("             '上海济煜' EMP_W_COM,\n");
+        // 手机号码,实际转正日期
+        sb.append("             substring(e.fphone,5,15) EMP_B_MOBI_PHNUM,to_char(h.frealregulardate,'yyyy-MM-dd') EMP_W_OBTA_DATE,\n");
+        // 用人单位编码,职级
+        // TODO sb.append("             q.fnumber EMP_B_BELONG_LEGAL, p.fnumber EMP_B_RANK, \n");
+        sb.append("             '1054' EMP_B_BELONG_LEGAL, p.fnumber EMP_B_RANK, \n");
+        sb.append("             to_char(person.fmodifytime,'yyyy-MM-dd hh24:mi:ss') EMP_B_LAST_UPTIME, \n");
+        // 邮箱,生日,办公地点
+        sb.append("             e.fbusemail EMP_B_EMAIL,to_char(b.fbirthday,'yyyy-MM-dd') EMP_B_DATE_BIRTH,wp.fname EMP_B_WORKSPACE,\n");
+        // 身份证,用工关系状态,国籍
+        sb.append("             g.fnumber EMP_B_IDNUMBER, n.fk_nckd_mdmkey EMP_B_RELA_STATUS, nation.fk_nckd_mdmkey EMP_B_NATIONALITY, \n");
+        // 在职状态
+        sb.append("             s.fk_nckd_mdmkey EMP_W_WORKSTATE, \n");
+        // 离职单相关信息
+        sb.append("             j.fbillno EMP_W_RESIGNNUMBER,\n");
+        sb.append("             to_char(i.fcontractenddate,'yyyy-MM-dd') EMP_W_RESIGNBIZDATE,\n");
+        sb.append("             to_char(j.fcreatetime,'yyyy-MM-dd') EMP_W_RESIGNCREATEDATE,\n");
+        sb.append("             case when k.fjoincomdate is null then '2025-04-01' else to_char(k.fjoincomdate,'yyyy-MM-dd') end EMP_W_ENTRY_DATE,\n");
+        // TODO 现居住地
+        sb.append("             case when b.fk_nckd_isgbqs = '1' then '是' else '否' end EMP_B_RELAT_CADRES, \n");
+        sb.append("             d.fnativeplace EMP_B_NATIVE_PLACE ,g1.fnumber EMP_B_PASSPORT,l.fk_nckd_mdmkey EMP_B_NATIONAL \n");
+        sb.append(" from t_hrpi_ermanfile person\n");
+        sb.append(" left join t_hrpi_person a on a.fid = person.fpersonid and a.fiscurrentversion = '1'     -- 人员主表\n");
+        sb.append(" left join t_hrpi_pernontsprop b on a.fid = b.fpersonid and b.fiscurrentversion = '1'    -- 非时序\n");
+        sb.append(" left join t_hrpi_pertsprop c on a.fid = c.fpersonid and c.fiscurrentversion = '1'            -- 时序\n");
+        sb.append(" left join t_hrpi_perregion d on a.fid = d.fpersonid and d.fiscurrentversion = '1'         -- 区域信息\n");
+        sb.append(" left join t_hrpi_percontact e on a.fid = e.fpersonid and e.fiscurrentversion = '1'       -- 联系方式\n");
+        sb.append(" inner join t_hrpi_empposorgrel f on f.fid = person.fempposrelid and f.fiscurrentversion = '1' and f.fisprimary = '1'   -- 任职经历\n");
+        sb.append(" left join t_hrpi_percre g on a.fid = g.fpersonid and g.fiscurrentversion = '1' and g.fcredentialstypeid = '1010'                    -- 证件信息 身份证\n");
+        sb.append(" left join t_hrpi_percre g1 on a.fid = g1.fpersonid and g1.fiscurrentversion = '1' and g1.fcredentialstypeid = '1020'           -- 证件信息 护照\n");
+        sb.append(" left join t_hrpi_trialperiod h on a.fid = h.fpersonid and h.fiscurrentversion = '1'        -- 试用期\n");
+        sb.append(" left join t_haos_adminorg org on org.fid = f.fadminorgid                                             -- 所属部门\n");
+        sb.append(" left join t_hbpm_position pos on pos.fid = f.fpositionid                                               -- 岗位\n");
+        sb.append(" left join t_hbpm_position pos1 on pos1.fid = pos.fparentid                                          -- 上级岗位\n");
+        sb.append(" left join t_hbss_sex sex on sex.fid = b.fgenderid                                                            -- 性别\n");
+        sb.append(" left join t_hbss_workplace wp on wp.fid = f.fworkplaceid                                           -- 工作地点\n");
+        sb.append(" left join t_hbss_nationality nation on nation.fid = b.fnationalityid                              -- 国籍\n");
+        sb.append(" left join t_htm_quitfileinfo i on i.femployeeid = f.femployeeid                                       -- 离职档案\n");
+        sb.append(" left join t_htm_quitapplybill j on j.fid = i.fquitapplyid                                                    -- 离职办理单\n");
+        sb.append(" left join t_hrpi_perserlen k on a.fid = k.fpersonid and k.fiscurrentversion = '1'         -- 服务年限\n");
+        sb.append(" left join t_hbss_flok l on l.fid = b.ffolkid                                                                          -- 民族\n");
+        sb.append(" left join t_hrpi_empentrel m on m.fid = person.fempentrelid                                      -- 职业信息\n");
+        sb.append(" left join t_hbss_laborrelstatus n on n.fid = m.flaborrelstatusid                                  -- 用工关系状态\n");
+        sb.append(" left join t_hrpi_empjobrel o on a.fid = o.fpersonid and o.fiscurrentversion  = '1'     -- 职级职等 \n");
+        sb.append(" left join t_hbjm_joblevel p on p.fid = o.fjoblevelid  -- 职级 \n");
+        sb.append(" left join t_hbss_enterprise q on q.fid = m.fenterpriseid   -- 用人单位 \n");
+        sb.append(" left join tk_nckd_personproperty r on r.fid = b.fk_nckd_personproperty -- 个人性质 \n");
+        sb.append(" left join t_hbss_labrelstatuscls s on s.fid = n.flabrelstatusclsid -- 用工状态分类 \n");
+        sb.append(" where person.fiscurrentversion = '1' \n");
+        sb.append("   and person.fbusinessstatus = '1' \n");
+        return sb;
+    }
+
+
 
 }