feat: complete phase 5 overseas fulfillment contracts

This commit is contained in:
2026-09-01 14:24:59 +08:00
parent ffed9bf898
commit 97168b19d8
46 changed files with 2446 additions and 409 deletions
@@ -20,6 +20,11 @@ class IamOpenApiContractTest {
assertThat(document).contains("/api/platform/v1/iam/authorization/permissions:")
.contains("/api/merchant/v1/iam/authorization/permissions:")
.contains("platform:overseas-warehouse:dispatch:transfer-delivery")
.contains("platform:overseas-warehouse:outbound:cancel")
.contains("merchant:warehouse:delivery:list")
.contains("merchant:warehouse:delivery:create")
.contains("列表权限包含详情只读")
.contains("PermissionCodesApiResponse:")
.contains("TenantPageApiResponse:")
.contains("TenantApiResponse:")
@@ -96,6 +96,10 @@ class OverseasPhase4PermissionSqlContractTest {
void servicePermissionConstantsExactlyMatchTheIamCatalog() throws Exception {
Set<String> moduleCatalog = codes(new ClassPathResource("db/lastleg-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8));
codes(new ClassPathResource("db/phase5-delivery-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8)).stream()
.filter(code -> code.startsWith("platform:"))
.forEach(moduleCatalog::add);
Set<String> serviceCatalog = new LinkedHashSet<>();
serviceCatalog.addAll(codes(repositoryFile(
"lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java")));
@@ -0,0 +1,123 @@
package com.baiyue.iam.repository;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
class Phase5DeliveryPermissionSqlContractTest {
private static final Pattern CODE = Pattern.compile("(?:platform:overseas-warehouse|merchant:warehouse):[a-z0-9:-]+");
private static final Set<String> REQUIRED = Set.of(
"platform:overseas-warehouse:dispatch:edit",
"platform:overseas-warehouse:dispatch:cancel",
"platform:overseas-warehouse:dispatch:transfer-delivery",
"platform:overseas-warehouse:outbound:list",
"platform:overseas-warehouse:outbound:create",
"platform:overseas-warehouse:outbound:cancel",
"platform:overseas-warehouse:delivery:list",
"merchant:warehouse:delivery:list",
"merchant:warehouse:delivery:create");
@Test
void definesOnlyTheFrozenPhase5DeliveryCatalogWithoutAliases() throws Exception {
String sql = sql();
assertThat(codes(sql)).containsExactlyInAnyOrderElementsOf(REQUIRED);
assertThat(codes(sql)).noneMatch(code -> code.endsWith(":view"));
assertThat(sql).contains(
"guard_phase5_delivery_permission_ids",
"权限ID或编码冲突",
"permission_type=VALUES(permission_type)",
"列表权限同时覆盖列表和详情只读");
}
@Test
void grantsAdministratorsAndWarehouseRolesByTheFrozenMinimumMatrix() throws Exception {
String sql = sql();
assertThat(sql).contains(
"UPPER(role.role_code) IN ('PLATFORM_ADMIN','PLATFORM_CUSTOM_ADMIN')",
"tmp_phase5_delivery_role_permission",
"('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:edit')",
"('WAREHOUSE_OPERATOR','platform:overseas-warehouse:outbound:create')",
"('WAREHOUSE_TALLY','platform:overseas-warehouse:outbound:list')",
"('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:list')",
"role.role_code IN ('OVERSEAS_WAREHOUSE_PDA_OPERATOR','CN_FIRSTLEG_PDA_OPERATOR')",
"PDA岗位错误获得后台权限");
assertThat(sql).doesNotContain(
"('WAREHOUSE_TALLY','platform:overseas-warehouse:dispatch:edit')",
"('WAREHOUSE_TALLY','platform:overseas-warehouse:outbound:create')",
"('OVERSEAS_WAREHOUSE_PDA_OPERATOR','platform:overseas-warehouse:",
"('CN_FIRSTLEG_PDA_OPERATOR','platform:overseas-warehouse:");
}
@Test
void grantsOnlyTheDefaultCustomerAdministratorAutomatically() throws Exception {
String sql = sql();
int marker = sql.indexOf("-- 客户默认管理员获得派送列表/详情只读及独立创建");
int assertion = sql.indexOf("DROP PROCEDURE IF EXISTS assert_phase5_delivery_permissions", marker);
assertThat(marker).isGreaterThanOrEqualTo(0);
assertThat(assertion).isGreaterThan(marker);
String grant = sql.substring(marker, assertion);
assertThat(grant).contains(
"role.role_code='MERCHANT_OWNER'",
"merchant:warehouse:delivery:list",
"merchant:warehouse:delivery:create");
assertThat(grant).doesNotContain("MERCHANT_OPERATOR", "ORDER_VIEWER", "role.role_code IN");
}
@Test
void domesticUnifiedEntryInlinesTheCompleteModuleSqlAfterPhase4Permissions() throws Exception {
String moduleSql = sql().trim();
String unifiedSql = repositoryFile("deploy/sql/头程数据库统一增量-MySQL8.sql");
int phase4 = unifiedSql.indexOf("-- 四期海外权限统一目录");
int phase5 = unifiedSql.indexOf("-- 五期海外排车、出库与派送权限(来源:iam/db/phase5-delivery-permissions.sql)");
int bodyStart = unifiedSql.indexOf("USE baiyue_iam;", phase5);
int nextSection = unifiedSql.indexOf("-- 海外智能排车草稿锁", bodyStart);
assertThat(phase4).isGreaterThanOrEqualTo(0);
assertThat(phase5).isGreaterThan(phase4);
assertThat(bodyStart).isGreaterThan(phase5);
assertThat(nextSection).isGreaterThan(bodyStart);
assertThat(unifiedSql.substring(bodyStart, nextSection).trim()).isEqualTo(moduleSql);
assertThat(codes(unifiedSql.substring(phase5, nextSection)))
.containsExactlyInAnyOrderElementsOf(REQUIRED);
}
@Test
void deploymentGuideUsesOnlyTheDomesticUnifiedEntry() throws Exception {
String readme = repositoryFile("deploy/sql/README.md");
assertThat(readme).contains(
"五期海外排车、出库与派送权限",
"测试和部署只执行固定入口,不再单独执行模块脚本",
"merchant:warehouse:delivery:list",
"merchant:warehouse:delivery:create",
"PDA 岗位不得获得上述后台权限");
}
private static String sql() throws Exception {
return new ClassPathResource("db/phase5-delivery-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
}
private static Set<String> codes(String source) {
Set<String> values = new LinkedHashSet<>();
CODE.matcher(source).results().map(result -> result.group()).forEach(values::add);
return values;
}
private static String repositoryFile(String relativePath) throws Exception {
Path path = Path.of(relativePath);
if (!Files.exists(path)) path = Path.of("..").resolve(relativePath);
return Files.readString(path, StandardCharsets.UTF_8);
}
}
@@ -74,6 +74,22 @@ class AuthorizationSnapshotServiceTest {
verify(mapper).findPermissions(42L, 0L, 9L, "PLATFORM");
}
@Test
void exposesPhase5DeliveryPermissionsFromCurrentRoleAssignments() {
when(mapper.countActiveIdentity(42L, 7L, 9L)).thenReturn(1);
when(mapper.findRoles(42L, 7L, 9L, "MERCHANT")).thenReturn(List.of("MERCHANT_OWNER"));
when(mapper.findPermissions(42L, 7L, 9L, "MERCHANT")).thenReturn(List.of(
"merchant:warehouse:delivery:list",
"merchant:warehouse:delivery:create"));
var result = service.currentPermissions(new AuthenticatedUser(42L, 7L, 7L, 9L,
"owner", "MERCHANT", "MERCHANT", java.util.Set.of()), "MERCHANT");
assertThat(result).containsExactlyInAnyOrder(
"merchant:warehouse:delivery:create",
"merchant:warehouse:delivery:list");
}
@Test
void rejectsIncompleteCurrentIdentityAsBusinessError() {
assertThatThrownBy(() -> service