feat: gate overseas receiving and harden phase4 workflows

This commit is contained in:
2026-08-25 10:31:04 +08:00
parent cb78bc6b41
commit 52b9fc382f
93 changed files with 2779 additions and 201 deletions
@@ -60,6 +60,35 @@ class OverseasPhase4PermissionSqlContractTest {
assertCustomAdminGrant(sql);
}
@Test
void warehouseRolesReceiveOnlyTheTenPhase4ListPermissionsAndPickerRemainsPdaOnly() throws Exception {
String moduleSql = new ClassPathResource("db/lastleg-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
Path path = Path.of("deploy/sql/头程数据库统一增量-MySQL8.sql");
if (!Files.exists(path)) path = Path.of("../deploy/sql/头程数据库统一增量-MySQL8.sql");
String unifiedSql = Files.readString(path, StandardCharsets.UTF_8);
for (String sql : List.of(moduleSql, unifiedSql)) {
String matrix = matrixBlock(sql);
assertThat(matrix).contains("WAREHOUSE_OPERATOR", "WAREHOUSE_TALLY");
assertThat(codes(matrix)).containsExactlyInAnyOrder(
"platform:overseas-warehouse:last-mile-order:list",
"platform:overseas-warehouse:inbound-order:list",
"platform:overseas-warehouse:relabel-order:list",
"platform:overseas-warehouse:inventory:list",
"platform:overseas-warehouse:warehouse:list",
"platform:overseas-warehouse:location:list",
"platform:overseas-warehouse:pallet:list",
"platform:overseas-business:purchase:list",
"platform:overseas-business:truck:list",
"platform:overseas-business:looseboard:list");
assertThat(matrix).doesNotContain("WAREHOUSE_PICKER");
assertThat(matrix).doesNotContain(":create'", ":edit'", ":status'", ":export'", ":adjust'");
assertThat(sql).contains("assert_phase4_warehouse_role_minimum", "<> 20",
"role.role_code IN ('WAREHOUSE_OPERATOR','WAREHOUSE_PICKER','WAREHOUSE_TALLY')");
}
}
@Test
void servicePermissionConstantsExactlyMatchTheIamCatalog() throws Exception {
Set<String> moduleCatalog = codes(new ClassPathResource("db/lastleg-permissions.sql")
@@ -109,6 +138,14 @@ class OverseasPhase4PermissionSqlContractTest {
assertThat(sql.substring(grantStart, grantEnd)).contains("lastleg:pda:operate");
}
private static String matrixBlock(String sql) {
int start = sql.indexOf("INSERT INTO tmp_phase4_warehouse_role_permission");
int end = sql.indexOf("DELETE grant_row FROM", start);
assertThat(start).isGreaterThanOrEqualTo(0);
assertThat(end).isGreaterThan(start);
return sql.substring(start, end);
}
private static String repositoryFile(String relativePath) throws Exception {
Path path = Path.of(relativePath);
if (!Files.exists(path)) path = Path.of("..").resolve(relativePath);
@@ -135,6 +135,34 @@ class PlatformUserManagementServiceTest {
verify(auth).revokeSessions(eq("internal-token"), any());
}
@Test
void changingWarehouseBindingRevokesAllAuthSessionsSoAccountVersionIsBumped() {
platformRole.setRoleCode("WAREHOUSE_PICKER");
membership.setOverseasWarehouseId(900L);
UpdateUserRequest changed = new UpdateUserRequest("张伟", "13800138000", null,
0L, List.of(40001L), 901L);
UserResponse response = service.update(30L, changed, Set.of("platform:user:grant-role"));
assertEquals(901L, response.overseasWarehouseId());
verify(auth).revokeSessions(eq("internal-token"),
eq(new AuthAccountClient.RevokeAccountSessionsRequest(Set.of(10L))));
}
@Test
void clearingWarehouseBindingAlsoRevokesAllAuthSessions() {
platformRole.setRoleCode("WAREHOUSE_OPERATOR");
membership.setOverseasWarehouseId(900L);
UpdateUserRequest cleared = new UpdateUserRequest("张伟", "13800138000", null,
0L, List.of(40001L), null);
UserResponse response = service.update(30L, cleared, Set.of("platform:user:grant-role"));
assertNull(response.overseasWarehouseId());
verify(auth).revokeSessions(eq("internal-token"),
eq(new AuthAccountClient.RevokeAccountSessionsRequest(Set.of(10L))));
}
@Test
void currentPlatformOperatorCannotDisableSelf() {
assertThrows(BizException.class,