fix(aihr): scope org sync to tenant
This commit is contained in:
+13
-7
@@ -9,6 +9,7 @@ import org.dromara.aihr.domain.AihrOrgSyncDto.OrgProjectOption;
|
|||||||
import org.dromara.aihr.domain.AihrOrgSyncDto.OrgSnapshotResponse;
|
import org.dromara.aihr.domain.AihrOrgSyncDto.OrgSnapshotResponse;
|
||||||
import org.dromara.aihr.domain.AihrOrgSyncDto.SyncRequest;
|
import org.dromara.aihr.domain.AihrOrgSyncDto.SyncRequest;
|
||||||
import org.dromara.aihr.domain.AihrOrgSyncDto.SyncResponse;
|
import org.dromara.aihr.domain.AihrOrgSyncDto.SyncResponse;
|
||||||
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@@ -344,7 +345,7 @@ public class AihrOrgSyncService {
|
|||||||
private void saveRows(List<OrgRow> rows, boolean replaceExisting) {
|
private void saveRows(List<OrgRow> rows, boolean replaceExisting) {
|
||||||
transactionTemplate.executeWithoutResult(status -> {
|
transactionTemplate.executeWithoutResult(status -> {
|
||||||
if (replaceExisting) {
|
if (replaceExisting) {
|
||||||
jdbcTemplate.update("delete from aihr_org_snapshot where tenant_id = ?", TENANT_ID);
|
jdbcTemplate.update("delete from aihr_org_snapshot where tenant_id = ?", tenantId());
|
||||||
}
|
}
|
||||||
jdbcTemplate.batchUpdate("""
|
jdbcTemplate.batchUpdate("""
|
||||||
insert into aihr_org_snapshot
|
insert into aihr_org_snapshot
|
||||||
@@ -362,7 +363,7 @@ public class AihrOrgSyncService {
|
|||||||
employment_status = values(employment_status),
|
employment_status = values(employment_status),
|
||||||
snapshot_date = values(snapshot_date),
|
snapshot_date = values(snapshot_date),
|
||||||
create_time = now()
|
create_time = now()
|
||||||
""", rows.stream().map(OrgRow::args).toList());
|
""", rows.stream().map(row -> row.args(tenantId())).toList());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +438,7 @@ public class AihrOrgSyncService {
|
|||||||
|
|
||||||
private String orgSnapshotWhere(String keyword, String projectCode, String positionLevel, String status, List<Object> args) {
|
private String orgSnapshotWhere(String keyword, String projectCode, String positionLevel, String status, List<Object> args) {
|
||||||
StringBuilder where = new StringBuilder(" where tenant_id = ?");
|
StringBuilder where = new StringBuilder(" where tenant_id = ?");
|
||||||
args.add(TENANT_ID);
|
args.add(tenantId());
|
||||||
String keywordValue = clean(keyword);
|
String keywordValue = clean(keyword);
|
||||||
if (!keywordValue.isBlank()) {
|
if (!keywordValue.isBlank()) {
|
||||||
String like = "%" + keywordValue + "%";
|
String like = "%" + keywordValue + "%";
|
||||||
@@ -486,7 +487,7 @@ public class AihrOrgSyncService {
|
|||||||
""", (rs, rowNum) -> new OrgProjectOption(
|
""", (rs, rowNum) -> new OrgProjectOption(
|
||||||
rs.getString("project_code"),
|
rs.getString("project_code"),
|
||||||
rs.getString("project_name")
|
rs.getString("project_name")
|
||||||
), TENANT_ID);
|
), tenantId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> orgLevels() {
|
private List<String> orgLevels() {
|
||||||
@@ -496,7 +497,7 @@ public class AihrOrgSyncService {
|
|||||||
where tenant_id = ? and position_level is not null and position_level <> ''
|
where tenant_id = ? and position_level is not null and position_level <> ''
|
||||||
order by position_level
|
order by position_level
|
||||||
limit 20
|
limit 20
|
||||||
""", (rs, rowNum) -> rs.getString("position_level"), TENANT_ID);
|
""", (rs, rowNum) -> rs.getString("position_level"), tenantId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requireSnapshotTable() {
|
private void requireSnapshotTable() {
|
||||||
@@ -715,11 +716,16 @@ public class AihrOrgSyncService {
|
|||||||
String employmentStatus,
|
String employmentStatus,
|
||||||
LocalDate snapshotDate
|
LocalDate snapshotDate
|
||||||
) {
|
) {
|
||||||
Object[] args() {
|
Object[] args(String tenantId) {
|
||||||
return new Object[] {
|
return new Object[] {
|
||||||
TENANT_ID, projectCode, projectName, deptName, extPartyId, personPhone, personName,
|
tenantId, projectCode, projectName, deptName, extPartyId, personPhone, personName,
|
||||||
positionName, positionLevel, employmentStatus, snapshotDate
|
positionName, positionLevel, employmentStatus, snapshotDate
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String tenantId() {
|
||||||
|
String tenantId = LoginHelper.getTenantId();
|
||||||
|
return clean(tenantId).isBlank() ? TENANT_ID : tenantId.trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,4 +93,4 @@
|
|||||||
- 2026-07-14 候选人关联发布边界核对:生产根站点与 `/h5/` 返回 200,`wygj-aihr.service` active,线上后端仍为上一版 jar;远端管理端主 JS 未包含本批 `入职主体关联/candidate-links`,本批源码已提交但尚未发布。后续发布需按现有备份、静态资源同步、后端重启和浏览器回归流程执行。
|
- 2026-07-14 候选人关联发布边界核对:生产根站点与 `/h5/` 返回 200,`wygj-aihr.service` active,线上后端仍为上一版 jar;远端管理端主 JS 未包含本批 `入职主体关联/candidate-links`,本批源码已提交但尚未发布。后续发布需按现有备份、静态资源同步、后端重启和浏览器回归流程执行。
|
||||||
- 2026-07-14 门禁合同复核:`scripts/tests/demo-check-pilot-gates.test.sh` 通过,确认严格预检覆盖批次日期、唯一在职身份、1–2 个项目、每人至少 10 次训练、80% 完训、20 条校准、AI/人工分档一致率、SOP 可用率、满意度和音频/RAG schema;`scripts/tests/pilot-export-contract.test.mjs` 5/5 通过,AIHR 案例/对练定向测试 31/31 通过,`mobile-uni` 类型检查与 49 个单测通过。当前没有新增可安全实现的门禁缺口,剩余阻塞仍是正式组织映射、正式试点数据、视频样片和方言样本等外部输入。
|
- 2026-07-14 门禁合同复核:`scripts/tests/demo-check-pilot-gates.test.sh` 通过,确认严格预检覆盖批次日期、唯一在职身份、1–2 个项目、每人至少 10 次训练、80% 完训、20 条校准、AI/人工分档一致率、SOP 可用率、满意度和音频/RAG schema;`scripts/tests/pilot-export-contract.test.mjs` 5/5 通过,AIHR 案例/对练定向测试 31/31 通过,`mobile-uni` 类型检查与 49 个单测通过。当前没有新增可安全实现的门禁缺口,剩余阻塞仍是正式组织映射、正式试点数据、视频样片和方言样本等外部输入。
|
||||||
- 2026-07-14 租户边界复核:AI 面试结果、候选人入职主体关联、候选人补充资料、模型配置和案例记录的查询、写入、组织身份解析均改为使用当前登录租户;无登录上下文时仅保留本地开发默认租户 `000000` 回退。该修复已覆盖案例服务的列表、详情、项目范围、贡献者校验、保存和持久化回读路径,仍需在正式多租户环境做隔离回归。
|
- 2026-07-14 租户边界复核:AI 面试结果、候选人入职主体关联、候选人补充资料、模型配置和案例记录的查询、写入、组织身份解析均改为使用当前登录租户;无登录上下文时仅保留本地开发默认租户 `000000` 回退。该修复已覆盖案例服务的列表、详情、项目范围、贡献者校验、保存和持久化回读路径,仍需在正式多租户环境做隔离回归。
|
||||||
- 2026-07-14 仪表盘租户边界复核:管理端首页的面试、训练、知识库、案例、候选资料、组织和模型统计改为按当前登录租户查询;无登录上下文时保留本地开发默认租户回退。尚未把批量知识处理队列和完整 SOP 服务的全部租户调用统一替换,后续继续按数据敏感度分批审查。
|
- 2026-07-14 仪表盘租户边界复核:管理端首页的面试、训练、知识库、案例、候选资料、组织和模型统计改为按当前登录租户查询;组织同步写入和组织快照查询也改为当前登录租户;无登录上下文时保留本地开发默认租户回退。尚未把批量知识处理队列和完整 SOP 服务的全部租户调用统一替换,后续继续按数据敏感度分批审查。
|
||||||
|
|||||||
Reference in New Issue
Block a user