diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java index 97637868..c8472f03 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java @@ -119,6 +119,24 @@ public class IWorkIntegrationController { return success(syncService.fullSync(reqVO)); } + @PostMapping("/hr/departments/full-sync") + @Operation(summary = "手动触发 iWork 部门全量同步") + public CommonResult fullSyncDepartments(@Valid @RequestBody IWorkFullSyncReqVO reqVO) { + return success(syncService.fullSyncDepartments(reqVO)); + } + + @PostMapping("/hr/job-titles/full-sync") + @Operation(summary = "手动触发 iWork 岗位全量同步") + public CommonResult fullSyncJobTitles(@Valid @RequestBody IWorkFullSyncReqVO reqVO) { + return success(syncService.fullSyncJobTitles(reqVO)); + } + + @PostMapping("/hr/users/full-sync") + @Operation(summary = "手动触发 iWork 人员全量同步") + public CommonResult fullSyncUsers(@Valid @RequestBody IWorkFullSyncReqVO reqVO) { + return success(syncService.fullSyncUsers(reqVO)); + } + @PostMapping("/hr/single-sync") @Operation(summary = "按 iWork ID 同步单条组织/人员") public CommonResult singleSync(@Valid @RequestBody IWorkSingleSyncReqVO reqVO) { diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/user/vo/user/UserSaveReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/user/vo/user/UserSaveReqVO.java index b902e3af..248f6ff3 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/user/vo/user/UserSaveReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/user/vo/user/UserSaveReqVO.java @@ -84,6 +84,10 @@ public class UserSaveReqVO { @Schema(description = "用户来源类型", example = "1") private Integer userSource; + @Schema(hidden = true) + @JsonIgnore + private boolean skipAssociationValidation; + // ========== 仅【创建】时,需要传递的字段 ========== @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java index 2c84ffa0..566ec028 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java @@ -15,6 +15,21 @@ public interface IWorkSyncService { */ IWorkFullSyncRespVO fullSync(IWorkFullSyncReqVO reqVO); + /** + * 仅同步部门(会自动包含依赖的分部) + */ + IWorkFullSyncRespVO fullSyncDepartments(IWorkFullSyncReqVO reqVO); + + /** + * 仅同步岗位 + */ + IWorkFullSyncRespVO fullSyncJobTitles(IWorkFullSyncReqVO reqVO); + + /** + * 仅同步人员(会自动包含依赖的分部、部门) + */ + IWorkFullSyncRespVO fullSyncUsers(IWorkFullSyncReqVO reqVO); + /** * 根据 iWork ID 进行单条同步 */ diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java index 31843b06..332a090d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java @@ -229,17 +229,16 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { } String username = resolveUsername(user); if (StrUtil.isBlank(username)) { - log.warn("[iWork] 人员缺少可用账号,跳过:id={} name={}", user.getId(), user.getLastname()); + log.warn("[iWork] 人员缺少可用账号(工号={}, 登录账号={}),跳过:id={} name={}", + user.getWorkcode(), user.getLoginid(), user.getId(), user.getLastname()); result.increaseFailed(); continue; } try { Long deptId = resolveUserDeptId(user); if (deptId == null) { - log.warn("[iWork] 人员未找到匹配部门,跳过:id={} name={} deptId={} subcompany={}", + log.warn("[iWork] 人员未找到匹配部门,继续同步:id={} name={} deptId={} subcompany={}", user.getId(), user.getLastname(), user.getDepartmentid(), user.getSubcompanyid1()); - result.increaseFailed(); - continue; } Long postId = resolveUserPostId(user); CommonStatusEnum status = inactive ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE; @@ -313,21 +312,26 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { return new JobSyncOutcome(SyncAction.SKIPPED, false, null); } PostSaveReqVO createReq = new PostSaveReqVO(); + Long desiredId = job.getJobtitleid() == null ? null : job.getJobtitleid().longValue(); + if (desiredId != null) { + createReq.setId(desiredId); + } createReq.setCode(code); createReq.setName(name); createReq.setSort(defaultSort(job.getShoworder())); createReq.setStatus(status); createReq.setRemark(StrUtil.blankToDefault(job.getJobfunction(), job.getDescription())); Long postId = postService.createPost(createReq); + Long effectivePostId = desiredId != null ? desiredId : postId; PostDO created = new PostDO(); - created.setId(postId); + created.setId(effectivePostId); created.setCode(code); created.setName(createReq.getName()); created.setSort(createReq.getSort()); created.setStatus(status); created.setRemark(createReq.getRemark()); postCache.put(buildPostCacheKey(code), created); - return new JobSyncOutcome(SyncAction.CREATED, disabled, postId); + return new JobSyncOutcome(SyncAction.CREATED, disabled, effectivePostId); } if (!options.isAllowUpdate()) { return new JobSyncOutcome(SyncAction.SKIPPED, false, existing.getId()); @@ -355,10 +359,15 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { Long postId, CommonStatusEnum status) { UserSaveReqVO req = buildUserSaveReq(source, username, deptId, postId, status); + Long desiredUserId = source.getId() == null ? null : source.getId().longValue(); + if (desiredUserId != null) { + req.setId(desiredUserId); + } req.setPassword(DEFAULT_USER_PASSWORD); req.setUserSource(UserSourceEnum.IWORK.getSource()); Long userId = adminUserService.createUser(req); - return new UserSyncOutcome(SyncAction.CREATED, CommonStatusEnum.isDisable(req.getStatus()), userId); + Long effectiveUserId = desiredUserId != null ? desiredUserId : userId; + return new UserSyncOutcome(SyncAction.CREATED, CommonStatusEnum.isDisable(req.getStatus()), effectiveUserId); } private UserSyncOutcome updateUser(AdminUserDO existing, @@ -419,7 +428,9 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { req.setUsername(username); req.setNickname(limitLength(StrUtil.blankToDefault(source.getLastname(), username), 30)); req.setRemark(buildUserRemark(source)); - req.setDeptIds(singletonSet(deptId)); + if (deptId != null) { + req.setDeptIds(singletonSet(deptId)); + } if (postId != null) { req.setPostIds(singletonSet(postId)); } @@ -427,6 +438,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { req.setMobile(trimToNull(source.getMobile())); req.setSex(resolveSex(source.getSex())); req.setStatus(status.getStatus()); + req.setSkipAssociationValidation(true); return req; } @@ -590,12 +602,9 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { } private String resolveUsername(IWorkHrUserPageRespVO.User user) { - String candidate = sanitizeUsername(user.getLoginid()); + String candidate = sanitizeUsername(user.getWorkcode()); if (candidate == null) { - candidate = sanitizeUsername(user.getWorkcode()); - } - if (candidate == null && user.getId() != null) { - candidate = sanitizeUsername("IWORK" + user.getId()); + candidate = sanitizeUsername(user.getLoginid()); } return candidate; } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java index 2ce9debf..073c2507 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java @@ -12,10 +12,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import static com.zt.plat.module.system.service.integration.iwork.IWorkIntegrationErrorCodeConstants.IWORK_ORG_REMOTE_FAILED; @@ -32,15 +29,33 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { @Override public IWorkFullSyncRespVO fullSync(IWorkFullSyncReqVO reqVO) { + return runFullSync(reqVO, reqVO.resolveScopes()); + } + + @Override + public IWorkFullSyncRespVO fullSyncDepartments(IWorkFullSyncReqVO reqVO) { + return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.DEPARTMENT)); + } + + @Override + public IWorkFullSyncRespVO fullSyncJobTitles(IWorkFullSyncReqVO reqVO) { + return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.JOB_TITLE)); + } + + @Override + public IWorkFullSyncRespVO fullSyncUsers(IWorkFullSyncReqVO reqVO) { + return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.USER)); + } + + private IWorkFullSyncRespVO runFullSync(IWorkFullSyncReqVO reqVO, Set scopes) { IWorkFullSyncRespVO respVO = new IWorkFullSyncRespVO(); respVO.setPageSize(reqVO.getPageSize()); List batchStats = new ArrayList<>(); respVO.setBatches(batchStats); - Set scopes = reqVO.resolveScopes(); boolean syncUsers = scopes.contains(IWorkSyncEntityTypeEnum.USER); - boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT) || syncUsers; - boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY) || syncDepartments; + boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT); + boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY); int processedPages = 0; IWorkSyncProcessor.SyncOptions options = buildFullSyncOptions(reqVO); if (syncSubcompanies) { diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java index c710d2a2..fc45afba 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java @@ -108,7 +108,8 @@ public class AdminUserServiceImpl implements AdminUserService { }); // 1.2 校验正确性 validateUserForCreateOrUpdate(null, createReqVO.getUsername(), - createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptIds(), createReqVO.getPostIds()); + createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptIds(), createReqVO.getPostIds(), + createReqVO.isSkipAssociationValidation()); // 2.1 插入用户 AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class); user.setStatus(CommonStatusEnum.ENABLE.getStatus()); @@ -154,7 +155,7 @@ public class AdminUserServiceImpl implements AdminUserService { } }); // 1.3 校验正确性 - validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null); + validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null, false); // 2. 插入用户 AdminUserDO user = BeanUtils.toBean(registerReqVO, AdminUserDO.class); @@ -173,7 +174,8 @@ public class AdminUserServiceImpl implements AdminUserService { updateReqVO.setPassword(null); // 特殊:此处不更新密码 // 1. 校验正确性 AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(), - updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptIds(), updateReqVO.getPostIds()); + updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptIds(), + updateReqVO.getPostIds(), updateReqVO.isSkipAssociationValidation()); // 2.1 只更新非空字段 AdminUserDO updateObj = new AdminUserDO(); @@ -512,7 +514,7 @@ public class AdminUserServiceImpl implements AdminUserService { } private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, - Set deptIds, Set postIds) { + Set deptIds, Set postIds, boolean skipAssociationValidation) { // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确 return DataPermissionUtils.executeIgnore(() -> { // 校验用户存在 @@ -524,7 +526,9 @@ public class AdminUserServiceImpl implements AdminUserService { // 校验邮箱唯一 validateEmailUnique(id, email); // 校验岗位处于开启状态 - postService.validatePostList(postIds); + if (!skipAssociationValidation) { + postService.validatePostList(postIds); + } return user; }); }