feat: complete overseas customer and PDA workflows
This commit is contained in:
@@ -36,6 +36,12 @@ class IamOpenApiContractTest {
|
||||
.contains("platform:overseas-warehouse:outbound:cancel")
|
||||
.contains("merchant:warehouse:delivery:list")
|
||||
.contains("merchant:warehouse:delivery:create")
|
||||
.contains("merchant:cross-border:procurement")
|
||||
.contains("merchant:cross-border:domestic-trucking")
|
||||
.contains("merchant:cross-border:pallet-shipping")
|
||||
.contains("merchant:warehouse:inbound:list")
|
||||
.contains("lastleg:pda:operate")
|
||||
.contains("OVERSEAS_WAREHOUSE_PDA_OPERATOR")
|
||||
.contains("列表权限包含详情只读")
|
||||
.contains("PermissionCodesApiResponse:")
|
||||
.contains("TenantPageApiResponse:")
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
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 OverseasCustomerPermissionSqlContractTest {
|
||||
private static final Pattern MERCHANT_CODE = Pattern.compile("merchant:[a-z0-9:-]+");
|
||||
private static final Set<String> CUSTOMER_OVERSEAS_PERMISSIONS = Set.of(
|
||||
"merchant:cross-border:procurement",
|
||||
"merchant:cross-border:domestic-trucking",
|
||||
"merchant:cross-border:pallet-shipping",
|
||||
"merchant:warehouse:inbound:list");
|
||||
|
||||
@Test
|
||||
void declaresTheFrozenCustomerOverseasPermissionCatalog() throws Exception {
|
||||
String sql = sql();
|
||||
|
||||
assertThat(merchantCodes(sql)).containsExactlyInAnyOrderElementsOf(CUSTOMER_OVERSEAS_PERMISSIONS);
|
||||
for (String permission : CUSTOMER_OVERSEAS_PERMISSIONS) {
|
||||
assertThat(sql).contains("0,'MERCHANT','MENU'", "'" + permission + "'");
|
||||
}
|
||||
assertThat(sql).contains(
|
||||
"'merchant:cross-border:procurement','海外采购','/cross-border/procurement'",
|
||||
"'merchant:cross-border:domestic-trucking','美国本土卡','/cross-border/domestic-trucking'",
|
||||
"'merchant:cross-border:pallet-shipping','美本土散板','/cross-border/pallet-shipping'",
|
||||
"'merchant:warehouse:inbound:list','海外仓入库订单','/orders/inbound'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void grantsAllFourPermissionsOnlyToTheDefaultCustomerAdministrator() throws Exception {
|
||||
String sql = sql();
|
||||
int comment = sql.indexOf("-- 客户默认管理员获得当前客户海外业务入口");
|
||||
int grantStart = sql.indexOf("INSERT IGNORE INTO iam_role_permission", comment);
|
||||
int grantEnd = sql.indexOf(';', grantStart);
|
||||
|
||||
assertThat(comment).isGreaterThanOrEqualTo(0);
|
||||
assertThat(grantStart).isGreaterThan(comment);
|
||||
assertThat(grantEnd).isGreaterThan(grantStart);
|
||||
String grant = sql.substring(grantStart, grantEnd);
|
||||
assertThat(merchantCodes(grant)).containsExactlyInAnyOrderElementsOf(CUSTOMER_OVERSEAS_PERMISSIONS);
|
||||
assertThat(grant).contains(
|
||||
"role.app_code='MERCHANT'",
|
||||
"role.role_code='MERCHANT_OWNER'",
|
||||
"permission.app_code='MERCHANT'");
|
||||
assertThat(grant).doesNotContain("PLATFORM_ADMIN", "PLATFORM_CUSTOM_ADMIN");
|
||||
}
|
||||
|
||||
@Test
|
||||
void assertsCatalogAndOwnerGrantCompleteness() throws Exception {
|
||||
String sql = sql();
|
||||
|
||||
assertThat(sql).contains(
|
||||
"assert_overseas_merchant_permissions",
|
||||
"海外客户权限初始化失败:权限资源不完整",
|
||||
"海外客户权限初始化失败:客户默认管理员授权不完整",
|
||||
"permission.app_code='MERCHANT'",
|
||||
"role.role_code='MERCHANT_OWNER'",
|
||||
")) <> 4 THEN");
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsAllOverseasPdaOperationsBehindTheSingleExistingPermission() throws Exception {
|
||||
String sql = sql();
|
||||
Set<String> pdaCodes = new LinkedHashSet<>();
|
||||
Pattern.compile("lastleg:pda:[a-z0-9:-]+")
|
||||
.matcher(sql).results().map(result -> result.group()).forEach(pdaCodes::add);
|
||||
|
||||
assertThat(pdaCodes).containsExactly("lastleg:pda:operate");
|
||||
assertThat(sql).contains(
|
||||
"role.id=4000005",
|
||||
"role.role_code='OVERSEAS_WAREHOUSE_PDA_OPERATOR'",
|
||||
"存在非海外仓 PDA 作业员授权");
|
||||
assertThat(sql).doesNotContain(
|
||||
"lastleg:pda:stocktake",
|
||||
"lastleg:pda:transfer",
|
||||
"lastleg:pda:relabel",
|
||||
"lastleg:pda:query");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchesTheFrozenLastlegPermissionConstants() throws Exception {
|
||||
Path constants = Path.of(
|
||||
"lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java");
|
||||
if (!Files.exists(constants)) constants = Path.of("..").resolve(constants);
|
||||
|
||||
assertThat(merchantCodes(Files.readString(constants, StandardCharsets.UTF_8)))
|
||||
.containsAll(CUSTOMER_OVERSEAS_PERMISSIONS);
|
||||
}
|
||||
|
||||
private static Set<String> merchantCodes(String source) {
|
||||
Set<String> values = new LinkedHashSet<>();
|
||||
MERCHANT_CODE.matcher(source).results().map(result -> result.group()).forEach(values::add);
|
||||
return values;
|
||||
}
|
||||
|
||||
private static String sql() throws Exception {
|
||||
return new ClassPathResource("db/lastleg-permissions.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -138,17 +138,17 @@ class Phase5DeliveryPermissionSqlContractTest {
|
||||
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 overseasCatalog = unifiedSql.indexOf("-- 海外权限统一目录");
|
||||
int outboundDelivery = unifiedSql.indexOf("-- 海外排车、出库与派送权限(来源:iam/db/phase5-delivery-permissions.sql)");
|
||||
int bodyStart = unifiedSql.indexOf("USE baiyue_iam;", outboundDelivery);
|
||||
int nextSection = unifiedSql.indexOf("-- IAM 客户提交即成功", bodyStart);
|
||||
|
||||
assertThat(phase4).isGreaterThanOrEqualTo(0);
|
||||
assertThat(phase5).isGreaterThan(phase4);
|
||||
assertThat(bodyStart).isGreaterThan(phase5);
|
||||
assertThat(overseasCatalog).isGreaterThanOrEqualTo(0);
|
||||
assertThat(outboundDelivery).isGreaterThan(overseasCatalog);
|
||||
assertThat(bodyStart).isGreaterThan(outboundDelivery);
|
||||
assertThat(nextSection).isGreaterThan(bodyStart);
|
||||
assertThat(unifiedSql.substring(bodyStart, nextSection).trim()).isEqualTo(moduleSql);
|
||||
assertThat(codes(unifiedSql.substring(phase5, nextSection)))
|
||||
assertThat(codes(unifiedSql.substring(outboundDelivery, nextSection)))
|
||||
.containsExactlyInAnyOrderElementsOf(REQUIRED);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ class Phase5DeliveryPermissionSqlContractTest {
|
||||
String readme = repositoryFile("deploy/sql/README.md");
|
||||
|
||||
assertThat(readme).contains(
|
||||
"五期海外排车、出库与派送权限",
|
||||
"海外排车、出库与派送权限",
|
||||
"测试和部署只执行固定入口,不再单独执行模块脚本",
|
||||
"排车列表/编辑/取消/转派送",
|
||||
"异常订单列表/创建和客户回访列表/编辑十四项权限",
|
||||
|
||||
@@ -90,6 +90,26 @@ class AuthorizationSnapshotServiceTest {
|
||||
"merchant:warehouse:delivery:list");
|
||||
}
|
||||
|
||||
@Test
|
||||
void exposesCustomerOverseasBusinessPermissionsFromCurrentRoleAssignments() {
|
||||
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:cross-border:procurement",
|
||||
"merchant:cross-border:domestic-trucking",
|
||||
"merchant:cross-border:pallet-shipping",
|
||||
"merchant:warehouse:inbound:list"));
|
||||
|
||||
var result = service.currentPermissions(new AuthenticatedUser(42L, 7L, 7L, 9L,
|
||||
"owner", "MERCHANT", "MERCHANT", java.util.Set.of()), "MERCHANT");
|
||||
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"merchant:cross-border:procurement",
|
||||
"merchant:cross-border:domestic-trucking",
|
||||
"merchant:cross-border:pallet-shipping",
|
||||
"merchant:warehouse:inbound:list");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsIncompleteCurrentIdentityAsBusinessError() {
|
||||
assertThatThrownBy(() -> service
|
||||
|
||||
Reference in New Issue
Block a user