fix(aihr): honor hire date for daily drills

This commit is contained in:
2026-07-14 10:39:45 +08:00
parent 9810c9253c
commit 7e82d0c7eb
4 changed files with 48 additions and 1 deletions
@@ -1769,7 +1769,7 @@ public class AihrPracticeSeedService {
}
private void ensureDailyDrills(String extPartyId) {
if (isBlank(extPartyId) || countMobileRecords(extPartyId) >= 3) {
if (isBlank(extPartyId) || !dailyDrillEligible(extPartyId)) {
return;
}
int existingToday = count("""
@@ -1803,6 +1803,40 @@ public class AihrPracticeSeedService {
}
}
private boolean dailyDrillEligible(String extPartyId) {
if (orgSnapshotTableExists() && orgSnapshotColumnExists("hire_date")) {
return findHireDate(extPartyId)
.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;
}
private Optional<LocalDate> findHireDate(String extPartyId) {
List<LocalDate> hireDates = jdbcTemplate.query("""
SELECT hire_date
FROM aihr_org_snapshot
WHERE tenant_id = ? AND employment_status = 'active'
AND (ext_party_id = ? OR person_phone = ?)
AND hire_date IS NOT NULL
ORDER BY hire_date DESC
LIMIT 1
""", (rs, rowNum) -> {
java.sql.Date hireDate = rs.getDate("hire_date");
return hireDate == null ? null : hireDate.toLocalDate();
}, tenantId(), extPartyId, extPartyId);
return hireDates.stream().filter(java.util.Objects::nonNull).findFirst();
}
static boolean isWithinNewHireWindow(LocalDate hireDate, LocalDate asOf) {
if (hireDate == null || asOf == null || hireDate.isAfter(asOf)) {
return false;
}
return !hireDate.isBefore(asOf.minusMonths(3));
}
public PracticeAssignmentResponse createAssignment(PracticeAssignmentRequest request) {
String extPartyId = request == null ? "" : firstNonBlank(request.extPartyId(), "");
if (isBlank(extPartyId)) {
@@ -109,6 +109,17 @@ public class AihrPracticeSeedServiceTest {
assertEquals("缺少员工ID,无法派发专项训练", error.getMessage());
}
@Test
public void newHireWindowUsesInclusiveThreeMonthBoundary() {
LocalDate asOf = LocalDate.of(2026, 7, 14);
assertTrue(AihrPracticeSeedService.isWithinNewHireWindow(asOf, asOf));
assertTrue(AihrPracticeSeedService.isWithinNewHireWindow(asOf.minusMonths(3), asOf));
assertFalse(AihrPracticeSeedService.isWithinNewHireWindow(asOf.minusMonths(3).minusDays(1), asOf));
assertFalse(AihrPracticeSeedService.isWithinNewHireWindow(asOf.plusDays(1), asOf));
assertFalse(AihrPracticeSeedService.isWithinNewHireWindow(null, asOf));
}
@Test
public void mobilePracticeSessionRejectsForeignAndUnknownOwner() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);