fix(aihr): honor hire date for daily drills
This commit is contained in:
+35
-1
@@ -1769,7 +1769,7 @@ public class AihrPracticeSeedService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ensureDailyDrills(String extPartyId) {
|
private void ensureDailyDrills(String extPartyId) {
|
||||||
if (isBlank(extPartyId) || countMobileRecords(extPartyId) >= 3) {
|
if (isBlank(extPartyId) || !dailyDrillEligible(extPartyId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int existingToday = count("""
|
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) {
|
public PracticeAssignmentResponse createAssignment(PracticeAssignmentRequest request) {
|
||||||
String extPartyId = request == null ? "" : firstNonBlank(request.extPartyId(), "");
|
String extPartyId = request == null ? "" : firstNonBlank(request.extPartyId(), "");
|
||||||
if (isBlank(extPartyId)) {
|
if (isBlank(extPartyId)) {
|
||||||
|
|||||||
+11
@@ -109,6 +109,17 @@ public class AihrPracticeSeedServiceTest {
|
|||||||
assertEquals("缺少员工ID,无法派发专项训练", error.getMessage());
|
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
|
@Test
|
||||||
public void mobilePracticeSessionRejectsForeignAndUnknownOwner() {
|
public void mobilePracticeSessionRejectsForeignAndUnknownOwner() {
|
||||||
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
||||||
|
|||||||
@@ -174,3 +174,4 @@
|
|||||||
- 2026-07-14 BRD 4.4 每日三题口径复核:当前 `ensureDailyDrills` 以“移动端训练记录少于 3 次”作为新员工近似条件;`aihr_org_snapshot` 只有快照日期,没有入职/任职起始日期,因此不能证明“入职 3 个月内”,也不能用账号创建时间替代。当前保留该近似仅用于 Demo;正式试点需由组织同步提供并确认 `hire_date/entry_date` 字段后,再把每日派题资格改为真实任职日期判断。
|
- 2026-07-14 BRD 4.4 每日三题口径复核:当前 `ensureDailyDrills` 以“移动端训练记录少于 3 次”作为新员工近似条件;`aihr_org_snapshot` 只有快照日期,没有入职/任职起始日期,因此不能证明“入职 3 个月内”,也不能用账号创建时间替代。当前保留该近似仅用于 Demo;正式试点需由组织同步提供并确认 `hire_date/entry_date` 字段后,再把每日派题资格改为真实任职日期判断。
|
||||||
- 2026-07-14 BRD G3 移动首页权限复核:发现公开首页方法对已登录 SYS 用户仍可能调用全局统计分支;现要求只有 APP 用户且身份非空才读取员工/主管动态数据,后台系统用户和异常身份统一返回无业务统计的公开 seed。AIHR 全量测试 `70/70` 通过,未修改生产环境。
|
- 2026-07-14 BRD G3 移动首页权限复核:发现公开首页方法对已登录 SYS 用户仍可能调用全局统计分支;现要求只有 APP 用户且身份非空才读取员工/主管动态数据,后台系统用户和异常身份统一返回无业务统计的公开 seed。AIHR 全量测试 `70/70` 通过,未修改生产环境。
|
||||||
- 2026-07-14 BRD G3 音频读取权限复核:发现移动端音频下载接口对已登录 SYS 用户未校验角色,普通后台账号理论上可枚举 `ossId` 读取训练录音;现复用 `superadmin/hr_operator` 门禁,APP 用户继续按本人/主管项目范围校验,其他身份返回 403。AIHR 全量测试 `70/70` 通过,未修改生产环境。
|
- 2026-07-14 BRD G3 音频读取权限复核:发现移动端音频下载接口对已登录 SYS 用户未校验角色,普通后台账号理论上可枚举 `ossId` 读取训练录音;现复用 `superadmin/hr_operator` 门禁,APP 用户继续按本人/主管项目范围校验,其他身份返回 403。AIHR 全量测试 `70/70` 通过,未修改生产环境。
|
||||||
|
- 2026-07-14 BRD 4.4 每日三题资格补强:每日派题现在在组织快照存在 `hire_date` 列时按“入职日期至今不超过 3 个月”判断,边界按自然月且包含当天;旧 Demo 快照没有该列时继续使用“移动端训练记录少于 3 次”的兼容回退。正式试点仍需在外部组织同步落地并校验 `hire_date`,不能把回退口径当成正式新员工资格。
|
||||||
|
|||||||
@@ -470,6 +470,7 @@ contains mobile-uni/src/pages/supervisor/review/index.vue "人工贡献分"
|
|||||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "/practice/reviews/{id}/reviewed"
|
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "/practice/reviews/{id}/reviewed"
|
||||||
contains mobile-uni/src/pages/supervisor/review/index.vue "标记已复盘"
|
contains mobile-uni/src/pages/supervisor/review/index.vue "标记已复盘"
|
||||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "source = 'retry'"
|
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "source = 'retry'"
|
||||||
|
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "isWithinNewHireWindow"
|
||||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java "instr(coalesce(person_name, '')"
|
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java "instr(coalesce(person_name, '')"
|
||||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "maskSensitiveText"
|
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "maskSensitiveText"
|
||||||
contains mobile-uni/src/services/practice.ts "/api/aihr/mobile/practice/assignments"
|
contains mobile-uni/src/services/practice.ts "/api/aihr/mobile/practice/assignments"
|
||||||
|
|||||||
Reference in New Issue
Block a user