fix(aihr): guard partial organization snapshot replace
This commit is contained in:
+2
-1
@@ -14,7 +14,8 @@ public final class AihrOrgSyncDto {
|
||||
Integer maxPages,
|
||||
String groupId,
|
||||
String companyId,
|
||||
String departmentId
|
||||
String departmentId,
|
||||
Boolean allowPartialReplace
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
+15
-1
@@ -66,7 +66,7 @@ public class AihrOrgSyncService {
|
||||
private String configuredSigningSecret;
|
||||
|
||||
public SyncResponse sync(SyncRequest request) {
|
||||
SyncRequest req = request == null ? new SyncRequest(null, null, null, null, null, null, null) : request;
|
||||
SyncRequest req = request == null ? new SyncRequest(null, null, null, null, null, null, null, null) : request;
|
||||
String baseUrl = normalizeBaseUrl(configuredBaseUrl);
|
||||
if (baseUrl.isBlank()) {
|
||||
throw new IllegalArgumentException("请先配置 AIHR_ORG_SYNC_BASE_URL,值为外部开放平台 /api/open/v1 前缀");
|
||||
@@ -79,6 +79,7 @@ public class AihrOrgSyncService {
|
||||
requireSnapshotTable();
|
||||
}
|
||||
boolean replaceExisting = req.replaceExisting() == null || Boolean.TRUE.equals(req.replaceExisting());
|
||||
boolean allowPartialReplace = Boolean.TRUE.equals(req.allowPartialReplace());
|
||||
String token = accessToken(baseUrl);
|
||||
List<String> warnings = new ArrayList<>();
|
||||
|
||||
@@ -116,6 +117,10 @@ public class AihrOrgSyncService {
|
||||
if (!dryRun && replaceExisting && rows.isEmpty()) {
|
||||
throw new IllegalArgumentException("外部员工快照为空,已阻止覆盖本地组织人员快照");
|
||||
}
|
||||
if (!dryRun && replaceExisting && !allowPartialReplace
|
||||
&& hasUnsafeReplaceData(employeeItems.size(), rows.size(), skipped, phoneLinked, maskedPhone, suspectText)) {
|
||||
throw new IllegalArgumentException("外部员工快照存在不完整或疑似异常数据,已阻止覆盖本地组织人员快照;请先 dry-run,确认后显式传 allowPartialReplace=true");
|
||||
}
|
||||
if (!dryRun && !rows.isEmpty()) {
|
||||
saveRows(rows, replaceExisting);
|
||||
}
|
||||
@@ -136,6 +141,15 @@ public class AihrOrgSyncService {
|
||||
);
|
||||
}
|
||||
|
||||
static boolean hasUnsafeReplaceData(int employeeCount, int rowCount, int skipped,
|
||||
int phoneLinked, int maskedPhone, int suspectText) {
|
||||
return employeeCount != rowCount
|
||||
|| skipped > 0
|
||||
|| phoneLinked < rowCount
|
||||
|| maskedPhone > 0
|
||||
|| suspectText > 0;
|
||||
}
|
||||
|
||||
public OrgSnapshotResponse snapshot(String keyword, String projectCode, String positionLevel, String status,
|
||||
Integer pageNum, Integer pageSize, Integer limit) {
|
||||
requireSnapshotTable();
|
||||
|
||||
+10
-2
@@ -29,6 +29,14 @@ public class AihrOrgSyncServiceTest {
|
||||
assertEquals("", AihrOrgSyncService.normalizeMobilePhone("025-88888888"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partialOrSuspiciousSnapshotMustNotReplaceExistingDataByDefault() {
|
||||
assertTrue(AihrOrgSyncService.hasUnsafeReplaceData(22, 20, 2, 20, 1, 0));
|
||||
assertTrue(AihrOrgSyncService.hasUnsafeReplaceData(22, 22, 0, 21, 0, 0));
|
||||
assertTrue(AihrOrgSyncService.hasUnsafeReplaceData(22, 22, 0, 22, 0, 1));
|
||||
assertFalse(AihrOrgSyncService.hasUnsafeReplaceData(22, 22, 0, 22, 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unusablePhoneCandidateDetectsMaskedPhone() throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
@@ -50,7 +58,7 @@ public class AihrOrgSyncServiceTest {
|
||||
ReflectionTestUtils.setField(service, "configuredSigningSecret", "");
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> service.sync(
|
||||
new SyncRequest(true, true, 1, 1, null, null, null)
|
||||
new SyncRequest(true, true, 1, 1, null, null, null, null)
|
||||
));
|
||||
verifyNoInteractions(jdbcTemplate, transactionTemplate);
|
||||
}
|
||||
@@ -83,7 +91,7 @@ public class AihrOrgSyncServiceTest {
|
||||
ReflectionTestUtils.setField(service, "configuredClientSecret", "");
|
||||
ReflectionTestUtils.setField(service, "configuredSigningSecret", "");
|
||||
|
||||
var response = service.sync(new SyncRequest(true, true, 1, 1, null, null, null));
|
||||
var response = service.sync(new SyncRequest(true, true, 1, 1, null, null, null, null));
|
||||
|
||||
assertTrue(response.dryRun());
|
||||
assertEquals(1, response.employeeCount());
|
||||
|
||||
Reference in New Issue
Block a user