iwork 人员组织同步相关
This commit is contained in:
@@ -14,6 +14,9 @@ public class AdminUserRespDTO implements VO {
|
|||||||
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "zhangsan")
|
||||||
|
private String username;
|
||||||
|
|
||||||
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
|
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
|
||||||
|
|||||||
@@ -114,17 +114,23 @@ public class IWorkIntegrationController {
|
|||||||
// ----------------- 同步到本地 -----------------
|
// ----------------- 同步到本地 -----------------
|
||||||
|
|
||||||
@PostMapping("/hr/full-sync")
|
@PostMapping("/hr/full-sync")
|
||||||
@Operation(summary = "手动触发 iWork 组织/人员全量同步")
|
@Operation(summary = "手动触发 iWork 组织/人员同步")
|
||||||
public CommonResult<IWorkFullSyncRespVO> fullSync(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
public CommonResult<IWorkFullSyncRespVO> fullSync(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
||||||
return success(syncService.fullSync(reqVO));
|
return success(syncService.fullSync(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/hr/departments/full-sync")
|
@PostMapping("/hr/departments/full-sync")
|
||||||
@Operation(summary = "手动触发 iWork 部门全量同步")
|
@Operation(summary = "手动触发 iWork 部门同步")
|
||||||
public CommonResult<IWorkFullSyncRespVO> fullSyncDepartments(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
public CommonResult<IWorkFullSyncRespVO> fullSyncDepartments(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
||||||
return success(syncService.fullSyncDepartments(reqVO));
|
return success(syncService.fullSyncDepartments(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/hr/subcompanies/full-sync")
|
||||||
|
@Operation(summary = "手动触发 iWork 分部同步")
|
||||||
|
public CommonResult<IWorkFullSyncRespVO> fullSyncSubcompanies(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
||||||
|
return success(syncService.fullSyncSubcompanies(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/hr/job-titles/full-sync")
|
@PostMapping("/hr/job-titles/full-sync")
|
||||||
@Operation(summary = "手动触发 iWork 岗位全量同步")
|
@Operation(summary = "手动触发 iWork 岗位全量同步")
|
||||||
public CommonResult<IWorkFullSyncRespVO> fullSyncJobTitles(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
public CommonResult<IWorkFullSyncRespVO> fullSyncJobTitles(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
|
||||||
|
|||||||
@@ -159,13 +159,9 @@ public class IWorkHrDepartmentPageRespVO {
|
|||||||
private String supsubcomname;
|
private String supsubcomname;
|
||||||
|
|
||||||
@Schema(description = "父部门 ID")
|
@Schema(description = "父部门 ID")
|
||||||
@JsonProperty("parentdeptid")
|
@JsonProperty("supdepid")
|
||||||
@JsonDeserialize(using = LenientIntegerDeserializer.class)
|
@JsonDeserialize(using = LenientIntegerDeserializer.class)
|
||||||
private Integer parentdeptid;
|
private Integer supdepid;
|
||||||
|
|
||||||
@Schema(description = "父部门名称")
|
|
||||||
@JsonProperty("parentdeptname")
|
|
||||||
private String parentdeptname;
|
|
||||||
|
|
||||||
@Schema(description = "层级路径")
|
@Schema(description = "层级路径")
|
||||||
@JsonProperty("alllevel")
|
@JsonProperty("alllevel")
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import com.fasterxml.jackson.annotation.JsonAnySetter;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
import com.zt.plat.module.system.service.integration.iwork.jackson.LenientIntegerDeserializer;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import com.zt.plat.module.system.service.integration.iwork.jackson.LenientIntegerDeserializer;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -50,9 +49,10 @@ public class IWorkHrSubcompanyPageRespVO {
|
|||||||
@Schema(description = "分部信息")
|
@Schema(description = "分部信息")
|
||||||
public static class Subcompany {
|
public static class Subcompany {
|
||||||
|
|
||||||
@Schema(description = "分部唯一 ID")
|
@Schema(description = "部门 ID(iWork 主键)")
|
||||||
@JsonProperty("subcompanyid1")
|
@JsonProperty("id")
|
||||||
private Integer subcompanyid1;
|
@JsonDeserialize(using = LenientIntegerDeserializer.class)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
@Schema(description = "分部编码")
|
@Schema(description = "分部编码")
|
||||||
@JsonProperty("subcompanycode")
|
@JsonProperty("subcompanycode")
|
||||||
|
|||||||
@@ -74,6 +74,12 @@ public class DeptServiceImpl implements DeptService {
|
|||||||
// 校验部门名的唯一性
|
// 校验部门名的唯一性
|
||||||
validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
|
validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
|
||||||
// 生成并校验部门编码
|
// 生成并校验部门编码
|
||||||
|
boolean isIWorkSource = Objects.equals(createReqVO.getDeptSource(), DeptSourceEnum.IWORK.getSource());
|
||||||
|
if (isIWorkSource) {
|
||||||
|
// iWork 来源直接使用提供的编码,不再生成
|
||||||
|
String providedCode = StrUtil.blankToDefault(createReqVO.getCode(), null);
|
||||||
|
createReqVO.setCode(providedCode);
|
||||||
|
} else {
|
||||||
Long effectiveParentId = normalizeParentId(createReqVO.getParentId());
|
Long effectiveParentId = normalizeParentId(createReqVO.getParentId());
|
||||||
boolean isTopLevel = Objects.equals(effectiveParentId, DeptDO.PARENT_ID_ROOT);
|
boolean isTopLevel = Objects.equals(effectiveParentId, DeptDO.PARENT_ID_ROOT);
|
||||||
String resolvedCode;
|
String resolvedCode;
|
||||||
@@ -84,6 +90,7 @@ public class DeptServiceImpl implements DeptService {
|
|||||||
validateDeptCodeUnique(null, resolvedCode);
|
validateDeptCodeUnique(null, resolvedCode);
|
||||||
}
|
}
|
||||||
createReqVO.setCode(resolvedCode);
|
createReqVO.setCode(resolvedCode);
|
||||||
|
}
|
||||||
|
|
||||||
// 插入部门
|
// 插入部门
|
||||||
DeptDO dept = BeanUtils.toBean(createReqVO, DeptDO.class);
|
DeptDO dept = BeanUtils.toBean(createReqVO, DeptDO.class);
|
||||||
@@ -110,9 +117,15 @@ public class DeptServiceImpl implements DeptService {
|
|||||||
// 校验部门名的唯一性
|
// 校验部门名的唯一性
|
||||||
validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
|
validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
|
||||||
// 如果上级发生变化,需要重新生成编码并同步子级
|
// 如果上级发生变化,需要重新生成编码并同步子级
|
||||||
|
boolean isIWorkSource = Objects.equals(originalDept.getDeptSource(), DeptSourceEnum.IWORK.getSource());
|
||||||
Long newParentId = normalizeParentId(updateReqVO.getParentId());
|
Long newParentId = normalizeParentId(updateReqVO.getParentId());
|
||||||
Long oldParentId = normalizeParentId(originalDept.getParentId());
|
Long oldParentId = normalizeParentId(originalDept.getParentId());
|
||||||
boolean parentChanged = !Objects.equals(newParentId, oldParentId);
|
boolean parentChanged = !Objects.equals(newParentId, oldParentId);
|
||||||
|
if (isIWorkSource) {
|
||||||
|
// iWork 来源直接使用提供的编码,不再生成
|
||||||
|
String providedCode = StrUtil.blankToDefault(updateReqVO.getCode(), null);
|
||||||
|
updateReqVO.setCode(providedCode);
|
||||||
|
} else {
|
||||||
if (parentChanged) {
|
if (parentChanged) {
|
||||||
String newCode;
|
String newCode;
|
||||||
if (Objects.equals(newParentId, DeptDO.PARENT_ID_ROOT)) {
|
if (Objects.equals(newParentId, DeptDO.PARENT_ID_ROOT)) {
|
||||||
@@ -134,6 +147,7 @@ public class DeptServiceImpl implements DeptService {
|
|||||||
updateReqVO.setCode(originalDept.getCode());
|
updateReqVO.setCode(originalDept.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 更新部门
|
// 更新部门
|
||||||
DeptDO updateObj = BeanUtils.toBean(updateReqVO, DeptDO.class);
|
DeptDO updateObj = BeanUtils.toBean(updateReqVO, DeptDO.class);
|
||||||
|
|||||||
@@ -16,10 +16,15 @@ public interface IWorkSyncService {
|
|||||||
IWorkFullSyncRespVO fullSync(IWorkFullSyncReqVO reqVO);
|
IWorkFullSyncRespVO fullSync(IWorkFullSyncReqVO reqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仅同步部门(会自动包含依赖的分部)
|
* 仅同步部门
|
||||||
*/
|
*/
|
||||||
IWorkFullSyncRespVO fullSyncDepartments(IWorkFullSyncReqVO reqVO);
|
IWorkFullSyncRespVO fullSyncDepartments(IWorkFullSyncReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅同步分部
|
||||||
|
*/
|
||||||
|
IWorkFullSyncRespVO fullSyncSubcompanies(IWorkFullSyncReqVO reqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仅同步岗位
|
* 仅同步岗位
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -28,14 +28,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -72,12 +65,12 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
|||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
IWorkHrSubcompanyPageRespVO.Subcompany sub = iterator.next();
|
IWorkHrSubcompanyPageRespVO.Subcompany sub = iterator.next();
|
||||||
if (shouldSkipByCanceled(sub.getCanceled(), options)) {
|
if (shouldSkipByCanceled(sub.getCanceled(), options)) {
|
||||||
logSkip("分部", sub.getSubcompanyid1(), "iWork 标记为失效且当前不同步失效记录");
|
logSkip("分部", sub.getId(), "iWork 标记为失效且当前不同步失效记录");
|
||||||
result.increaseSkipped();
|
result.increaseSkipped();
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Integer externalId = sub.getSubcompanyid1();
|
Integer externalId = sub.getId();
|
||||||
if (externalId == null) {
|
if (externalId == null) {
|
||||||
log.warn("[iWork] 分部缺少标识,跳过:{}", sub.getSubcompanyname());
|
log.warn("[iWork] 分部缺少标识,跳过:{}", sub.getSubcompanyname());
|
||||||
result.increaseFailed();
|
result.increaseFailed();
|
||||||
@@ -95,7 +88,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
|||||||
options);
|
options);
|
||||||
applyDeptOutcome(result, outcome, "分部", sub.getSubcompanyname());
|
applyDeptOutcome(result, outcome, "分部", sub.getSubcompanyname());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
log.error("[iWork] 同步分部失败: id={} name={}", sub.getSubcompanyid1(), sub.getSubcompanyname(), ex);
|
log.error("[iWork] 同步分部失败: id={} name={}", sub.getId(), sub.getSubcompanyname(), ex);
|
||||||
result.increaseFailed();
|
result.increaseFailed();
|
||||||
result.withMessage("同步分部失败: " + ex.getMessage());
|
result.withMessage("同步分部失败: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
@@ -108,7 +101,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
|||||||
}
|
}
|
||||||
if (!queue.isEmpty()) {
|
if (!queue.isEmpty()) {
|
||||||
for (IWorkHrSubcompanyPageRespVO.Subcompany remaining : queue) {
|
for (IWorkHrSubcompanyPageRespVO.Subcompany remaining : queue) {
|
||||||
log.warn("[iWork] 分部因父级缺失未同步: id={} name={}", remaining.getSubcompanyid1(), remaining.getSubcompanyname());
|
log.warn("[iWork] 分部因父级缺失未同步: id={} name={}", remaining.getId(), remaining.getSubcompanyname());
|
||||||
result.increaseFailed();
|
result.increaseFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +390,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
|||||||
DeptSaveReqVO req = new DeptSaveReqVO();
|
DeptSaveReqVO req = new DeptSaveReqVO();
|
||||||
req.setId(deptId);
|
req.setId(deptId);
|
||||||
req.setName(limitLength(StrUtil.blankToDefault(data.getSubcompanyname(), "未命名分部"), 30));
|
req.setName(limitLength(StrUtil.blankToDefault(data.getSubcompanyname(), "未命名分部"), 30));
|
||||||
req.setShortName(limitLength(data.getSubcompanyname(), 20));
|
// req.setShortName(limitLength(data.getSubcompanyname(), 20));
|
||||||
req.setCode(trimToNull(data.getSubcompanycode()));
|
req.setCode(trimToNull(data.getSubcompanycode()));
|
||||||
req.setParentId(parentId == null ? DeptDO.PARENT_ID_ROOT : parentId);
|
req.setParentId(parentId == null ? DeptDO.PARENT_ID_ROOT : parentId);
|
||||||
req.setSort(defaultSort(data.getShoworder()));
|
req.setSort(defaultSort(data.getShoworder()));
|
||||||
@@ -415,7 +408,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
|||||||
DeptSaveReqVO req = new DeptSaveReqVO();
|
DeptSaveReqVO req = new DeptSaveReqVO();
|
||||||
req.setId(deptId);
|
req.setId(deptId);
|
||||||
req.setName(limitLength(StrUtil.blankToDefault(data.getDepartmentname(), "未命名部门"), 30));
|
req.setName(limitLength(StrUtil.blankToDefault(data.getDepartmentname(), "未命名部门"), 30));
|
||||||
req.setShortName(limitLength(StrUtil.blankToDefault(data.getDepartmentmark(), data.getDepartmentname()), 20));
|
// req.setShortName(limitLength(StrUtil.blankToDefault(data.getDepartmentmark(), data.getDepartmentname()), 20));
|
||||||
req.setCode(trimToNull(data.getDepartmentcode()));
|
req.setCode(trimToNull(data.getDepartmentcode()));
|
||||||
req.setParentId(parentId == null ? DeptDO.PARENT_ID_ROOT : parentId);
|
req.setParentId(parentId == null ? DeptDO.PARENT_ID_ROOT : parentId);
|
||||||
req.setSort(defaultSort(data.getShoworder()));
|
req.setSort(defaultSort(data.getShoworder()));
|
||||||
@@ -472,8 +465,8 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ParentHolder resolveDepartmentParent(IWorkHrDepartmentPageRespVO.Department dept) {
|
private ParentHolder resolveDepartmentParent(IWorkHrDepartmentPageRespVO.Department dept) {
|
||||||
Long parentDeptId = toLong(dept.getParentdeptid());
|
Long parentDeptId = toLong(dept.getSupdepid());
|
||||||
if (parentDeptId != null) {
|
if (parentDeptId != null && parentDeptId > 0) {
|
||||||
return new ParentHolder(parentDeptId);
|
return new ParentHolder(parentDeptId);
|
||||||
}
|
}
|
||||||
Long subcompanyId = toLong(dept.getSubcompanyid1());
|
Long subcompanyId = toLong(dept.getSubcompanyid1());
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ public class IWorkSyncServiceImpl implements IWorkSyncService {
|
|||||||
return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.DEPARTMENT));
|
return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.DEPARTMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IWorkFullSyncRespVO fullSyncSubcompanies(IWorkFullSyncReqVO reqVO) {
|
||||||
|
return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.SUBCOMPANY));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IWorkFullSyncRespVO fullSyncJobTitles(IWorkFullSyncReqVO reqVO) {
|
public IWorkFullSyncRespVO fullSyncJobTitles(IWorkFullSyncReqVO reqVO) {
|
||||||
return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.JOB_TITLE));
|
return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.JOB_TITLE));
|
||||||
@@ -56,6 +61,7 @@ public class IWorkSyncServiceImpl implements IWorkSyncService {
|
|||||||
boolean syncUsers = scopes.contains(IWorkSyncEntityTypeEnum.USER);
|
boolean syncUsers = scopes.contains(IWorkSyncEntityTypeEnum.USER);
|
||||||
boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT);
|
boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT);
|
||||||
boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY);
|
boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY);
|
||||||
|
boolean syncJobTitle = scopes.contains(IWorkSyncEntityTypeEnum.JOB_TITLE);
|
||||||
int processedPages = 0;
|
int processedPages = 0;
|
||||||
IWorkSyncProcessor.SyncOptions options = buildFullSyncOptions(reqVO);
|
IWorkSyncProcessor.SyncOptions options = buildFullSyncOptions(reqVO);
|
||||||
if (syncSubcompanies) {
|
if (syncSubcompanies) {
|
||||||
@@ -64,7 +70,7 @@ public class IWorkSyncServiceImpl implements IWorkSyncService {
|
|||||||
if (syncDepartments) {
|
if (syncDepartments) {
|
||||||
processedPages += executeDepartmentFullSync(reqVO, options, respVO.getDepartmentStat(), batchStats);
|
processedPages += executeDepartmentFullSync(reqVO, options, respVO.getDepartmentStat(), batchStats);
|
||||||
}
|
}
|
||||||
if (scopes.contains(IWorkSyncEntityTypeEnum.JOB_TITLE)) {
|
if (syncJobTitle) {
|
||||||
processedPages += executeJobTitleFullSync(reqVO, options, respVO.getJobTitleStat(), batchStats);
|
processedPages += executeJobTitleFullSync(reqVO, options, respVO.getJobTitleStat(), batchStats);
|
||||||
}
|
}
|
||||||
if (syncUsers) {
|
if (syncUsers) {
|
||||||
|
|||||||
Reference in New Issue
Block a user