From d88e5cffce58b3794e01c76011cc77e929d6362c Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 1 Sep 2026 20:00:49 +0800 Subject: [PATCH] fix: align phase5 overseas permissions --- deploy/sql/README.md | 4 +- deploy/sql/头程数据库统一增量-MySQL8.sql | 130 ++++++++++++++---- .../db/phase5-delivery-permissions.sql | 115 ++++++++++++++-- iam/src/main/resources/openapi/iam-v1.yaml | 2 +- .../controller/IamOpenApiContractTest.java | 12 ++ ...ase5DeliveryPermissionSqlContractTest.java | 45 +++++- .../controller/CustomerVisitController.java | 8 ++ .../controller/DispatchQueryController.java | 4 +- .../controller/ExceptionOrderController.java | 7 + .../lastleg/security/OverseasPermissions.java | 7 + .../openapi/overseas-business-v1.yaml | 93 ++++++++++++- .../DispatchQueryControllerTest.java | 6 +- .../Phase5AdminPermissionContractTest.java | 81 +++++++++++ 13 files changed, 459 insertions(+), 55 deletions(-) create mode 100644 lastleg-service/src/test/java/com/baiyue/lastleg/security/Phase5AdminPermissionContractTest.java diff --git a/deploy/sql/README.md b/deploy/sql/README.md index 135a4f942..91def854e 100644 --- a/deploy/sql/README.md +++ b/deploy/sql/README.md @@ -230,9 +230,9 @@ SELECT ## 五期海外排车、出库与派送权限 - 国内固定入口已在四期 `lastleg-permissions.sql` 权限段之后完整内联 `iam/src/main/resources/db/phase5-delivery-permissions.sql`;测试和部署只执行固定入口,不再单独执行模块脚本。 -- 平台端固定使用排车编辑/取消/转派送、出库列表/创建/取消和派送列表七项权限;列表权限包含详情只读,写操作保持独立授权。 +- 平台端固定使用排车列表/编辑/取消/转派送、出库列表/创建/取消、派送列表/退回/状态、异常订单列表/创建和客户回访列表/编辑十四项权限;列表权限包含详情及只读辅助接口,写操作保持独立授权。 - 客户端固定使用 `merchant:warehouse:delivery:list` 和 `merchant:warehouse:delivery:create`;客户默认管理员获得两项权限,其他客户角色不自动扩权。 -- `WAREHOUSE_OPERATOR` 获得七项后台作业权限,`WAREHOUSE_TALLY` 只获得出库和派送列表只读;国内、海外 PDA 岗位不得获得上述后台权限。 +- `WAREHOUSE_OPERATOR` 获得十四项后台作业权限,`WAREHOUSE_TALLY` 只获得排车、出库、派送、异常订单和客户回访五项列表只读;国内、海外 PDA 岗位不得获得上述后台权限。 ## 五期海外排车与出库结构升级 diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index 2cdd21695..7bba8626d 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -16518,24 +16518,38 @@ CREATE PROCEDURE guard_phase5_delivery_permission_ids() BEGIN IF EXISTS ( SELECT 1 FROM iam_permission - WHERE (id = 5107016 AND permission_code <> 'platform:overseas-warehouse:dispatch:edit') + WHERE (id = 5107064 AND permission_code <> 'platform:overseas-warehouse:dispatch:list') + OR (id = 5107016 AND permission_code <> 'platform:overseas-warehouse:dispatch:edit') OR (id = 5107017 AND permission_code <> 'platform:overseas-warehouse:dispatch:cancel') OR (id = 5107018 AND permission_code <> 'platform:overseas-warehouse:dispatch:transfer-delivery') OR (id = 5107090 AND permission_code <> 'platform:overseas-warehouse:outbound:list') OR (id = 5107091 AND permission_code <> 'platform:overseas-warehouse:outbound:create') OR (id = 5107092 AND permission_code <> 'platform:overseas-warehouse:delivery:list') OR (id = 5107093 AND permission_code <> 'platform:overseas-warehouse:outbound:cancel') + OR (id = 5107070 AND permission_code <> 'platform:overseas-warehouse:exception-order:list') + OR (id = 5107071 AND permission_code <> 'platform:overseas-warehouse:exception-order:create') + OR (id = 5107072 AND permission_code <> 'platform:overseas-warehouse:delivery:return') + OR (id = 5107080 AND permission_code <> 'platform:overseas-warehouse:customer-visit:list') + OR (id = 5107081 AND permission_code <> 'platform:overseas-warehouse:customer-visit:edit') + OR (id = 5107082 AND permission_code <> 'platform:overseas-warehouse:delivery:status') OR (id = 5306000 AND permission_code <> 'merchant:warehouse:delivery:list') OR (id = 5306001 AND permission_code <> 'merchant:warehouse:delivery:create') ) OR EXISTS ( SELECT 1 FROM iam_permission - WHERE (permission_code = 'platform:overseas-warehouse:dispatch:edit' AND id <> 5107016) + WHERE (permission_code = 'platform:overseas-warehouse:dispatch:list' AND id <> 5107064) + OR (permission_code = 'platform:overseas-warehouse:dispatch:edit' AND id <> 5107016) OR (permission_code = 'platform:overseas-warehouse:dispatch:cancel' AND id <> 5107017) OR (permission_code = 'platform:overseas-warehouse:dispatch:transfer-delivery' AND id <> 5107018) OR (permission_code = 'platform:overseas-warehouse:outbound:list' AND id <> 5107090) OR (permission_code = 'platform:overseas-warehouse:outbound:create' AND id <> 5107091) OR (permission_code = 'platform:overseas-warehouse:delivery:list' AND id <> 5107092) OR (permission_code = 'platform:overseas-warehouse:outbound:cancel' AND id <> 5107093) + OR (permission_code = 'platform:overseas-warehouse:exception-order:list' AND id <> 5107070) + OR (permission_code = 'platform:overseas-warehouse:exception-order:create' AND id <> 5107071) + OR (permission_code = 'platform:overseas-warehouse:delivery:return' AND id <> 5107072) + OR (permission_code = 'platform:overseas-warehouse:customer-visit:list' AND id <> 5107080) + OR (permission_code = 'platform:overseas-warehouse:customer-visit:edit' AND id <> 5107081) + OR (permission_code = 'platform:overseas-warehouse:delivery:status' AND id <> 5107082) OR (permission_code = 'merchant:warehouse:delivery:list' AND id <> 5306000) OR (permission_code = 'merchant:warehouse:delivery:create' AND id <> 5306001) ) THEN @@ -16550,14 +16564,21 @@ INSERT INTO iam_permission (id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, route_path, http_method, sort_no, status, built_in, deleted) VALUES - (5107016,0,'PLATFORM','BUTTON',5107010,'platform:overseas-warehouse:dispatch:edit','编辑海外排车',NULL,'PUT',716,'ACTIVE',1,0), - (5107017,0,'PLATFORM','BUTTON',5107010,'platform:overseas-warehouse:dispatch:cancel','取消海外排车',NULL,'POST',717,'ACTIVE',1,0), - (5107018,0,'PLATFORM','BUTTON',5107010,'platform:overseas-warehouse:dispatch:transfer-delivery','排车转派送',NULL,'POST',718,'ACTIVE',1,0), + (5107064,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:dispatch:list','海外排车单','/overseas-warehouse/dispatches','GET',764,'ACTIVE',1,0), + (5107016,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:edit','编辑海外排车',NULL,'PUT',716,'ACTIVE',1,0), + (5107017,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:cancel','取消海外排车',NULL,'DELETE',717,'ACTIVE',1,0), + (5107018,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:transfer-delivery','排车转派送',NULL,'POST',718,'ACTIVE',1,0), + (5107070,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:exception-order:list','海外异常订单','/overseas-warehouse/exception-orders','GET',770,'ACTIVE',1,0), + (5107071,0,'PLATFORM','BUTTON',5107070,'platform:overseas-warehouse:exception-order:create','新增海外异常订单',NULL,'POST',771,'ACTIVE',1,0), + (5107072,0,'PLATFORM','BUTTON',5107092,'platform:overseas-warehouse:delivery:return','派送单标记退货',NULL,'POST',772,'ACTIVE',1,0), + (5107080,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:customer-visit:list','客户回访','/overseas-warehouse/customer-visits','GET',780,'ACTIVE',1,0), + (5107081,0,'PLATFORM','BUTTON',5107080,'platform:overseas-warehouse:customer-visit:edit','保存客户回访',NULL,'PUT',781,'ACTIVE',1,0), + (5107082,0,'PLATFORM','BUTTON',5107092,'platform:overseas-warehouse:delivery:status','编辑派送单状态',NULL,'PUT',782,'ACTIVE',1,0), (5107090,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:outbound:list','海外出库单','/overseas-warehouse/outbounds','GET',765,'ACTIVE',1,0), (5107091,0,'PLATFORM','BUTTON',5107090,'platform:overseas-warehouse:outbound:create','创建海外出库单',NULL,'POST',766,'ACTIVE',1,0), (5107092,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:delivery:list','海外派送单','/overseas-warehouse/delivery-orders','GET',767,'ACTIVE',1,0), (5107093,0,'PLATFORM','BUTTON',5107090,'platform:overseas-warehouse:outbound:cancel','取消海外出库单',NULL,'POST',768,'ACTIVE',1,0), - (5306000,0,'MERCHANT','MENU',0,'merchant:warehouse:delivery:list','海外仓派送单','/overseas-warehouse/delivery-orders','GET',60,'ACTIVE',1,0), + (5306000,0,'MERCHANT','MENU',0,'merchant:warehouse:delivery:list','海外仓派送单','/orders/delivery','GET',60,'ACTIVE',1,0), (5306001,0,'MERCHANT','BUTTON',5306000,'merchant:warehouse:delivery:create','创建海外仓派送单',NULL,'POST',10,'ACTIVE',1,0) ON DUPLICATE KEY UPDATE permission_type=VALUES(permission_type), parent_id=VALUES(parent_id), @@ -16574,13 +16595,20 @@ SELECT 0, role.id, permission.id, CURRENT_TIMESTAMP(3) AND UPPER(role.role_code) IN ('PLATFORM_ADMIN','PLATFORM_CUSTOM_ADMIN') AND role.status='ACTIVE' AND role.deleted=0 AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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') + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit') AND permission.status='ACTIVE' AND permission.deleted=0; -- 仓库后台岗位按最小职责授权;PDA 岗位不得获得后台排车、出库或派送权限。 @@ -16591,6 +16619,7 @@ CREATE TEMPORARY TABLE tmp_phase5_delivery_role_permission ( PRIMARY KEY (role_code, permission_code) ) ENGINE=MEMORY; INSERT INTO tmp_phase5_delivery_role_permission (role_code, permission_code) VALUES + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:list'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:edit'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:cancel'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:transfer-delivery'), @@ -16598,8 +16627,17 @@ INSERT INTO tmp_phase5_delivery_role_permission (role_code, permission_code) VAL ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:outbound:create'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:outbound:cancel'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:list'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:list'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:create'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:return'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:status'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:customer-visit:list'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:customer-visit:edit'), + ('WAREHOUSE_TALLY','platform:overseas-warehouse:dispatch:list'), ('WAREHOUSE_TALLY','platform:overseas-warehouse:outbound:list'), - ('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:list'); + ('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:list'), + ('WAREHOUSE_TALLY','platform:overseas-warehouse:exception-order:list'), + ('WAREHOUSE_TALLY','platform:overseas-warehouse:customer-visit:list'); DELETE grant_row FROM iam_role_permission grant_row JOIN iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id @@ -16609,13 +16647,20 @@ LEFT JOIN tmp_phase5_delivery_role_permission expected WHERE role.tenant_id=0 AND role.app_code='PLATFORM' AND role.role_code IN ('WAREHOUSE_OPERATOR','WAREHOUSE_TALLY','OVERSEAS_WAREHOUSE_PDA_OPERATOR','CN_FIRSTLEG_PDA_OPERATOR') AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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') + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit') AND expected.permission_code IS NULL; INSERT IGNORE INTO iam_role_permission (tenant_id, role_id, permission_id, created_at) @@ -16649,6 +16694,7 @@ BEGIN IF (SELECT COUNT(*) FROM iam_permission WHERE tenant_id=0 AND status='ACTIVE' AND deleted=0 AND permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', 'platform:overseas-warehouse:dispatch:edit', 'platform:overseas-warehouse:dispatch:cancel', 'platform:overseas-warehouse:dispatch:transfer-delivery', @@ -16656,8 +16702,14 @@ BEGIN 'platform:overseas-warehouse:outbound:create', 'platform:overseas-warehouse:outbound:cancel', 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit', 'merchant:warehouse:delivery:list', - 'merchant:warehouse:delivery:create')) <> 9 THEN + 'merchant:warehouse:delivery:create')) <> 16 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:权限目录不完整'; END IF; IF (SELECT COUNT(*) FROM iam_role_permission grant_row @@ -16665,21 +16717,49 @@ BEGIN JOIN iam_permission permission ON permission.id=grant_row.permission_id WHERE role.role_code='PLATFORM_ADMIN' AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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')) <> 7 THEN + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台管理员授权不完整'; END IF; + IF (SELECT COUNT(*) FROM iam_role_permission grant_row + JOIN iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id + JOIN iam_permission permission ON permission.id=grant_row.permission_id + WHERE role.role_code='PLATFORM_CUSTOM_ADMIN' + AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', + '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', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台自定义管理员授权不完整'; + END IF; SELECT COALESCE(SUM(role_code='WAREHOUSE_OPERATOR'),0), COALESCE(SUM(role_code='WAREHOUSE_TALLY'),0) INTO v_warehouse_operator_permission_count, v_warehouse_tally_permission_count FROM tmp_phase5_delivery_role_permission; - IF v_warehouse_operator_permission_count <> 7 - OR v_warehouse_tally_permission_count <> 2 THEN + IF v_warehouse_operator_permission_count <> 14 + OR v_warehouse_tally_permission_count <> 5 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:仓库岗位最小权限矩阵异常'; END IF; IF EXISTS (SELECT 1 FROM iam_role_permission grant_row @@ -16687,13 +16767,20 @@ BEGIN JOIN iam_permission permission ON permission.id=grant_row.permission_id WHERE role.role_code IN ('OVERSEAS_WAREHOUSE_PDA_OPERATOR','CN_FIRSTLEG_PDA_OPERATOR') AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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')) THEN + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit')) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:PDA岗位错误获得后台权限'; END IF; IF (SELECT COUNT(*) FROM iam_role_permission grant_row @@ -16830,21 +16917,6 @@ CREATE TABLE IF NOT EXISTS ll_customer_visit ( ) ENGINE=InnoDB COMMENT='派送单维度客户回访记录'; -INSERT INTO baiyue_iam.iam_permission - (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,deleted) -VALUES - (5107070,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:exception-order:list','海外异常订单','/overseas-warehouse/exception-orders','GET',770,'ACTIVE',1,0), - (5107071,0,'PLATFORM','BUTTON',5107070,'platform:overseas-warehouse:exception-order:create','新增海外异常订单',NULL,'POST',771,'ACTIVE',1,0), - (5107072,0,'PLATFORM','BUTTON',5107070,'platform:overseas-warehouse:delivery:return','派送单标记退货',NULL,'POST',772,'ACTIVE',1,0) - ,(5107080,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:customer-visit:list','客户回访','/overseas-warehouse/customer-visits','GET',780,'ACTIVE',1,0) - ,(5107081,0,'PLATFORM','BUTTON',5107080,'platform:overseas-warehouse:customer-visit:edit','保存客户回访',NULL,'PUT',781,'ACTIVE',1,0) - ,(5107082,0,'PLATFORM','BUTTON',5107080,'platform:overseas-warehouse:delivery:status','编辑派送单状态',NULL,'PUT',782,'ACTIVE',1,0) -ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),route_path=VALUES(route_path),http_method=VALUES(http_method),sort_no=VALUES(sort_no),status='ACTIVE',built_in=1,deleted=0; -INSERT IGNORE INTO baiyue_iam.iam_role_permission (tenant_id,role_id,permission_id,created_at) -SELECT 0,role.id,permission.id,NOW(3) FROM baiyue_iam.iam_role role -JOIN baiyue_iam.iam_permission permission ON permission.id BETWEEN 5107070 AND 5107082 AND permission.tenant_id=0 -WHERE role.tenant_id=0 AND role.app_code='PLATFORM' AND role.role_code='PLATFORM_ADMIN' AND role.status='ACTIVE' AND role.deleted=0; - -- IAM 客户提交即成功,默认尺寸通过持久化任务后台初始化;已有客户按历史事实标记 READY。 USE baiyue_iam; SET @customer_dimension_status_ddl = (SELECT IF( diff --git a/iam/src/main/resources/db/phase5-delivery-permissions.sql b/iam/src/main/resources/db/phase5-delivery-permissions.sql index f60b4a4b5..0254b102b 100644 --- a/iam/src/main/resources/db/phase5-delivery-permissions.sql +++ b/iam/src/main/resources/db/phase5-delivery-permissions.sql @@ -8,24 +8,38 @@ CREATE PROCEDURE guard_phase5_delivery_permission_ids() BEGIN IF EXISTS ( SELECT 1 FROM iam_permission - WHERE (id = 5107016 AND permission_code <> 'platform:overseas-warehouse:dispatch:edit') + WHERE (id = 5107064 AND permission_code <> 'platform:overseas-warehouse:dispatch:list') + OR (id = 5107016 AND permission_code <> 'platform:overseas-warehouse:dispatch:edit') OR (id = 5107017 AND permission_code <> 'platform:overseas-warehouse:dispatch:cancel') OR (id = 5107018 AND permission_code <> 'platform:overseas-warehouse:dispatch:transfer-delivery') OR (id = 5107090 AND permission_code <> 'platform:overseas-warehouse:outbound:list') OR (id = 5107091 AND permission_code <> 'platform:overseas-warehouse:outbound:create') OR (id = 5107092 AND permission_code <> 'platform:overseas-warehouse:delivery:list') OR (id = 5107093 AND permission_code <> 'platform:overseas-warehouse:outbound:cancel') + OR (id = 5107070 AND permission_code <> 'platform:overseas-warehouse:exception-order:list') + OR (id = 5107071 AND permission_code <> 'platform:overseas-warehouse:exception-order:create') + OR (id = 5107072 AND permission_code <> 'platform:overseas-warehouse:delivery:return') + OR (id = 5107080 AND permission_code <> 'platform:overseas-warehouse:customer-visit:list') + OR (id = 5107081 AND permission_code <> 'platform:overseas-warehouse:customer-visit:edit') + OR (id = 5107082 AND permission_code <> 'platform:overseas-warehouse:delivery:status') OR (id = 5306000 AND permission_code <> 'merchant:warehouse:delivery:list') OR (id = 5306001 AND permission_code <> 'merchant:warehouse:delivery:create') ) OR EXISTS ( SELECT 1 FROM iam_permission - WHERE (permission_code = 'platform:overseas-warehouse:dispatch:edit' AND id <> 5107016) + WHERE (permission_code = 'platform:overseas-warehouse:dispatch:list' AND id <> 5107064) + OR (permission_code = 'platform:overseas-warehouse:dispatch:edit' AND id <> 5107016) OR (permission_code = 'platform:overseas-warehouse:dispatch:cancel' AND id <> 5107017) OR (permission_code = 'platform:overseas-warehouse:dispatch:transfer-delivery' AND id <> 5107018) OR (permission_code = 'platform:overseas-warehouse:outbound:list' AND id <> 5107090) OR (permission_code = 'platform:overseas-warehouse:outbound:create' AND id <> 5107091) OR (permission_code = 'platform:overseas-warehouse:delivery:list' AND id <> 5107092) OR (permission_code = 'platform:overseas-warehouse:outbound:cancel' AND id <> 5107093) + OR (permission_code = 'platform:overseas-warehouse:exception-order:list' AND id <> 5107070) + OR (permission_code = 'platform:overseas-warehouse:exception-order:create' AND id <> 5107071) + OR (permission_code = 'platform:overseas-warehouse:delivery:return' AND id <> 5107072) + OR (permission_code = 'platform:overseas-warehouse:customer-visit:list' AND id <> 5107080) + OR (permission_code = 'platform:overseas-warehouse:customer-visit:edit' AND id <> 5107081) + OR (permission_code = 'platform:overseas-warehouse:delivery:status' AND id <> 5107082) OR (permission_code = 'merchant:warehouse:delivery:list' AND id <> 5306000) OR (permission_code = 'merchant:warehouse:delivery:create' AND id <> 5306001) ) THEN @@ -40,14 +54,21 @@ INSERT INTO iam_permission (id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, route_path, http_method, sort_no, status, built_in, deleted) VALUES - (5107016,0,'PLATFORM','BUTTON',5107010,'platform:overseas-warehouse:dispatch:edit','编辑海外排车',NULL,'PUT',716,'ACTIVE',1,0), - (5107017,0,'PLATFORM','BUTTON',5107010,'platform:overseas-warehouse:dispatch:cancel','取消海外排车',NULL,'POST',717,'ACTIVE',1,0), - (5107018,0,'PLATFORM','BUTTON',5107010,'platform:overseas-warehouse:dispatch:transfer-delivery','排车转派送',NULL,'POST',718,'ACTIVE',1,0), + (5107064,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:dispatch:list','海外排车单','/overseas-warehouse/dispatches','GET',764,'ACTIVE',1,0), + (5107016,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:edit','编辑海外排车',NULL,'PUT',716,'ACTIVE',1,0), + (5107017,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:cancel','取消海外排车',NULL,'DELETE',717,'ACTIVE',1,0), + (5107018,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:transfer-delivery','排车转派送',NULL,'POST',718,'ACTIVE',1,0), + (5107070,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:exception-order:list','海外异常订单','/overseas-warehouse/exception-orders','GET',770,'ACTIVE',1,0), + (5107071,0,'PLATFORM','BUTTON',5107070,'platform:overseas-warehouse:exception-order:create','新增海外异常订单',NULL,'POST',771,'ACTIVE',1,0), + (5107072,0,'PLATFORM','BUTTON',5107092,'platform:overseas-warehouse:delivery:return','派送单标记退货',NULL,'POST',772,'ACTIVE',1,0), + (5107080,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:customer-visit:list','客户回访','/overseas-warehouse/customer-visits','GET',780,'ACTIVE',1,0), + (5107081,0,'PLATFORM','BUTTON',5107080,'platform:overseas-warehouse:customer-visit:edit','保存客户回访',NULL,'PUT',781,'ACTIVE',1,0), + (5107082,0,'PLATFORM','BUTTON',5107092,'platform:overseas-warehouse:delivery:status','编辑派送单状态',NULL,'PUT',782,'ACTIVE',1,0), (5107090,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:outbound:list','海外出库单','/overseas-warehouse/outbounds','GET',765,'ACTIVE',1,0), (5107091,0,'PLATFORM','BUTTON',5107090,'platform:overseas-warehouse:outbound:create','创建海外出库单',NULL,'POST',766,'ACTIVE',1,0), (5107092,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:delivery:list','海外派送单','/overseas-warehouse/delivery-orders','GET',767,'ACTIVE',1,0), (5107093,0,'PLATFORM','BUTTON',5107090,'platform:overseas-warehouse:outbound:cancel','取消海外出库单',NULL,'POST',768,'ACTIVE',1,0), - (5306000,0,'MERCHANT','MENU',0,'merchant:warehouse:delivery:list','海外仓派送单','/overseas-warehouse/delivery-orders','GET',60,'ACTIVE',1,0), + (5306000,0,'MERCHANT','MENU',0,'merchant:warehouse:delivery:list','海外仓派送单','/orders/delivery','GET',60,'ACTIVE',1,0), (5306001,0,'MERCHANT','BUTTON',5306000,'merchant:warehouse:delivery:create','创建海外仓派送单',NULL,'POST',10,'ACTIVE',1,0) ON DUPLICATE KEY UPDATE permission_type=VALUES(permission_type), parent_id=VALUES(parent_id), @@ -64,13 +85,20 @@ SELECT 0, role.id, permission.id, CURRENT_TIMESTAMP(3) AND UPPER(role.role_code) IN ('PLATFORM_ADMIN','PLATFORM_CUSTOM_ADMIN') AND role.status='ACTIVE' AND role.deleted=0 AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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') + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit') AND permission.status='ACTIVE' AND permission.deleted=0; -- 仓库后台岗位按最小职责授权;PDA 岗位不得获得后台排车、出库或派送权限。 @@ -81,6 +109,7 @@ CREATE TEMPORARY TABLE tmp_phase5_delivery_role_permission ( PRIMARY KEY (role_code, permission_code) ) ENGINE=MEMORY; INSERT INTO tmp_phase5_delivery_role_permission (role_code, permission_code) VALUES + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:list'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:edit'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:cancel'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:transfer-delivery'), @@ -88,8 +117,17 @@ INSERT INTO tmp_phase5_delivery_role_permission (role_code, permission_code) VAL ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:outbound:create'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:outbound:cancel'), ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:list'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:list'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:create'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:return'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:status'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:customer-visit:list'), + ('WAREHOUSE_OPERATOR','platform:overseas-warehouse:customer-visit:edit'), + ('WAREHOUSE_TALLY','platform:overseas-warehouse:dispatch:list'), ('WAREHOUSE_TALLY','platform:overseas-warehouse:outbound:list'), - ('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:list'); + ('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:list'), + ('WAREHOUSE_TALLY','platform:overseas-warehouse:exception-order:list'), + ('WAREHOUSE_TALLY','platform:overseas-warehouse:customer-visit:list'); DELETE grant_row FROM iam_role_permission grant_row JOIN iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id @@ -99,13 +137,20 @@ LEFT JOIN tmp_phase5_delivery_role_permission expected WHERE role.tenant_id=0 AND role.app_code='PLATFORM' AND role.role_code IN ('WAREHOUSE_OPERATOR','WAREHOUSE_TALLY','OVERSEAS_WAREHOUSE_PDA_OPERATOR','CN_FIRSTLEG_PDA_OPERATOR') AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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') + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit') AND expected.permission_code IS NULL; INSERT IGNORE INTO iam_role_permission (tenant_id, role_id, permission_id, created_at) @@ -139,6 +184,7 @@ BEGIN IF (SELECT COUNT(*) FROM iam_permission WHERE tenant_id=0 AND status='ACTIVE' AND deleted=0 AND permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', 'platform:overseas-warehouse:dispatch:edit', 'platform:overseas-warehouse:dispatch:cancel', 'platform:overseas-warehouse:dispatch:transfer-delivery', @@ -146,8 +192,14 @@ BEGIN 'platform:overseas-warehouse:outbound:create', 'platform:overseas-warehouse:outbound:cancel', 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit', 'merchant:warehouse:delivery:list', - 'merchant:warehouse:delivery:create')) <> 9 THEN + 'merchant:warehouse:delivery:create')) <> 16 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:权限目录不完整'; END IF; IF (SELECT COUNT(*) FROM iam_role_permission grant_row @@ -155,21 +207,49 @@ BEGIN JOIN iam_permission permission ON permission.id=grant_row.permission_id WHERE role.role_code='PLATFORM_ADMIN' AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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')) <> 7 THEN + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台管理员授权不完整'; END IF; + IF (SELECT COUNT(*) FROM iam_role_permission grant_row + JOIN iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id + JOIN iam_permission permission ON permission.id=grant_row.permission_id + WHERE role.role_code='PLATFORM_CUSTOM_ADMIN' + AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', + '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', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台自定义管理员授权不完整'; + END IF; SELECT COALESCE(SUM(role_code='WAREHOUSE_OPERATOR'),0), COALESCE(SUM(role_code='WAREHOUSE_TALLY'),0) INTO v_warehouse_operator_permission_count, v_warehouse_tally_permission_count FROM tmp_phase5_delivery_role_permission; - IF v_warehouse_operator_permission_count <> 7 - OR v_warehouse_tally_permission_count <> 2 THEN + IF v_warehouse_operator_permission_count <> 14 + OR v_warehouse_tally_permission_count <> 5 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:仓库岗位最小权限矩阵异常'; END IF; IF EXISTS (SELECT 1 FROM iam_role_permission grant_row @@ -177,13 +257,20 @@ BEGIN JOIN iam_permission permission ON permission.id=grant_row.permission_id WHERE role.role_code IN ('OVERSEAS_WAREHOUSE_PDA_OPERATOR','CN_FIRSTLEG_PDA_OPERATOR') AND permission.permission_code IN ( + 'platform:overseas-warehouse:dispatch:list', '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')) THEN + 'platform:overseas-warehouse:delivery:list', + 'platform:overseas-warehouse:exception-order:list', + 'platform:overseas-warehouse:exception-order:create', + 'platform:overseas-warehouse:delivery:return', + 'platform:overseas-warehouse:delivery:status', + 'platform:overseas-warehouse:customer-visit:list', + 'platform:overseas-warehouse:customer-visit:edit')) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:PDA岗位错误获得后台权限'; END IF; IF (SELECT COUNT(*) FROM iam_role_permission grant_row diff --git a/iam/src/main/resources/openapi/iam-v1.yaml b/iam/src/main/resources/openapi/iam-v1.yaml index c2c0037d5..e2bef5864 100644 --- a/iam/src/main/resources/openapi/iam-v1.yaml +++ b/iam/src/main/resources/openapi/iam-v1.yaml @@ -124,7 +124,7 @@ paths: get: tags: [IAM Resources / IAM 资源] summary: 查询当前用户有效权限 - description: 返回当前有效平台成员权限编码;只要求有效 PLATFORM JWT,不依赖 `platform:role:list`。五期海外排车、出库与派送分别返回 `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`;列表权限包含详情只读,写操作独立授权。 + description: 返回当前有效平台成员权限编码;只要求有效 PLATFORM JWT,不依赖 `platform:role:list`。五期海外仓返回 `platform:overseas-warehouse:dispatch:list`、`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`、`platform:overseas-warehouse:delivery:return`、`platform:overseas-warehouse:delivery:status`、`platform:overseas-warehouse:exception-order:list`、`platform:overseas-warehouse:exception-order:create`、`platform:overseas-warehouse:customer-visit:list`、`platform:overseas-warehouse:customer-visit:edit`;列表权限包含详情和只读辅助接口,写操作独立授权。 responses: '200': description: 当前平台成员权限查询成功 diff --git a/iam/src/test/java/com/baiyue/iam/controller/IamOpenApiContractTest.java b/iam/src/test/java/com/baiyue/iam/controller/IamOpenApiContractTest.java index 5ae67d606..c594921df 100644 --- a/iam/src/test/java/com/baiyue/iam/controller/IamOpenApiContractTest.java +++ b/iam/src/test/java/com/baiyue/iam/controller/IamOpenApiContractTest.java @@ -20,7 +20,19 @@ class IamOpenApiContractTest { assertThat(document).contains("/api/platform/v1/iam/authorization/permissions:") .contains("/api/merchant/v1/iam/authorization/permissions:") + .contains("platform:overseas-warehouse:dispatch:list") + .contains("platform:overseas-warehouse:dispatch:edit") + .contains("platform:overseas-warehouse:dispatch:cancel") .contains("platform:overseas-warehouse:dispatch:transfer-delivery") + .contains("platform:overseas-warehouse:outbound:list") + .contains("platform:overseas-warehouse:outbound:create") + .contains("platform:overseas-warehouse:delivery:list") + .contains("platform:overseas-warehouse:delivery:return") + .contains("platform:overseas-warehouse:delivery:status") + .contains("platform:overseas-warehouse:exception-order:list") + .contains("platform:overseas-warehouse:exception-order:create") + .contains("platform:overseas-warehouse:customer-visit:list") + .contains("platform:overseas-warehouse:customer-visit:edit") .contains("platform:overseas-warehouse:outbound:cancel") .contains("merchant:warehouse:delivery:list") .contains("merchant:warehouse:delivery:create") diff --git a/iam/src/test/java/com/baiyue/iam/repository/Phase5DeliveryPermissionSqlContractTest.java b/iam/src/test/java/com/baiyue/iam/repository/Phase5DeliveryPermissionSqlContractTest.java index 1112018dd..1ddfa354d 100644 --- a/iam/src/test/java/com/baiyue/iam/repository/Phase5DeliveryPermissionSqlContractTest.java +++ b/iam/src/test/java/com/baiyue/iam/repository/Phase5DeliveryPermissionSqlContractTest.java @@ -15,6 +15,7 @@ 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 REQUIRED = Set.of( + "platform:overseas-warehouse:dispatch:list", "platform:overseas-warehouse:dispatch:edit", "platform:overseas-warehouse:dispatch:cancel", "platform:overseas-warehouse:dispatch:transfer-delivery", @@ -22,6 +23,12 @@ class Phase5DeliveryPermissionSqlContractTest { "platform:overseas-warehouse:outbound:create", "platform:overseas-warehouse:outbound:cancel", "platform:overseas-warehouse:delivery:list", + "platform:overseas-warehouse:exception-order:list", + "platform:overseas-warehouse:exception-order:create", + "platform:overseas-warehouse:delivery:return", + "platform:overseas-warehouse:delivery:status", + "platform:overseas-warehouse:customer-visit:list", + "platform:overseas-warehouse:customer-visit:edit", "merchant:warehouse:delivery:list", "merchant:warehouse:delivery:create"); @@ -38,6 +45,25 @@ class Phase5DeliveryPermissionSqlContractTest { "列表权限同时覆盖列表和详情只读"); } + @Test + void keepsMenuRoutesAndHttpMethodsAlignedWithTheFrozenAdminAndClientContracts() throws Exception { + String sql = sql(); + + assertThat(sql).contains( + "'platform:overseas-warehouse:dispatch:list','海外排车单','/overseas-warehouse/dispatches','GET'", + "'platform:overseas-warehouse:dispatch:cancel','取消海外排车',NULL,'DELETE'", + "'platform:overseas-warehouse:exception-order:list','海外异常订单','/overseas-warehouse/exception-orders','GET'", + "'platform:overseas-warehouse:exception-order:create','新增海外异常订单',NULL,'POST'", + "'platform:overseas-warehouse:delivery:return','派送单标记退货',NULL,'POST'", + "'platform:overseas-warehouse:delivery:status','编辑派送单状态',NULL,'PUT'", + "'platform:overseas-warehouse:customer-visit:list','客户回访','/overseas-warehouse/customer-visits','GET'", + "'platform:overseas-warehouse:customer-visit:edit','保存客户回访',NULL,'PUT'", + "'merchant:warehouse:delivery:list','海外仓派送单','/orders/delivery','GET'"); + assertThat(sql).doesNotContain( + "'platform:overseas-warehouse:dispatch:cancel','取消海外排车',NULL,'POST'", + "'merchant:warehouse:delivery:list','海外仓派送单','/overseas-warehouse/delivery-orders'"); + } + @Test void grantsAdministratorsAndWarehouseRolesByTheFrozenMinimumMatrix() throws Exception { String sql = sql(); @@ -45,15 +71,27 @@ class Phase5DeliveryPermissionSqlContractTest { assertThat(sql).contains( "UPPER(role.role_code) IN ('PLATFORM_ADMIN','PLATFORM_CUSTOM_ADMIN')", "tmp_phase5_delivery_role_permission", + "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:list')", "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:dispatch:edit')", "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:outbound:create')", + "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:create')", + "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:return')", + "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:status')", + "('WAREHOUSE_OPERATOR','platform:overseas-warehouse:customer-visit:edit')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:dispatch:list')", "('WAREHOUSE_TALLY','platform:overseas-warehouse:outbound:list')", "('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:list')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:exception-order:list')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:customer-visit: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')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:exception-order:create')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:return')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:delivery:status')", + "('WAREHOUSE_TALLY','platform:overseas-warehouse:customer-visit:edit')", "('OVERSEAS_WAREHOUSE_PDA_OPERATOR','platform:overseas-warehouse:", "('CN_FIRSTLEG_PDA_OPERATOR','platform:overseas-warehouse:"); } @@ -68,8 +106,9 @@ class Phase5DeliveryPermissionSqlContractTest { "SELECT COALESCE(SUM(role_code='WAREHOUSE_OPERATOR'),0)", "COALESCE(SUM(role_code='WAREHOUSE_TALLY'),0)", "INTO v_warehouse_operator_permission_count, v_warehouse_tally_permission_count", - "IF v_warehouse_operator_permission_count <> 7", - "OR v_warehouse_tally_permission_count <> 2 THEN"); + "IF v_warehouse_operator_permission_count <> 14", + "OR v_warehouse_tally_permission_count <> 5 THEN", + "平台自定义管理员授权不完整"); assertThat(sql).doesNotContain( "IF (SELECT COUNT(*) FROM tmp_phase5_delivery_role_permission", "OR (SELECT COUNT(*) FROM tmp_phase5_delivery_role_permission"); @@ -116,6 +155,8 @@ class Phase5DeliveryPermissionSqlContractTest { assertThat(readme).contains( "五期海外排车、出库与派送权限", "测试和部署只执行固定入口,不再单独执行模块脚本", + "排车列表/编辑/取消/转派送", + "异常订单列表/创建和客户回访列表/编辑十四项权限", "merchant:warehouse:delivery:list", "merchant:warehouse:delivery:create", "PDA 岗位不得获得上述后台权限"); diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/controller/CustomerVisitController.java b/lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/controller/CustomerVisitController.java index 1c87236ee..f22fbe916 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/controller/CustomerVisitController.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/controller/CustomerVisitController.java @@ -5,10 +5,12 @@ import com.baiyue.common.security.AuthenticatedUser; import com.baiyue.lastleg.customervisit.dto.CustomerVisitRequests; import com.baiyue.lastleg.customervisit.dto.CustomerVisitResponses; import com.baiyue.lastleg.customervisit.service.CustomerVisitService; +import com.baiyue.lastleg.security.OverseasPermissions; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; @@ -29,12 +31,14 @@ public class CustomerVisitController { @Resource private CustomerVisitService service; @GetMapping("/customer-visits") + @PreAuthorize("hasAuthority('" + OverseasPermissions.CUSTOMER_VISIT_LIST + "')") public ApiResponse page(@AuthenticationPrincipal AuthenticatedUser user, @Valid CustomerVisitRequests.Query query) { return ApiResponse.success(service.page(scope(user), query)); } @GetMapping("/customer-visits/{visitId}") + @PreAuthorize("hasAuthority('" + OverseasPermissions.CUSTOMER_VISIT_LIST + "')") public ApiResponse detail(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable long visitId) { @@ -42,6 +46,7 @@ public class CustomerVisitController { } @PutMapping("/customer-visits/{visitId}") + @PreAuthorize("hasAuthority('" + OverseasPermissions.CUSTOMER_VISIT_EDIT + "')") public ApiResponse save(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable long visitId, @@ -50,6 +55,7 @@ public class CustomerVisitController { } @PostMapping(value = "/customer-visits/{visitId}/attachments", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @PreAuthorize("hasAuthority('" + OverseasPermissions.CUSTOMER_VISIT_EDIT + "')") public ApiResponse upload(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable long visitId, @@ -59,6 +65,7 @@ public class CustomerVisitController { } @PostMapping("/delivery-orders/{deliveryNo}/complete") + @PreAuthorize("hasAuthority('" + OverseasPermissions.DELIVERY_STATUS + "')") public ApiResponse completeDelivery( @AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable String deliveryNo) { @@ -66,6 +73,7 @@ public class CustomerVisitController { } @PutMapping("/delivery-orders/{deliveryNo}/status") + @PreAuthorize("hasAuthority('" + OverseasPermissions.DELIVERY_STATUS + "')") public ApiResponse updateDeliveryStatus( @AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable String deliveryNo, @Valid @RequestBody CustomerVisitRequests.DeliveryStatus request) { diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryController.java b/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryController.java index c31d84a80..e01581530 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryController.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryController.java @@ -29,7 +29,7 @@ public class DispatchQueryController { @Resource private DispatchService service; @GetMapping - @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_LIST + "')") + @PreAuthorize("hasAuthority('" + OverseasPermissions.DISPATCH_LIST + "')") @Operation(summary = "Page dispatch orders") public ApiResponse> page( @AuthenticationPrincipal AuthenticatedUser user, @@ -39,7 +39,7 @@ public class DispatchQueryController { } @GetMapping("/{dispatchNo}") - @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_LIST + "')") + @PreAuthorize("hasAuthority('" + OverseasPermissions.DISPATCH_LIST + "')") @Operation(summary = "Get dispatch details and all pallet destinations") public ApiResponse detail( @AuthenticationPrincipal AuthenticatedUser user, diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/controller/ExceptionOrderController.java b/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/controller/ExceptionOrderController.java index 2804eec2f..26972c486 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/controller/ExceptionOrderController.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/controller/ExceptionOrderController.java @@ -6,9 +6,11 @@ import com.baiyue.common.security.AuthenticatedUser; import com.baiyue.lastleg.exceptionorder.dto.ExceptionOrderRequests; import com.baiyue.lastleg.exceptionorder.dto.ExceptionOrderResponses; import com.baiyue.lastleg.exceptionorder.service.ExceptionOrderService; +import com.baiyue.lastleg.security.OverseasPermissions; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; @@ -21,12 +23,14 @@ public class ExceptionOrderController { @Resource private ExceptionOrderService service; @GetMapping("/exception-orders") + @PreAuthorize("hasAuthority('" + OverseasPermissions.EXCEPTION_ORDER_LIST + "')") public ApiResponse> page(@AuthenticationPrincipal AuthenticatedUser user, @Valid ExceptionOrderRequests.Query query) { return ApiResponse.success(service.page(scope(user), query)); } @GetMapping("/exception-orders/resolve") + @PreAuthorize("hasAuthority('" + OverseasPermissions.EXCEPTION_ORDER_LIST + "')") public ApiResponse resolve(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @RequestParam(required = false) String inboundCode, @@ -35,12 +39,14 @@ public class ExceptionOrderController { } @PostMapping("/exception-orders") + @PreAuthorize("hasAuthority('" + OverseasPermissions.EXCEPTION_ORDER_CREATE + "')") public ApiResponse create(@AuthenticationPrincipal AuthenticatedUser user, @Valid @RequestBody ExceptionOrderRequests.Create request) { return ApiResponse.success(service.create(scope(user), operator(user), request)); } @GetMapping("/delivery-orders/{deliveryNo}/return-inbound-options") + @PreAuthorize("hasAuthority('" + OverseasPermissions.EXCEPTION_ORDER_LIST + "')") public ApiResponse> returnOptions(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable String deliveryNo) { @@ -48,6 +54,7 @@ public class ExceptionOrderController { } @PostMapping("/delivery-orders/{deliveryNo}/mark-return") + @PreAuthorize("hasAuthority('" + OverseasPermissions.DELIVERY_RETURN + "')") public ApiResponse markReturn(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, @PathVariable String deliveryNo, diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java b/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java index 76ae1b4bd..15c528dab 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java @@ -20,6 +20,9 @@ public final class OverseasPermissions { public static final String INVENTORY_EDIT = "platform:overseas-warehouse:inventory:edit"; public static final String INVENTORY_ADJUST = "platform:overseas-warehouse:inventory:adjust"; public static final String DELIVERY_LIST = "platform:overseas-warehouse:delivery:list"; + public static final String DELIVERY_RETURN = "platform:overseas-warehouse:delivery:return"; + public static final String DELIVERY_STATUS = "platform:overseas-warehouse:delivery:status"; + public static final String DISPATCH_LIST = "platform:overseas-warehouse:dispatch:list"; public static final String DISPATCH_EDIT = "platform:overseas-warehouse:dispatch:edit"; public static final String DISPATCH_CANCEL = "platform:overseas-warehouse:dispatch:cancel"; public static final String DISPATCH_TRANSFER_DELIVERY = @@ -27,6 +30,10 @@ public final class OverseasPermissions { public static final String OUTBOUND_LIST = "platform:overseas-warehouse:outbound:list"; public static final String OUTBOUND_CREATE = "platform:overseas-warehouse:outbound:create"; public static final String OUTBOUND_CANCEL = "platform:overseas-warehouse:outbound:cancel"; + public static final String EXCEPTION_ORDER_LIST = "platform:overseas-warehouse:exception-order:list"; + public static final String EXCEPTION_ORDER_CREATE = "platform:overseas-warehouse:exception-order:create"; + public static final String CUSTOMER_VISIT_LIST = "platform:overseas-warehouse:customer-visit:list"; + public static final String CUSTOMER_VISIT_EDIT = "platform:overseas-warehouse:customer-visit:edit"; public static final String MERCHANT_DELIVERY_LIST = "merchant:warehouse:delivery:list"; public static final String MERCHANT_DELIVERY_CREATE = "merchant:warehouse:delivery:create"; public static final String PURCHASE_LIST = "platform:overseas-business:purchase:list"; diff --git a/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml b/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml index 39b455819..d152f6325 100644 --- a/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml +++ b/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml @@ -365,7 +365,7 @@ paths: /api/platform/v1/last-leg/dispatches: get: summary: 分页查询排车单 - description: 权限 platform:overseas-warehouse:inbound-order:list;平台跨客户分页查询,前端不传 customerId。 + description: 权限 platform:overseas-warehouse:dispatch:list;平台跨客户分页查询,前端不传 customerId。 security: [{ bearerAuth: [] }] parameters: - { name: page, in: query, schema: { type: integer, minimum: 1, default: 1 } } @@ -379,7 +379,7 @@ paths: /api/platform/v1/last-leg/dispatches/{dispatchNo}: get: summary: 查询排车单详情 - description: 权限 platform:overseas-warehouse:inbound-order:list;平台按全局排车单号定位记录,并使用记录自身客户范围查询明细,前端不传 customerId。 + description: 权限 platform:overseas-warehouse:dispatch:list;列表权限包含详情只读;平台按全局排车单号定位记录,并使用记录自身客户范围查询明细,前端不传 customerId。 security: [{ bearerAuth: [] }] parameters: - { name: dispatchNo, in: path, required: true, schema: { type: string } } @@ -523,6 +523,95 @@ paths: parameters: [{ name: outboundNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/OutboundCancel' } } } } responses: { '200': { description: 取消成功或已取消 }, '404': { description: 出库单不存在 }, '409': { description: 出库已开始执行 } } + /api/platform/v1/last-leg/delivery-orders: + get: + summary: 分页查询平台派送单 + description: 权限 platform:overseas-warehouse:delivery:list;customerId 仅为可选平台筛选条件。 + security: [{ bearerAuth: [] }] + responses: { '200': { description: 派送单分页 } } + /api/platform/v1/last-leg/delivery-orders/{deliveryNo}: + get: + summary: 查询平台派送单详情 + description: 权限 platform:overseas-warehouse:delivery:list;列表权限包含详情只读。 + security: [{ bearerAuth: [] }] + parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] + responses: { '200': { description: 派送单详情 }, '404': { description: 派送单不存在 } } + /api/platform/v1/last-leg/exception-orders: + get: + summary: 分页查询异常订单 + description: 权限 platform:overseas-warehouse:exception-order:list。 + security: [{ bearerAuth: [] }] + responses: { '200': { description: 异常订单分页 } } + post: + summary: 创建异常订单 + description: 权限 platform:overseas-warehouse:exception-order:create。 + security: [{ bearerAuth: [] }] + requestBody: { required: true, content: { application/json: { schema: { type: object } } } } + responses: { '200': { description: 已创建异常订单 } } + /api/platform/v1/last-leg/exception-orders/resolve: + get: + summary: 解析异常订单关联关系 + description: 权限 platform:overseas-warehouse:exception-order:list;属于列表页只读辅助接口。 + security: [{ bearerAuth: [] }] + responses: { '200': { description: 关联关系 } } + /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/return-inbound-options: + get: + summary: 查询派送退回候选入仓单 + description: 权限 platform:overseas-warehouse:exception-order:list;属于异常订单列表只读辅助接口。 + security: [{ bearerAuth: [] }] + parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] + responses: { '200': { description: 退回候选入仓单 } } + /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/mark-return: + post: + summary: 将派送单标记为退回入仓 + description: 权限 platform:overseas-warehouse:delivery:return。 + security: [{ bearerAuth: [] }] + parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] + requestBody: { required: true, content: { application/json: { schema: { type: object } } } } + responses: { '200': { description: 已创建退回异常单 } } + /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/complete: + post: + summary: 标记派送完成并生成回访记录 + description: 权限 platform:overseas-warehouse:delivery:status。 + security: [{ bearerAuth: [] }] + parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] + responses: { '200': { description: 派送状态与回访记录 } } + /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/status: + put: + summary: 更新派送状态 + description: 权限 platform:overseas-warehouse:delivery:status。 + security: [{ bearerAuth: [] }] + parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] + requestBody: { required: true, content: { application/json: { schema: { type: object } } } } + responses: { '200': { description: 更新后的派送状态 } } + /api/platform/v1/last-leg/customer-visits: + get: + summary: 分页查询客户回访 + description: 权限 platform:overseas-warehouse:customer-visit:list。 + security: [{ bearerAuth: [] }] + responses: { '200': { description: 客户回访分页 } } + /api/platform/v1/last-leg/customer-visits/{visitId}: + get: + summary: 查询客户回访详情 + description: 权限 platform:overseas-warehouse:customer-visit:list;列表权限包含详情只读。 + security: [{ bearerAuth: [] }] + parameters: [{ name: visitId, in: path, required: true, schema: { type: integer, format: int64 } }] + responses: { '200': { description: 客户回访详情 } } + put: + summary: 保存客户回访 + description: 权限 platform:overseas-warehouse:customer-visit:edit。 + security: [{ bearerAuth: [] }] + parameters: [{ name: visitId, in: path, required: true, schema: { type: integer, format: int64 } }] + requestBody: { required: true, content: { application/json: { schema: { type: object } } } } + responses: { '200': { description: 已保存客户回访 } } + /api/platform/v1/last-leg/customer-visits/{visitId}/attachments: + post: + summary: 上传客户回访附件 + description: 权限 platform:overseas-warehouse:customer-visit:edit。 + security: [{ bearerAuth: [] }] + parameters: [{ name: visitId, in: path, required: true, schema: { type: integer, format: int64 } }] + requestBody: { required: true, content: { multipart/form-data: { schema: { type: object } } } } + responses: { '200': { description: 已上传附件 } } /api/platform/v1/last-leg/overseas-procurements: get: summary: 分页查询海外采购订单 diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryControllerTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryControllerTest.java index acf14950a..cd20a2fb0 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryControllerTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryControllerTest.java @@ -50,7 +50,7 @@ class DispatchQueryControllerTest { } @Test - void listAndDetailReuseInboundOrderListAuthority() throws Exception { + void listAndDetailUseDedicatedDispatchListAuthority() throws Exception { PreAuthorize page = DispatchQueryController.class .getMethod("page", AuthenticatedUser.class, DispatchRequests.Query.class) .getAnnotation(PreAuthorize.class); @@ -58,8 +58,8 @@ class DispatchQueryControllerTest { .getMethod("detail", AuthenticatedUser.class, String.class) .getAnnotation(PreAuthorize.class); - assertThat(page.value()).contains(OverseasPermissions.INBOUND_ORDER_LIST); - assertThat(detail.value()).contains(OverseasPermissions.INBOUND_ORDER_LIST); + assertThat(page.value()).isEqualTo("hasAuthority('" + OverseasPermissions.DISPATCH_LIST + "')"); + assertThat(detail.value()).isEqualTo("hasAuthority('" + OverseasPermissions.DISPATCH_LIST + "')"); } private static AuthenticatedUser platform() { diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/security/Phase5AdminPermissionContractTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/security/Phase5AdminPermissionContractTest.java new file mode 100644 index 000000000..ae844159c --- /dev/null +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/security/Phase5AdminPermissionContractTest.java @@ -0,0 +1,81 @@ +package com.baiyue.lastleg.security; + +import com.baiyue.lastleg.customervisit.controller.CustomerVisitController; +import com.baiyue.lastleg.exceptionorder.controller.ExceptionOrderController; +import org.junit.jupiter.api.Test; +import org.springframework.security.access.prepost.PreAuthorize; + +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class Phase5AdminPermissionContractTest { + @Test + void exceptionAndDeliveryReturnEndpointsUseIndependentAuthorities() { + Map permissions = permissions(ExceptionOrderController.class); + + assertEquals(authority(OverseasPermissions.EXCEPTION_ORDER_LIST), permissions.get("page")); + assertEquals(authority(OverseasPermissions.EXCEPTION_ORDER_LIST), permissions.get("resolve")); + assertEquals(authority(OverseasPermissions.EXCEPTION_ORDER_CREATE), permissions.get("create")); + assertEquals(authority(OverseasPermissions.EXCEPTION_ORDER_LIST), permissions.get("returnOptions")); + assertEquals(authority(OverseasPermissions.DELIVERY_RETURN), permissions.get("markReturn")); + } + + @Test + void customerVisitAndDeliveryStatusEndpointsUseIndependentAuthorities() { + Map permissions = permissions(CustomerVisitController.class); + + assertEquals(authority(OverseasPermissions.CUSTOMER_VISIT_LIST), permissions.get("page")); + assertEquals(authority(OverseasPermissions.CUSTOMER_VISIT_LIST), permissions.get("detail")); + assertEquals(authority(OverseasPermissions.CUSTOMER_VISIT_EDIT), permissions.get("save")); + assertEquals(authority(OverseasPermissions.CUSTOMER_VISIT_EDIT), permissions.get("upload")); + assertEquals(authority(OverseasPermissions.DELIVERY_STATUS), permissions.get("completeDelivery")); + assertEquals(authority(OverseasPermissions.DELIVERY_STATUS), permissions.get("updateDeliveryStatus")); + } + + @Test + void openApiPublishesEveryFrozenPhase5AdminAuthorityAndPath() throws Exception { + String yaml = Files.readString(Path.of("src/main/resources/openapi/overseas-business-v1.yaml"), + StandardCharsets.UTF_8); + + for (String permission : new String[] { + OverseasPermissions.DISPATCH_LIST, + OverseasPermissions.EXCEPTION_ORDER_LIST, + OverseasPermissions.EXCEPTION_ORDER_CREATE, + OverseasPermissions.DELIVERY_RETURN, + OverseasPermissions.DELIVERY_STATUS, + OverseasPermissions.CUSTOMER_VISIT_LIST, + OverseasPermissions.CUSTOMER_VISIT_EDIT + }) { + assertTrue(yaml.contains(permission), permission); + } + for (String path : new String[] { + "/api/platform/v1/last-leg/dispatches:", + "/api/platform/v1/last-leg/exception-orders:", + "/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/mark-return:", + "/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/status:", + "/api/platform/v1/last-leg/customer-visits:", + "/api/platform/v1/last-leg/customer-visits/{visitId}:" + }) { + assertTrue(yaml.contains(path), path); + } + } + + private static Map permissions(Class controller) { + return Arrays.stream(controller.getDeclaredMethods()) + .filter(method -> method.isAnnotationPresent(PreAuthorize.class)) + .collect(Collectors.toMap(Method::getName, + method -> method.getAnnotation(PreAuthorize.class).value())); + } + + private static String authority(String permission) { + return "hasAuthority('" + permission + "')"; + } +}