From 1fe91cc0f39b41b1992905b2679611a9eb2b98f0 Mon Sep 17 00:00:00 2001 From: let5sne Date: Thu, 16 Jul 2026 14:27:00 +0800 Subject: [PATCH] fix(aihr): adapt updated organization snapshot --- .../aihr/service/AihrOrgSyncService.java | 11 +++-- .../aihr/service/AihrOrgSyncServiceTest.java | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java index e06b95a6..eb510a2c 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java @@ -375,7 +375,7 @@ public class AihrOrgSyncService { project_code = values(project_code), project_name = values(project_name), dept_name = values(dept_name), - person_phone = values(person_phone), + person_phone = coalesce(nullif(values(person_phone), ''), person_phone), person_name = values(person_name), position_name = values(position_name), position_level = values(position_level), @@ -389,7 +389,7 @@ public class AihrOrgSyncService { private OrgRow orgRow(JsonNode employee, Map companies, Map departments, Map positionMappings) { - String extPartyId = firstNonBlank(text(employee, "employee_number", "employeeNo", "employee_id", "employeeId", "id", "user_id")); + String extPartyId = firstNonBlank(text(employee, "id", "employee_id", "employeeId", "employee_number", "employeeNo", "user_id")); if (extPartyId.isBlank()) { return null; } @@ -617,10 +617,13 @@ public class AihrOrgSyncService { private static String positionLevel(String rawLevel, String positionName) { String inferred = level(positionName); String level = clean(rawLevel); - if (level.isBlank() || (("一线".equals(level) || "员工".equals(level)) && !"一线".equals(inferred))) { + if (!POSITION_LEVELS.contains(level) && !"员工".equals(level)) { return inferred; } - return level; + if (("一线".equals(level) || "员工".equals(level)) && !"一线".equals(inferred)) { + return inferred; + } + return "员工".equals(level) ? "一线" : level; } private Map positionMappings() { diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrOrgSyncServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrOrgSyncServiceTest.java index e999330f..1094dc4e 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrOrgSyncServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrOrgSyncServiceTest.java @@ -16,13 +16,19 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.argThat; @Tag("dev") public class AihrOrgSyncServiceTest { @@ -135,6 +141,42 @@ public class AihrOrgSyncServiceTest { assertEquals("一线", ReflectionTestUtils.getField(noImplicitPromotion, "positionLevel")); } + @Test + public void updatedEmployeeSchemaKeepsResourceIdAndInfersNumericPositionLevel() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + AihrOrgSyncService service = new AihrOrgSyncService(mapper, mock(JdbcTemplate.class), mock(TransactionTemplate.class)); + + Object row = ReflectionTestUtils.invokeMethod(service, "orgRow", + mapper.readTree("{\"id\":\"employee-1\",\"employee_number\":\"NO-1001\"," + + "\"position_name\":\"客服主管\",\"position_level\":3}"), + Map.of(), Map.of(), Map.of()); + + assertEquals("employee-1", ReflectionTestUtils.getField(row, "extPartyId")); + assertEquals("主管", ReflectionTestUtils.getField(row, "positionLevel")); + } + + @Test + public void incrementalSyncDoesNotEraseExistingPhoneWhenUpstreamPhoneIsMasked() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class); + TransactionTemplate transactionTemplate = mock(TransactionTemplate.class); + doAnswer(invocation -> { + @SuppressWarnings("unchecked") + Consumer callback = invocation.getArgument(0); + callback.accept(mock(org.springframework.transaction.TransactionStatus.class)); + return null; + }).when(transactionTemplate).executeWithoutResult(any()); + AihrOrgSyncService service = new AihrOrgSyncService(mapper, jdbcTemplate, transactionTemplate); + Object row = ReflectionTestUtils.invokeMethod(service, "orgRow", + mapper.readTree("{\"id\":\"employee-1\",\"phone\":\"139****1111\"}"), + Map.of(), Map.of(), Map.of()); + + ReflectionTestUtils.invokeMethod(service, "saveRows", List.of(row), false); + + verify(jdbcTemplate).batchUpdate(argThat(sql -> + sql.contains("person_phone = coalesce(nullif(values(person_phone), ''), person_phone)")), anyList()); + } + @Test public void positionMapRejectsPrivilegeLevelsOutsideTheContract() { AihrOrgSyncService service = new AihrOrgSyncService(new ObjectMapper(), mock(JdbcTemplate.class), mock(TransactionTemplate.class));