1 Commits

Author SHA1 Message Date
6daa444c5e docs(finance): add finance permission seed scripts 2026-03-04 17:06:57 +08:00
3 changed files with 647 additions and 0 deletions

View File

@@ -13,6 +13,8 @@
- `seed_tenant_customer_permissions.sql`:补齐租户端客户管理权限码、菜单权限与角色授权映射(可重复执行)。
- `seed_tenant_member_permissions.sql`:补齐租户端会员管理权限码、菜单权限与角色授权映射(可重复执行)。
- `seed_tenant_member_stored_card_permissions.sql`:补齐租户端会员储值卡权限码、菜单权限与角色授权映射(可重复执行)。
- `seed_tenant_finance_permissions.sql`:补齐租户端财务中心交易流水与到账查询权限码、菜单权限与角色授权映射(可重复执行)。
- `seed_tenant_finance_invoice_permissions.sql`:补齐租户端财务中心发票管理权限码、菜单权限与角色授权映射(可重复执行)。
## 前置条件
@@ -143,6 +145,20 @@ psql -h <host> -p <port> -U identity_user -d takeout_identity_db -f .\seed_tenan
2. 更新会员储值卡菜单 (`/member/stored-card/index`) 的 `RequiredPermissions``MetaPermissions``AuthListJson`
3. 按订单列表权限映射补齐会员储值卡权限的角色模板与租户角色授权。
## 财务中心交易流水/到账权限补齐
`takeout_identity_db` 执行:
```powershell
psql -h <host> -p <port> -U identity_user -d takeout_identity_db -f .\seed_tenant_finance_permissions.sql
```
脚本会完成:
1. 新增/修正 `tenant:finance:transaction:*``tenant:finance:settlement:*` 权限码。
2. 更新财务中心菜单 `TransactionFlow` (`/finance/transaction/index`) 与 `SettlementQuery` (`/finance/settlement/index`) 的 `RequiredPermissions``MetaPermissions``AuthListJson`
3. 按旧财务权限(`income/statement`)映射补齐角色模板与租户角色授权。
## 常见问题
| 问题 | 处理方式 |

View File

@@ -0,0 +1,299 @@
-- 文件职责:补齐 Tenant 端财务中心发票管理权限与菜单权限绑定(可重复执行)。
-- 执行范围takeout_identity 数据库Portal=1Tenant 端)。
BEGIN;
-- 1) 新增/修正发票管理权限码
WITH invoice_permissions(code, name, sort_order) AS (
VALUES
('tenant:finance:invoice:view', '查看发票管理', 63),
('tenant:finance:invoice:issue', '发票开票', 64),
('tenant:finance:invoice:void', '发票作废', 65),
('tenant:finance:invoice:settings', '发票设置', 66)
),
missing AS (
SELECT
source.code,
source.name,
source.sort_order,
ROW_NUMBER() OVER (ORDER BY source.sort_order, source.code) AS rn
FROM invoice_permissions source
LEFT JOIN public.permissions existing
ON existing."Code" = source.code
WHERE existing."Id" IS NULL
),
base AS (
SELECT COALESCE(MAX("Id"), 820000000000000000) AS max_id
FROM public.permissions
),
parent AS (
SELECT COALESCE(
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:transaction:view'
LIMIT 1
),
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:order:list:view'
LIMIT 1
),
820000000000000004
) AS parent_id
)
INSERT INTO public.permissions
(
"Id", "Name", "Code", "Description", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy", "ParentId", "SortOrder", "Type", "Portal"
)
SELECT
base.max_id + missing.rn,
missing.name,
missing.code,
NULL,
NOW(),
NULL,
NULL,
NULL,
NULL,
NULL,
parent.parent_id,
missing.sort_order,
'leaf',
1
FROM missing
CROSS JOIN base
CROSS JOIN parent;
WITH invoice_permissions(code, name, sort_order) AS (
VALUES
('tenant:finance:invoice:view', '查看发票管理', 63),
('tenant:finance:invoice:issue', '发票开票', 64),
('tenant:finance:invoice:void', '发票作废', 65),
('tenant:finance:invoice:settings', '发票设置', 66)
),
parent AS (
SELECT COALESCE(
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:transaction:view'
LIMIT 1
),
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:order:list:view'
LIMIT 1
),
820000000000000004
) AS parent_id
)
UPDATE public.permissions target
SET
"Name" = source.name,
"ParentId" = parent.parent_id,
"SortOrder" = source.sort_order,
"Type" = 'leaf',
"Portal" = 1,
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW()
FROM invoice_permissions source
CROSS JOIN parent
WHERE target."Code" = source.code;
-- 2) 绑定发票管理菜单权限
UPDATE public.menu_definitions
SET
"RequiredPermissions" = 'tenant:finance:invoice:view',
"MetaPermissions" = 'tenant:finance:invoice:view,tenant:finance:invoice:issue,tenant:finance:invoice:void,tenant:finance:invoice:settings',
"AuthListJson" = '[{"title":"开票","authMark":"tenant:finance:invoice:issue"},{"title":"作废","authMark":"tenant:finance:invoice:void"},{"title":"设置","authMark":"tenant:finance:invoice:settings"}]',
"UpdatedAt" = NOW()
WHERE
"Portal" = 1
AND (
"Name" = 'InvoiceMgmt'
OR "Path" = 'invoice'
OR "Component" = '/finance/invoice/index'
);
-- 3) 给角色模板补齐发票管理权限(按交易流水权限映射)
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:transaction:view', 'tenant:finance:invoice:view'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:issue'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:void'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:settings')
),
candidates AS (
SELECT DISTINCT
source."RoleTemplateId",
mapping.target_code
FROM public.role_template_permissions source
INNER JOIN code_mapping mapping
ON mapping.source_code = source."PermissionCode"
WHERE source."DeletedAt" IS NULL
),
missing AS (
SELECT
candidate."RoleTemplateId",
candidate.target_code,
ROW_NUMBER() OVER (
ORDER BY candidate."RoleTemplateId", candidate.target_code
) AS rn
FROM candidates candidate
LEFT JOIN public.role_template_permissions existing
ON existing."RoleTemplateId" = candidate."RoleTemplateId"
AND existing."PermissionCode" = candidate.target_code
WHERE existing."Id" IS NULL
),
base AS (
SELECT COALESCE(MAX("Id"), 820000000000000000) AS max_id
FROM public.role_template_permissions
)
INSERT INTO public.role_template_permissions
(
"Id", "RoleTemplateId", "PermissionCode", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy"
)
SELECT
base.max_id + missing.rn,
missing."RoleTemplateId",
missing.target_code,
NOW(),
NULL,
NULL,
NULL,
NULL,
NULL
FROM missing
CROSS JOIN base;
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:transaction:view', 'tenant:finance:invoice:view'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:issue'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:void'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:settings')
)
UPDATE public.role_template_permissions target
SET
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW()
FROM public.role_template_permissions source
INNER JOIN code_mapping mapping
ON mapping.source_code = source."PermissionCode"
WHERE
source."RoleTemplateId" = target."RoleTemplateId"
AND target."PermissionCode" = mapping.target_code;
-- 4) 给租户角色补齐发票管理权限(按交易流水权限映射)
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:transaction:view', 'tenant:finance:invoice:view'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:issue'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:void'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:settings')
),
source_rows AS (
SELECT DISTINCT
source."RoleId",
source."TenantId",
source."Portal",
mapping.target_code
FROM public.role_permissions source
INNER JOIN public.permissions source_permission
ON source_permission."Id" = source."PermissionId"
INNER JOIN code_mapping mapping
ON mapping.source_code = source_permission."Code"
WHERE source."DeletedAt" IS NULL
AND source."Portal" = 1
),
candidates AS (
SELECT DISTINCT
source_row."RoleId",
source_row."TenantId",
source_row."Portal",
target_permission."Id" AS target_permission_id
FROM source_rows source_row
INNER JOIN public.permissions target_permission
ON target_permission."Code" = source_row.target_code
),
missing AS (
SELECT
candidate."RoleId",
candidate."TenantId",
candidate."Portal",
candidate.target_permission_id,
ROW_NUMBER() OVER (
ORDER BY candidate."TenantId", candidate."RoleId", candidate.target_permission_id
) AS rn
FROM candidates candidate
LEFT JOIN public.role_permissions existing
ON existing."RoleId" = candidate."RoleId"
AND existing."PermissionId" = candidate.target_permission_id
AND existing."Portal" = candidate."Portal"
AND (
(existing."TenantId" IS NULL AND candidate."TenantId" IS NULL)
OR existing."TenantId" = candidate."TenantId"
)
WHERE existing."Id" IS NULL
),
base AS (
SELECT COALESCE(MAX("Id"), 830000000000000000) AS max_id
FROM public.role_permissions
)
INSERT INTO public.role_permissions
(
"Id", "RoleId", "PermissionId", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy", "TenantId", "Portal"
)
SELECT
base.max_id + missing.rn,
missing."RoleId",
missing.target_permission_id,
NOW(),
NULL,
NULL,
NULL,
NULL,
NULL,
missing."TenantId",
missing."Portal"
FROM missing
CROSS JOIN base;
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:transaction:view', 'tenant:finance:invoice:view'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:issue'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:void'),
('tenant:finance:transaction:export', 'tenant:finance:invoice:settings')
)
UPDATE public.role_permissions target
SET
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW()
FROM public.role_permissions source
INNER JOIN public.permissions source_permission
ON source_permission."Id" = source."PermissionId"
INNER JOIN code_mapping mapping
ON mapping.source_code = source_permission."Code"
INNER JOIN public.permissions target_permission
ON target_permission."Code" = mapping.target_code
WHERE
source."Portal" = 1
AND target."Portal" = source."Portal"
AND target."RoleId" = source."RoleId"
AND target."PermissionId" = target_permission."Id"
AND (
(target."TenantId" IS NULL AND source."TenantId" IS NULL)
OR target."TenantId" = source."TenantId"
);
COMMIT;

View File

@@ -0,0 +1,332 @@
-- 文件职责:补齐 Tenant 端财务中心交易流水与到账查询权限、菜单绑定与角色授权映射(可重复执行)。
-- 执行范围takeout_identity 数据库Portal=1Tenant 端)。
BEGIN;
-- 1) 新增/修正财务中心交易流水与到账查询权限码
WITH finance_permissions(code, name, sort_order) AS (
VALUES
('tenant:finance:transaction:view', '查看交易流水', 51),
('tenant:finance:transaction:detail', '查看交易流水详情', 52),
('tenant:finance:transaction:export', '导出交易流水', 53),
('tenant:finance:settlement:view', '查看到账查询', 54),
('tenant:finance:settlement:export', '导出到账查询', 55)
),
missing AS (
SELECT
source.code,
source.name,
source.sort_order,
ROW_NUMBER() OVER (ORDER BY source.sort_order, source.code) AS rn
FROM finance_permissions source
LEFT JOIN public.permissions existing
ON existing."Code" = source.code
WHERE existing."Id" IS NULL
),
base AS (
SELECT COALESCE(MAX("Id"), 820000000000000000) AS max_id
FROM public.permissions
),
parent AS (
SELECT COALESCE(
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:income:view'
LIMIT 1
),
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:statement:view'
LIMIT 1
),
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:transaction:view'
LIMIT 1
),
820000000000000006
) AS parent_id
)
INSERT INTO public.permissions
(
"Id", "Name", "Code", "Description", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy", "ParentId", "SortOrder", "Type", "Portal"
)
SELECT
base.max_id + missing.rn,
missing.name,
missing.code,
NULL,
NOW(),
NULL,
NULL,
NULL,
NULL,
NULL,
parent.parent_id,
missing.sort_order,
'leaf',
1
FROM missing
CROSS JOIN base
CROSS JOIN parent;
WITH finance_permissions(code, name, sort_order) AS (
VALUES
('tenant:finance:transaction:view', '查看交易流水', 51),
('tenant:finance:transaction:detail', '查看交易流水详情', 52),
('tenant:finance:transaction:export', '导出交易流水', 53),
('tenant:finance:settlement:view', '查看到账查询', 54),
('tenant:finance:settlement:export', '导出到账查询', 55)
),
parent AS (
SELECT COALESCE(
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:income:view'
LIMIT 1
),
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:statement:view'
LIMIT 1
),
(
SELECT "ParentId"
FROM public.permissions
WHERE "Code" = 'tenant:finance:transaction:view'
LIMIT 1
),
820000000000000006
) AS parent_id
)
UPDATE public.permissions target
SET
"Name" = source.name,
"ParentId" = parent.parent_id,
"SortOrder" = source.sort_order,
"Type" = 'leaf',
"Portal" = 1,
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW()
FROM finance_permissions source
CROSS JOIN parent
WHERE target."Code" = source.code;
-- 2) 绑定交易流水菜单权限
UPDATE public.menu_definitions
SET
"RequiredPermissions" = 'tenant:finance:transaction:view',
"MetaPermissions" = 'tenant:finance:transaction:view,tenant:finance:transaction:detail,tenant:finance:transaction:export',
"AuthListJson" = '[{"title":"详情","authMark":"tenant:finance:transaction:detail"},{"title":"导出","authMark":"tenant:finance:transaction:export"}]',
"UpdatedAt" = NOW()
WHERE
"Portal" = 1
AND (
"Name" = 'TransactionFlow'
OR "Path" = 'transaction'
OR "Component" = '/finance/transaction/index'
);
-- 3) 绑定到账查询菜单权限
UPDATE public.menu_definitions
SET
"RequiredPermissions" = 'tenant:finance:settlement:view',
"MetaPermissions" = 'tenant:finance:settlement:view,tenant:finance:settlement:export',
"AuthListJson" = '[{"title":"导出","authMark":"tenant:finance:settlement:export"}]',
"UpdatedAt" = NOW()
WHERE
"Portal" = 1
AND (
"Name" = 'SettlementQuery'
OR "Path" = 'settlement'
OR "Component" = '/finance/settlement/index'
);
-- 4) 给角色模板补齐新权限(按旧财务权限映射)
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:income:view', 'tenant:finance:transaction:view'),
('tenant:finance:income:view', 'tenant:finance:transaction:detail'),
('tenant:finance:income:export', 'tenant:finance:transaction:export'),
('tenant:finance:statement:view', 'tenant:finance:settlement:view'),
('tenant:finance:statement:export', 'tenant:finance:settlement:export')
),
candidates AS (
SELECT DISTINCT
source."RoleTemplateId",
mapping.target_code
FROM public.role_template_permissions source
INNER JOIN code_mapping mapping
ON mapping.source_code = source."PermissionCode"
WHERE source."DeletedAt" IS NULL
),
missing AS (
SELECT
candidate."RoleTemplateId",
candidate.target_code,
ROW_NUMBER() OVER (
ORDER BY candidate."RoleTemplateId", candidate.target_code
) AS rn
FROM candidates candidate
LEFT JOIN public.role_template_permissions existing
ON existing."RoleTemplateId" = candidate."RoleTemplateId"
AND existing."PermissionCode" = candidate.target_code
WHERE existing."Id" IS NULL
),
base AS (
SELECT COALESCE(MAX("Id"), 820000000000000000) AS max_id
FROM public.role_template_permissions
)
INSERT INTO public.role_template_permissions
(
"Id", "RoleTemplateId", "PermissionCode", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy"
)
SELECT
base.max_id + missing.rn,
missing."RoleTemplateId",
missing.target_code,
NOW(),
NULL,
NULL,
NULL,
NULL,
NULL
FROM missing
CROSS JOIN base;
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:income:view', 'tenant:finance:transaction:view'),
('tenant:finance:income:view', 'tenant:finance:transaction:detail'),
('tenant:finance:income:export', 'tenant:finance:transaction:export'),
('tenant:finance:statement:view', 'tenant:finance:settlement:view'),
('tenant:finance:statement:export', 'tenant:finance:settlement:export')
)
UPDATE public.role_template_permissions target
SET
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW()
FROM public.role_template_permissions source
INNER JOIN code_mapping mapping
ON mapping.source_code = source."PermissionCode"
WHERE
source."RoleTemplateId" = target."RoleTemplateId"
AND target."PermissionCode" = mapping.target_code;
-- 5) 给租户角色补齐新权限(按旧财务权限映射)
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:income:view', 'tenant:finance:transaction:view'),
('tenant:finance:income:view', 'tenant:finance:transaction:detail'),
('tenant:finance:income:export', 'tenant:finance:transaction:export'),
('tenant:finance:statement:view', 'tenant:finance:settlement:view'),
('tenant:finance:statement:export', 'tenant:finance:settlement:export')
),
source_rows AS (
SELECT DISTINCT
source."RoleId",
source."TenantId",
source."Portal",
mapping.target_code
FROM public.role_permissions source
INNER JOIN public.permissions source_permission
ON source_permission."Id" = source."PermissionId"
INNER JOIN code_mapping mapping
ON mapping.source_code = source_permission."Code"
WHERE source."DeletedAt" IS NULL
AND source."Portal" = 1
),
candidates AS (
SELECT DISTINCT
source_row."RoleId",
source_row."TenantId",
source_row."Portal",
target_permission."Id" AS target_permission_id
FROM source_rows source_row
INNER JOIN public.permissions target_permission
ON target_permission."Code" = source_row.target_code
),
missing AS (
SELECT
candidate."RoleId",
candidate."TenantId",
candidate."Portal",
candidate.target_permission_id,
ROW_NUMBER() OVER (
ORDER BY candidate."TenantId", candidate."RoleId", candidate.target_permission_id
) AS rn
FROM candidates candidate
LEFT JOIN public.role_permissions existing
ON existing."RoleId" = candidate."RoleId"
AND existing."PermissionId" = candidate.target_permission_id
AND existing."Portal" = candidate."Portal"
AND (
(existing."TenantId" IS NULL AND candidate."TenantId" IS NULL)
OR existing."TenantId" = candidate."TenantId"
)
WHERE existing."Id" IS NULL
),
base AS (
SELECT COALESCE(MAX("Id"), 830000000000000000) AS max_id
FROM public.role_permissions
)
INSERT INTO public.role_permissions
(
"Id", "RoleId", "PermissionId", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy", "TenantId", "Portal"
)
SELECT
base.max_id + missing.rn,
missing."RoleId",
missing.target_permission_id,
NOW(),
NULL,
NULL,
NULL,
NULL,
NULL,
missing."TenantId",
missing."Portal"
FROM missing
CROSS JOIN base;
WITH code_mapping(source_code, target_code) AS (
VALUES
('tenant:finance:income:view', 'tenant:finance:transaction:view'),
('tenant:finance:income:view', 'tenant:finance:transaction:detail'),
('tenant:finance:income:export', 'tenant:finance:transaction:export'),
('tenant:finance:statement:view', 'tenant:finance:settlement:view'),
('tenant:finance:statement:export', 'tenant:finance:settlement:export')
)
UPDATE public.role_permissions target
SET
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW()
FROM public.role_permissions source
INNER JOIN public.permissions source_permission
ON source_permission."Id" = source."PermissionId"
INNER JOIN code_mapping mapping
ON mapping.source_code = source_permission."Code"
INNER JOIN public.permissions target_permission
ON target_permission."Code" = mapping.target_code
WHERE
source."Portal" = 1
AND target."Portal" = source."Portal"
AND target."RoleId" = source."RoleId"
AND target."PermissionId" = target_permission."Id"
AND (
(target."TenantId" IS NULL AND source."TenantId" IS NULL)
OR target."TenantId" = source."TenantId"
);
COMMIT;