fix(aihr): tighten org and daily drill gates
This commit is contained in:
+9
-10
@@ -110,7 +110,7 @@ public class AihrOrgSyncService {
|
||||
}
|
||||
}
|
||||
int phoneLinked = (int) rows.stream().filter(row -> !row.personPhone().isBlank()).count();
|
||||
int suspectText = (int) rows.stream().filter(AihrOrgSyncService::hasSuspectText).count();
|
||||
int suspectText = (int) rows.stream().filter(OrgRow::suspectText).count();
|
||||
int duplicatePartyIds = countDuplicatePartyIds(rows.stream().map(OrgRow::extPartyId).toList());
|
||||
if (!rows.isEmpty() && phoneLinked < rows.size()) {
|
||||
warnings.add("外部员工快照手机号覆盖 " + phoneLinked + "/" + rows.size() + ",移动端正式登录仅可映射已带手机号人员");
|
||||
@@ -397,6 +397,10 @@ public class AihrOrgSyncService {
|
||||
String positionName = firstNonBlank(text(employee, "position_name", "positionName", "job_title", "jobTitle",
|
||||
"post_name", "postName", "job_name", "jobName", "role_name", "roleName", "position", "title"), "员工");
|
||||
String positionLevel = firstNonBlank(text(employee, "position_level", "positionLevel", "job_level", "jobLevel"), level(positionName));
|
||||
boolean suspectText = hasQuestionMark(projectName)
|
||||
|| hasQuestionMark(deptName)
|
||||
|| hasQuestionMark(personName)
|
||||
|| hasQuestionMark(positionName);
|
||||
return new OrgRow(
|
||||
projectCode,
|
||||
projectName,
|
||||
@@ -407,7 +411,8 @@ public class AihrOrgSyncService {
|
||||
positionName,
|
||||
positionLevel(positionLevel, positionName),
|
||||
status(text(employee, "status", "employment_status", "employmentStatus")),
|
||||
LocalDate.now()
|
||||
LocalDate.now(),
|
||||
suspectText
|
||||
);
|
||||
}
|
||||
|
||||
@@ -614,13 +619,6 @@ public class AihrOrgSyncService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasSuspectText(OrgRow row) {
|
||||
return hasQuestionMark(row.projectName())
|
||||
|| hasQuestionMark(row.deptName())
|
||||
|| hasQuestionMark(row.personName())
|
||||
|| hasQuestionMark(row.positionName());
|
||||
}
|
||||
|
||||
private static boolean hasQuestionMark(String value) {
|
||||
return clean(value).contains("?");
|
||||
}
|
||||
@@ -728,7 +726,8 @@ public class AihrOrgSyncService {
|
||||
String positionName,
|
||||
String positionLevel,
|
||||
String employmentStatus,
|
||||
LocalDate snapshotDate
|
||||
LocalDate snapshotDate,
|
||||
boolean suspectText
|
||||
) {
|
||||
Object[] args(String tenantId) {
|
||||
return new Object[] {
|
||||
|
||||
+11
-3
@@ -48,6 +48,7 @@ import org.dromara.aihr.service.AihrPracticeLlmService.PracticeTurn;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -214,6 +215,8 @@ public class AihrPracticeSeedService {
|
||||
private final AihrPracticeLlmService practiceLlmService;
|
||||
private final AihrSopSeedService sopSeedService;
|
||||
private final TransactionTemplate pilotExportTransaction;
|
||||
@Value("${aihr.practice.allow-legacy-daily-drill-fallback:${AIHR_PRACTICE_ALLOW_LEGACY_DAILY_DRILL_FALLBACK:false}}")
|
||||
private boolean allowLegacyDailyDrillFallback;
|
||||
private volatile boolean practiceTableReady;
|
||||
private volatile boolean assignmentTableReady;
|
||||
private volatile boolean scenarioTableReady;
|
||||
@@ -1841,9 +1844,14 @@ public class AihrPracticeSeedService {
|
||||
.map(hireDate -> isWithinNewHireWindow(hireDate, LocalDate.now()))
|
||||
.orElse(false);
|
||||
}
|
||||
// The legacy Demo snapshot has no hire_date. Keep its deterministic fallback
|
||||
// until the external organization sync supplies the formal field.
|
||||
return countMobileRecords(extPartyId) < 3;
|
||||
// Formal production data must provide hire_date. The record-count fallback is
|
||||
// intentionally opt-in for the local Demo only; it must not infer employment
|
||||
// tenure from training activity in a pilot or production tenant.
|
||||
return isLegacyDailyDrillEligible(allowLegacyDailyDrillFallback, extPartyId, countMobileRecords(extPartyId));
|
||||
}
|
||||
|
||||
static boolean isLegacyDailyDrillEligible(boolean allowFallback, String extPartyId, int mobileRecordCount) {
|
||||
return allowFallback && extPartyId != null && !extPartyId.isBlank() && mobileRecordCount < 3;
|
||||
}
|
||||
|
||||
private Optional<LocalDate> findHireDate(String extPartyId) {
|
||||
|
||||
+16
@@ -76,6 +76,22 @@ public class AihrOrgSyncServiceTest {
|
||||
assertEquals("项目管理", ReflectionTestUtils.getField(demo, "deptName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suspectTextIsCheckedBeforeDisplayFieldsAreMasked() throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
AihrOrgSyncService service = new AihrOrgSyncService(new ObjectMapper(), mock(JdbcTemplate.class), mock(TransactionTemplate.class));
|
||||
var employee = mapper.readTree("""
|
||||
{"id":"EMP-1","name":"测试?员工","department_name":"项目?管理","project_name":"翡翠湾","position_name":"主管","phone":"13900001111"}
|
||||
""");
|
||||
|
||||
ReflectionTestUtils.setField(service, "storeDisplayFields", false);
|
||||
Object masked = ReflectionTestUtils.invokeMethod(service, "orgRow", employee, Map.of(), Map.of());
|
||||
|
||||
assertEquals("", ReflectionTestUtils.getField(masked, "personName"));
|
||||
assertEquals("", ReflectionTestUtils.getField(masked, "deptName"));
|
||||
assertEquals(true, ReflectionTestUtils.getField(masked, "suspectText"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void snapshotSuspectTextQuerySearchesLiteralQuestionMarks() {
|
||||
SnapshotJdbcTemplate jdbcTemplate = new SnapshotJdbcTemplate();
|
||||
|
||||
+8
@@ -120,6 +120,14 @@ public class AihrPracticeSeedServiceTest {
|
||||
assertFalse(AihrPracticeSeedService.isWithinNewHireWindow(null, asOf));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void legacyDailyDrillFallbackOnlyUsesTrainingCountAfterExplicitOptIn() {
|
||||
assertTrue(AihrPracticeSeedService.isLegacyDailyDrillEligible(true, "EMP-1", 0));
|
||||
assertFalse(AihrPracticeSeedService.isLegacyDailyDrillEligible(false, "EMP-1", 0));
|
||||
assertFalse(AihrPracticeSeedService.isLegacyDailyDrillEligible(true, "EMP-1", 3));
|
||||
assertFalse(AihrPracticeSeedService.isLegacyDailyDrillEligible(true, "", 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dailyDrillAnswerDoesNotOverwriteCompletedAttempt() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java"));
|
||||
|
||||
Reference in New Issue
Block a user