This commit is contained in:
2026-08-13 11:57:33 +08:00
parent 5a48992d78
commit 16dc03a2e2
102 changed files with 3656 additions and 120 deletions
@@ -69,7 +69,7 @@ public class PlatformTenantController {
}
@GetMapping("/tenants/{tenantId:\\d+}")
@PreAuthorize("hasAuthority('platform:customer:view')")
@PreAuthorize("hasAnyAuthority('platform:customer:list','platform:customer:view')")
@Operation(summary = "查询企业客户档案", description = "返回企业基础资料、销售负责人、账期、注册地址以及入驻和审批时间。")
public ApiResponse<TenantResponse> tenant(@PathVariable long tenantId,
@AuthenticationPrincipal AuthenticatedUser user) {
@@ -89,7 +89,7 @@ public class PlatformTenantController {
}
@GetMapping("/tenants/{tenantId:\\d+}/members")
@PreAuthorize("hasAuthority('platform:customer:view')")
@PreAuthorize("hasAnyAuthority('platform:customer:list','platform:customer:view')")
@Operation(summary = "查询企业客户成员及账号", description = "平台只读查询指定企业的全部成员,包含 OWNER 企业管理员,并返回登录账号。")
public ApiResponse<List<PlatformCustomerMemberDtos.MemberResponse>> members(
@PathVariable long tenantId, @AuthenticationPrincipal AuthenticatedUser user) {
@@ -115,7 +115,7 @@ public class ProfileResourceController {
}
@GetMapping("/api/platform/v1/iam/tenants/{tenantId}/qualifications")
@PreAuthorize("hasAuthority('platform:customer:view')")
@PreAuthorize("hasAnyAuthority('platform:customer:list','platform:customer:view')")
@Operation(summary = "查询企业客户资质", description = "只读查询企业客户资质元数据,不授予审核能力。")
public ApiResponse<List<IamTenantQualification>> platformQualifications(
@PathVariable long tenantId, @AuthenticationPrincipal AuthenticatedUser user) {
@@ -124,7 +124,7 @@ public class ProfileResourceController {
}
@GetMapping("/api/platform/v1/iam/tenants/{tenantId}/addresses")
@PreAuthorize("hasAuthority('platform:customer:view')")
@PreAuthorize("hasAnyAuthority('platform:customer:list','platform:customer:view')")
@Operation(summary = "查询企业客户地址", description = "只读查询企业客户地址,不开放平台端写入。")
public ApiResponse<List<IamTenantAddress>> platformAddresses(
@PathVariable long tenantId, @AuthenticationPrincipal AuthenticatedUser user) {
@@ -31,9 +31,9 @@ public class NotificationInboxController {
public ApiResponse<UnreadCountResponse> unread(@PathVariable String app,@AuthenticationPrincipal AuthenticatedUser user){String code=guard(app,user);return ApiResponse.success(service.unread(user.tenantId(),user.membershipId(),code));}
@GetMapping("/{id:\\d+}") @PreAuthorize("hasAuthority(#app + ':notification:view')")
public ApiResponse<NotificationDetail> detail(@PathVariable String app,@PathVariable Long id,@AuthenticationPrincipal AuthenticatedUser user){String code=guard(app,user);return ApiResponse.success(service.detail(user.tenantId(),user.membershipId(),code,id));}
@PutMapping("/{id:\\d+}/read") @PreAuthorize("hasAuthority(#app + ':notification:view')")
@PutMapping("/{id:\\d+}/read") @PreAuthorize("hasAuthority(#app + ':notification:read')")
public ApiResponse<NotificationDetail> read(@PathVariable String app,@PathVariable Long id,@AuthenticationPrincipal AuthenticatedUser user){String code=guard(app,user);return ApiResponse.success(service.read(user.tenantId(),user.membershipId(),code,id));}
@PutMapping("/read-all") @PreAuthorize("hasAuthority(#app + ':notification:view')")
@PutMapping("/read-all") @PreAuthorize("hasAuthority(#app + ':notification:read-all')")
public ApiResponse<ReadAllResponse> readAll(@PathVariable String app,@AuthenticationPrincipal AuthenticatedUser user){String code=guard(app,user);return ApiResponse.success(service.readAll(user.tenantId(),user.membershipId(),code));}
private String guard(String app,AuthenticatedUser user){String code=switch(app){case"platform"->"PLATFORM";case"merchant"->"MERCHANT";default->throw new BizException(ResultCode.BAD_REQUEST,"不支持的应用端");};TenantGuard.tenant(user,code);return code;}
}
@@ -0,0 +1,79 @@
-- Admin prototype-aligned page menus and page permissions.
-- Permission codes remain stable; this migration only adds page-level MENU resources,
-- reparents existing finance action resources, and retires unsupported fee create/delete actions.
USE baiyue_iam;
SET NAMES utf8mb4;
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
(5102041,0,'PLATFORM','MENU',5102000,'platform:firstleg:inbound:measure:view','订单测量','/inbounds/measurements','GET',30,'ACTIVE',1,0),
(5102051,0,'PLATFORM','MENU',5102000,'firstleg:inbound:measurement-review','测量数据审核','/inbounds/measurement-reviews','GET',40,'ACTIVE',1,0),
(5103070,0,'PLATFORM','API',5103010,'platform:domestic-container:list','整柜业务','/api/platform/v1/domestic-containers','GET',70,'ACTIVE',1,0),
(5103071,0,'PLATFORM','BUTTON',5103070,'platform:domestic-container:inbound:create','新建整柜入库单',NULL,'POST',10,'ACTIVE',1,0),
(5103072,0,'PLATFORM','BUTTON',5103070,'platform:domestic-container:outbound:create','新建整柜出库单',NULL,'POST',20,'ACTIVE',1,0),
(5103080,0,'PLATFORM','MENU',5103000,'platform:supplier:list','供应商列表','/suppliers','GET',80,'ACTIVE',1,0),
(5103081,0,'PLATFORM','BUTTON',5103080,'platform:supplier:create','新增供应商',NULL,'POST',10,'ACTIVE',1,0),
(5103082,0,'PLATFORM','BUTTON',5103080,'platform:supplier:edit','编辑供应商',NULL,'PUT',20,'ACTIVE',1,0),
(5103083,0,'PLATFORM','BUTTON',5103080,'platform:supplier:status','启停供应商',NULL,'PATCH',30,'ACTIVE',1,0),
(5105040,0,'PLATFORM','MENU',5105000,'platform:finance:customer-account:list','客户账户','/finance/customer-accounts','GET',10,'ACTIVE',1,0),
(5105041,0,'PLATFORM','MENU',5105000,'platform:finance:customer-arap:list','客户应收应付','/finance/customer-arap','GET',20,'ACTIVE',1,0),
(5105042,0,'PLATFORM','MENU',5105000,'platform:finance:customer-statement:list','客户对账单','/finance/customer-statements','GET',30,'ACTIVE',1,0),
(5105043,0,'PLATFORM','MENU',5105000,'platform:finance:settlement-ar:list','结算单应收','/finance/settlement-receivables','GET',40,'ACTIVE',1,0),
(5105044,0,'PLATFORM','MENU',5105000,'platform:finance:settlement-ap:list','结算单应付','/finance/settlement-payables','GET',50,'ACTIVE',1,0)
ON DUPLICATE KEY UPDATE
permission_type=VALUES(permission_type), parent_id=VALUES(parent_id),
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;
UPDATE iam_permission
SET status='INACTIVE', deleted=1
WHERE tenant_id=0 AND app_code='PLATFORM'
AND permission_code IN ('platform:overseas-storage-fee:create','platform:overseas-storage-fee:delete');
INSERT IGNORE INTO iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, r.id, p.id, CURRENT_TIMESTAMP(3)
FROM iam_role r
JOIN iam_permission p ON p.tenant_id=0 AND p.app_code='PLATFORM'
WHERE r.tenant_id=0 AND r.app_code='PLATFORM' AND r.role_code='PLATFORM_ADMIN'
AND p.permission_code IN (
'platform:finance:customer-account:list','platform:finance:customer-arap:list',
'platform:finance:customer-statement:list','platform:finance:settlement-ar:list',
'platform:finance:settlement-ap:list','platform:firstleg:inbound:measure:view',
'firstleg:inbound:measurement-review','platform:supplier:list',
'platform:supplier:create','platform:supplier:edit','platform:supplier:status',
'platform:domestic-container:list','platform:domestic-container:inbound:create',
'platform:domestic-container:outbound:create');
UPDATE iam_permission p
JOIN (SELECT 'platform:firstleg:inbound:measure:edit' code, 5102041 parent_id UNION ALL
SELECT 'platform:firstleg:inbound:measure:submit', 5102041 UNION ALL
SELECT 'platform:firstleg:inbound:measure:manual-entry', 5102041 UNION ALL
SELECT 'platform:firstleg:inbound:weight:edit', 5102041 UNION ALL
SELECT 'platform:firstleg:inbound:weight:confirm', 5102041 UNION ALL
SELECT 'firstleg:inbound:measurement-review-history', 5102051 UNION ALL
SELECT 'firstleg:inbound:exception-release', 5102051) mapping
ON mapping.code=p.permission_code
SET p.parent_id=mapping.parent_id
WHERE p.tenant_id=0 AND p.app_code='PLATFORM';
UPDATE iam_permission p
JOIN (SELECT 'platform:finance:account:view' code, 5105040 parent_id UNION ALL
SELECT 'platform:finance:fee-source:view', 5105041 UNION ALL
SELECT 'platform:finance:fee-source:review', 5105041 UNION ALL
SELECT 'platform:finance:fee-source:settlement', 5105041 UNION ALL
SELECT 'platform:finance:reconciliation:create', 5105042 UNION ALL
SELECT 'platform:finance:reconciliation:review', 5105042 UNION ALL
SELECT 'platform:finance:reconciliation:issue', 5105042 UNION ALL
SELECT 'platform:finance:reconciliation:adjust', 5105042 UNION ALL
SELECT 'platform:finance:reconciliation:void', 5105042 UNION ALL
SELECT 'platform:finance:settlement-ar:create', 5105043 UNION ALL
SELECT 'platform:finance:settlement-ar:view', 5105043 UNION ALL
SELECT 'platform:finance:settlement-ap:create', 5105044 UNION ALL
SELECT 'platform:finance:settlement-ap:view', 5105044 UNION ALL
SELECT 'platform:finance:payment:create', 5105044) mapping
ON mapping.code=p.permission_code
SET p.parent_id=mapping.parent_id
WHERE p.tenant_id=0 AND p.app_code='PLATFORM' AND p.permission_type='BUTTON';
@@ -0,0 +1,61 @@
USE baiyue_iam;
SET NAMES utf8mb4;
DROP PROCEDURE IF EXISTS migrate_domestic_container_permissions;
DELIMITER $$
CREATE PROCEDURE migrate_domestic_container_permissions()
BEGIN
IF EXISTS (
SELECT 1 FROM iam_permission
WHERE (id = 5103070 AND permission_code <> 'platform:domestic-container:list')
OR (id = 5103071 AND permission_code <> 'platform:domestic-container:inbound:create')
OR (id = 5103072 AND permission_code <> 'platform:domestic-container:outbound:create')
OR (permission_code = 'platform:domestic-container:list' AND id <> 5103070)
OR (permission_code = 'platform:domestic-container:inbound:create' AND id <> 5103071)
OR (permission_code = 'platform:domestic-container:outbound:create' AND id <> 5103072)
) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'domestic container permission id/code conflict';
END IF;
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
(5103070,0,'PLATFORM','API',5103010,'platform:domestic-container:list',
'查看国内整柜业务','/api/platform/v1/domestic-containers','GET',40,'ACTIVE',1,0),
(5103071,0,'PLATFORM','BUTTON',5103070,'platform:domestic-container:inbound:create',
'新建整柜入库单','/api/platform/v1/domestic-containers/inbounds','POST',10,'ACTIVE',1,0),
(5103072,0,'PLATFORM','BUTTON',5103070,'platform:domestic-container:outbound:create',
'新建整柜出库单','/api/platform/v1/domestic-containers/outbounds','POST',20,'ACTIVE',1,0)
ON DUPLICATE KEY UPDATE
permission_type=VALUES(permission_type), parent_id=VALUES(parent_id),
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 iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, r.id, p.id, CURRENT_TIMESTAMP(3)
FROM iam_role r
JOIN iam_permission p ON p.tenant_id=0 AND p.app_code='PLATFORM'
WHERE r.tenant_id=0 AND r.app_code='PLATFORM' AND r.role_code='PLATFORM_ADMIN'
AND r.status='ACTIVE' AND r.deleted=0
AND p.permission_code IN ('platform:domestic-container:list',
'platform:domestic-container:inbound:create','platform:domestic-container:outbound:create');
IF (SELECT COUNT(*) FROM iam_permission WHERE tenant_id=0 AND app_code='PLATFORM'
AND status='ACTIVE' AND built_in=1 AND deleted=0
AND permission_code IN ('platform:domestic-container:list',
'platform:domestic-container:inbound:create','platform:domestic-container:outbound:create')) <> 3 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'domestic container permission catalog is incomplete';
END IF;
IF (SELECT COUNT(*) FROM iam_role_permission rp
JOIN iam_role r ON r.id=rp.role_id AND r.tenant_id=rp.tenant_id
JOIN iam_permission p ON p.id=rp.permission_id AND p.tenant_id=rp.tenant_id
WHERE r.tenant_id=0 AND r.app_code='PLATFORM' AND r.role_code='PLATFORM_ADMIN'
AND p.permission_code IN ('platform:domestic-container:list',
'platform:domestic-container:inbound:create','platform:domestic-container:outbound:create')) <> 3 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'PLATFORM_ADMIN domestic container grant is incomplete';
END IF;
END$$
DELIMITER ;
CALL migrate_domestic_container_permissions();
DROP PROCEDURE IF EXISTS migrate_domestic_container_permissions;
@@ -58,24 +58,28 @@ VALUES
(5106000,0,'PLATFORM','MENU',0,'platform:notification','消息中心','/notifications',NULL,600,'ACTIVE',0),
(5106001,0,'PLATFORM','API',5106000,'platform:notification:view','查看消息','/api/platform/v1/notifications','GET',601,'ACTIVE',0),
(5106002,0,'PLATFORM','BUTTON',5106000,'platform:notification:create','发送消息','/api/platform/v1/notifications','POST',602,'ACTIVE',0),
(5106003,0,'PLATFORM','API',5106000,'platform:notification:template:list','查看消息模板','/api/platform/v1/notification-templates','GET',603,'ACTIVE',0),
(5106003,0,'PLATFORM','MENU',5106000,'platform:notification:template:list','模板管理','/notifications/templates','GET',603,'ACTIVE',0),
(5106004,0,'PLATFORM','BUTTON',5106000,'platform:notification:template:create','新增消息模板','/api/platform/v1/notification-templates','POST',604,'ACTIVE',0),
(5106005,0,'PLATFORM','BUTTON',5106000,'platform:notification:template:edit','编辑消息模板','/api/platform/v1/notification-templates/{id}','PUT',605,'ACTIVE',0),
(5106006,0,'PLATFORM','BUTTON',5106000,'platform:notification:template:status','变更模板状态','/api/platform/v1/notification-templates/{id}/status','PUT',606,'ACTIVE',0),
(5106007,0,'PLATFORM','API',5106000,'platform:notification:task:list','查看消息任务','/api/platform/v1/notification-tasks','GET',607,'ACTIVE',0),
(5106007,0,'PLATFORM','MENU',5106000,'platform:notification:task:list','消息管理','/notifications/messages','GET',607,'ACTIVE',0),
(5106008,0,'PLATFORM','BUTTON',5106000,'platform:notification:task:cancel','取消消息任务','/api/platform/v1/notification-tasks/{id}/cancel','PUT',608,'ACTIVE',0),
(5106009,0,'PLATFORM','BUTTON',5106000,'platform:notification:task:retry','重试消息任务','/api/platform/v1/notification-tasks/{id}/retry','PUT',609,'ACTIVE',0)
(5106009,0,'PLATFORM','BUTTON',5106000,'platform:notification:task:retry','重试消息任务','/api/platform/v1/notification-tasks/{id}/retry','PUT',609,'ACTIVE',0),
(5106011,0,'PLATFORM','BUTTON',5106001,'platform:notification:read','标记消息已读','/api/platform/v1/notifications/{id}/read','PUT',610,'ACTIVE',0),
(5106012,0,'PLATFORM','BUTTON',5106001,'platform:notification:read-all','全部标记已读','/api/platform/v1/notifications/read-all','PUT',611,'ACTIVE',0)
ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name), route_path=VALUES(route_path), http_method=VALUES(http_method), status='ACTIVE', deleted=0;
INSERT INTO iam_permission (id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, route_path, http_method, sort_no, status, deleted)
VALUES (5106010, 0, 'MERCHANT', 'API', 0, 'merchant:notification:view', '查看我的消息',
'/api/merchant/v1/notifications', 'GET', 900, 'ACTIVE', 0)
VALUES
(5106010,0,'MERCHANT','API',0,'merchant:notification:view','查看我的消息','/api/merchant/v1/notifications','GET',900,'ACTIVE',0),
(5106013,0,'MERCHANT','BUTTON',5106010,'merchant:notification:read','标记消息已读','/api/merchant/v1/notifications/{id}/read','PUT',901,'ACTIVE',0),
(5106014,0,'MERCHANT','BUTTON',5106010,'merchant:notification:read-all','全部标记已读','/api/merchant/v1/notifications/read-all','PUT',902,'ACTIVE',0)
ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name), route_path=VALUES(route_path), status='ACTIVE', deleted=0;
INSERT IGNORE INTO iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, r.id, p.id, CURRENT_TIMESTAMP(3)
FROM iam_permission p JOIN iam_role r ON r.tenant_id=0 AND r.app_code='MERCHANT' AND r.status='ACTIVE'
WHERE p.tenant_id=0 AND p.permission_code='merchant:notification:view' AND r.role_code='MERCHANT_OWNER';
WHERE p.tenant_id=0 AND p.permission_code IN ('merchant:notification:view','merchant:notification:read','merchant:notification:read-all') AND r.role_code='MERCHANT_OWNER';
INSERT IGNORE INTO iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, r.id, p.id, CURRENT_TIMESTAMP(3)
@@ -0,0 +1,46 @@
-- 平台供应商权限资源及 PLATFORM_ADMIN 默认授权;可重复执行。
USE baiyue_iam;
SET NAMES utf8mb4;
DROP PROCEDURE IF EXISTS guard_platform_supplier_permission_ids;
DELIMITER $$
CREATE PROCEDURE guard_platform_supplier_permission_ids()
BEGIN
IF EXISTS (SELECT 1 FROM iam_permission WHERE id BETWEEN 5103080 AND 5103083 AND permission_code <> CASE id WHEN 5103080 THEN 'platform:supplier:list' WHEN 5103081 THEN 'platform:supplier:create' WHEN 5103082 THEN 'platform:supplier:edit' WHEN 5103083 THEN 'platform:supplier:status' END)
OR EXISTS (SELECT 1 FROM iam_permission WHERE permission_code IN ('platform:supplier:list','platform:supplier:create','platform:supplier:edit','platform:supplier:status') AND id NOT BETWEEN 5103080 AND 5103083) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='供应商权限固定ID或权限码已被其他语义占用';
END IF;
END$$
DELIMITER ;
CALL guard_platform_supplier_permission_ids();
DROP PROCEDURE guard_platform_supplier_permission_ids;
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
(5103080,0,'PLATFORM','MENU',5103000,'platform:supplier:list','供应商列表','/suppliers','GET',80,'ACTIVE',1,0),
(5103081,0,'PLATFORM','BUTTON',5103080,'platform:supplier:create','新增供应商',NULL,'POST',10,'ACTIVE',1,0),
(5103082,0,'PLATFORM','BUTTON',5103080,'platform:supplier:edit','编辑供应商',NULL,'PUT',20,'ACTIVE',1,0),
(5103083,0,'PLATFORM','BUTTON',5103080,'platform:supplier:status','启停供应商',NULL,'PATCH',30,'ACTIVE',1,0)
ON DUPLICATE KEY UPDATE permission_type=VALUES(permission_type),parent_id=VALUES(parent_id),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 iam_role_permission (tenant_id,role_id,permission_id,created_at)
SELECT 0,r.id,p.id,CURRENT_TIMESTAMP(3)
FROM iam_role r JOIN iam_permission p ON p.tenant_id=0 AND p.app_code='PLATFORM'
WHERE r.tenant_id=0 AND r.app_code='PLATFORM' AND r.role_code='PLATFORM_ADMIN' AND r.status='ACTIVE' AND r.deleted=0
AND p.permission_code IN ('platform:supplier:list','platform:supplier:create','platform:supplier:edit','platform:supplier:status');
DROP PROCEDURE IF EXISTS assert_platform_supplier_permissions;
DELIMITER $$
CREATE PROCEDURE assert_platform_supplier_permissions()
BEGIN
IF (SELECT COUNT(*) FROM iam_permission WHERE tenant_id=0 AND app_code='PLATFORM' AND status='ACTIVE' AND deleted=0 AND permission_code IN ('platform:supplier:list','platform:supplier:create','platform:supplier:edit','platform:supplier:status')) <> 4 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='供应商权限资源初始化不完整';
END IF;
IF (SELECT COUNT(*) FROM iam_role_permission rp JOIN iam_role r ON r.id=rp.role_id AND r.tenant_id=rp.tenant_id JOIN iam_permission p ON p.id=rp.permission_id AND p.tenant_id=rp.tenant_id WHERE r.role_code='PLATFORM_ADMIN' AND p.permission_code IN ('platform:supplier:list','platform:supplier:create','platform:supplier:edit','platform:supplier:status')) <> 4 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='PLATFORM_ADMIN供应商权限授权不完整';
END IF;
END$$
DELIMITER ;
CALL assert_platform_supplier_permissions();
DROP PROCEDURE assert_platform_supplier_permissions;
@@ -35,12 +35,14 @@ paths:
put:
tags: [Notification inbox]
summary: Mark one message as read (idempotent)
description: Requires {app}:notification:read.
parameters: [{$ref: '#/components/parameters/AppPath'}, {$ref: '#/components/parameters/IdPath'}]
responses: {'200': {$ref: '#/components/responses/InboxDetail'}}
/{app}/v1/notifications/read-all:
put:
tags: [Notification inbox]
summary: Mark all current-user messages as read (idempotent)
description: Requires {app}:notification:read-all.
parameters: [{$ref: '#/components/parameters/AppPath'}]
responses: {'200': {$ref: '#/components/responses/ReadAll'}}
/platform/v1/notifications:
@@ -0,0 +1,69 @@
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 static org.assertj.core.api.Assertions.assertThat;
class AdminPrototypeMenuPermissionSqlContractTest {
private static final String[] FINANCE_MENUS = {
"platform:finance:customer-account:list", "platform:finance:customer-arap:list",
"platform:finance:customer-statement:list", "platform:finance:settlement-ar:list",
"platform:finance:settlement-ap:list"
};
@Test
void declaresFinancePageMenusAndReparentsActions() throws Exception {
String sql = new ClassPathResource("db/admin-prototype-menu-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
for (int index = 0; index < FINANCE_MENUS.length; index++) {
assertThat(sql).contains("(" + (5105040 + index) + ",0,'PLATFORM','MENU',5105000,'" + FINANCE_MENUS[index] + "'");
}
assertThat(sql)
.contains("'platform:finance:account:view' code, 5105040 parent_id")
.contains("'platform:finance:fee-source:view', 5105041")
.contains("'platform:finance:reconciliation:create', 5105042")
.contains("'platform:finance:settlement-ar:create', 5105043")
.contains("'platform:finance:settlement-ap:create', 5105044")
.contains("'platform:finance:payment:create', 5105044)")
.contains("role_code='PLATFORM_ADMIN'");
}
@Test
void retiresUnsupportedOverseasFeeCreateAndDelete() throws Exception {
String sql = new ClassPathResource("db/admin-prototype-menu-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql).contains("status='INACTIVE', deleted=1")
.contains("'platform:overseas-storage-fee:create','platform:overseas-storage-fee:delete'");
String unified = Files.readString(resolveUnifiedSql(), StandardCharsets.UTF_8);
assertThat(unified).contains("<> 2")
.contains("platform:overseas-storage-fee:list', 'platform:overseas-storage-fee:create'");
}
@Test
void keepsDomesticContainerAndSupplierPermissionIdsDisjoint() throws Exception {
String sql = new ClassPathResource("db/admin-prototype-menu-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql)
.contains("(5103070,0,'PLATFORM','API',5103010,'platform:domestic-container:list'")
.contains("(5103071,0,'PLATFORM','BUTTON',5103070,'platform:domestic-container:inbound:create'")
.contains("(5103072,0,'PLATFORM','BUTTON',5103070,'platform:domestic-container:outbound:create'")
.contains("(5103080,0,'PLATFORM','MENU',5103000,'platform:supplier:list'")
.contains("(5103081,0,'PLATFORM','BUTTON',5103080,'platform:supplier:create'")
.contains("(5103082,0,'PLATFORM','BUTTON',5103080,'platform:supplier:edit'")
.contains("(5103083,0,'PLATFORM','BUTTON',5103080,'platform:supplier:status'")
.doesNotContain("platform:supplier:view");
}
private static Path resolveUnifiedSql() {
Path direct = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
return Files.exists(direct) ? direct : Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql");
}
}
@@ -0,0 +1,36 @@
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 static org.assertj.core.api.Assertions.assertThat;
class DomesticContainerPermissionSqlContractTest {
@Test
void registersAndGrantsDedicatedPermissionsIdempotently() throws Exception {
String sql = new ClassPathResource("db/domestic-container-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql).contains("5103070", "5103071", "5103072",
"platform:domestic-container:list", "platform:domestic-container:inbound:create",
"platform:domestic-container:outbound:create", "ON DUPLICATE KEY UPDATE",
"INSERT IGNORE INTO iam_role_permission", "role_code='PLATFORM_ADMIN'", "<> 3");
assertThat(sql).contains("permission id/code conflict", "permission catalog is incomplete",
"PLATFORM_ADMIN domestic container grant is incomplete");
}
@Test
void reservesFinalIdsAndRejectsSupplierReuse() throws Exception {
String sql = new ClassPathResource("db/domestic-container-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql).contains("(5103070,0,'PLATFORM','API'", "(5103071,0,'PLATFORM','BUTTON',5103070",
"(5103072,0,'PLATFORM','BUTTON',5103070");
Path supplier = Path.of("src/main/resources/db/platform-supplier-permissions.sql");
if (!Files.exists(supplier)) supplier = Path.of("iam/src/main/resources/db/platform-supplier-permissions.sql");
if (Files.exists(supplier)) {
String supplierSql = Files.readString(supplier, StandardCharsets.UTF_8);
assertThat(supplierSql).doesNotContain("5103070", "5103071", "5103072");
}
}
}
@@ -0,0 +1,18 @@
package com.baiyue.iam.repository;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
class PlatformSupplierPermissionSqlContractTest {
@Test void registersFourSupplierPermissionsAndGrantsPlatformAdmin() throws Exception {
String sql = new ClassPathResource("db/platform-supplier-permissions.sql").getContentAsString(StandardCharsets.UTF_8);
assertThat(sql).contains("5103080", "5103081", "5103082", "5103083",
"platform:supplier:list", "platform:supplier:create",
"platform:supplier:edit", "platform:supplier:status", "role_code='PLATFORM_ADMIN'",
"ON DUPLICATE KEY UPDATE", "INSERT IGNORE INTO iam_role_permission",
"guard_platform_supplier_permission_ids", "SIGNAL SQLSTATE '45000'",
"assert_platform_supplier_permissions");
}
}