权限:移除业务物理删除入口
This commit is contained in:
@@ -111,7 +111,7 @@ async def edit_master_customer(
|
||||
summary='兼容旧接口,固定拒绝,请使用测试数据批次清理',
|
||||
description='兼容旧接口,固定拒绝单条物理删除,请使用测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('master:customer:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('master:customer:list')],
|
||||
)
|
||||
@Log(title='客户管理', business_type=BusinessType.DELETE)
|
||||
async def delete_master_customer(
|
||||
|
||||
@@ -163,7 +163,7 @@ async def edit_business_inbound(
|
||||
summary='不支持单条物理删除,请通过测试数据批次清理',
|
||||
description='不支持单条物理删除,请通过测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('business:inbound:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('business:inbound:list')],
|
||||
)
|
||||
@Log(title='仓库入库', business_type=BusinessType.DELETE)
|
||||
async def delete_business_inbound(
|
||||
|
||||
@@ -109,7 +109,7 @@ async def edit_master_line(
|
||||
summary='兼容旧接口,固定拒绝,请使用测试数据批次清理',
|
||||
description='兼容旧接口,固定拒绝单条物理删除,请使用测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('master:line:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('master:line:list')],
|
||||
)
|
||||
@Log(title='生产线管理', business_type=BusinessType.DELETE)
|
||||
async def delete_master_line(
|
||||
|
||||
@@ -123,7 +123,7 @@ async def edit_master_pallet(
|
||||
summary='兼容旧接口,固定拒绝,请使用测试数据批次清理',
|
||||
description='兼容旧接口,固定拒绝单条物理删除,请使用测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('master:pallet:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('master:pallet:list')],
|
||||
)
|
||||
@Log(title='托盘管理', business_type=BusinessType.DELETE)
|
||||
async def delete_master_pallet(
|
||||
|
||||
@@ -180,7 +180,7 @@ async def edit_business_shipment(
|
||||
summary='不支持单条物理删除,请通过测试数据批次清理',
|
||||
description='不支持单条物理删除,请通过测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('business:shipment:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('business:shipment:list')],
|
||||
)
|
||||
@Log(title='整托发货', business_type=BusinessType.DELETE)
|
||||
async def delete_business_shipment(
|
||||
|
||||
@@ -161,7 +161,7 @@ async def edit_master_site(
|
||||
summary='兼容旧接口,固定拒绝,请使用测试数据批次清理',
|
||||
description='兼容旧接口,固定拒绝单条物理删除,请使用测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('master:site:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('master:site:list')],
|
||||
)
|
||||
@Log(title='客户现场管理', business_type=BusinessType.DELETE)
|
||||
async def delete_master_site(
|
||||
|
||||
@@ -111,7 +111,7 @@ async def edit_master_strain(
|
||||
summary='兼容旧接口,固定拒绝,请使用测试数据批次清理',
|
||||
description='兼容旧接口,固定拒绝单条物理删除,请使用测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('master:strain:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('master:strain:list')],
|
||||
)
|
||||
@Log(title='菌种管理', business_type=BusinessType.DELETE)
|
||||
async def delete_master_strain(
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Path, Request, Response
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from common.annotation.log_annotation import Log, RequestLogFieldRoot
|
||||
from common.aspect.db_seesion import DBSessionDependency
|
||||
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||
from common.enums import BusinessType
|
||||
from common.router import APIRouterPro
|
||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||
from module_business.entity.vo.test_batch_vo import (
|
||||
AdoptionExecuteRequestModel,
|
||||
AdoptionPreviewRequestModel,
|
||||
PurgeExecuteRequestModel,
|
||||
TestBatchCreateModel,
|
||||
TestBatchEditModel,
|
||||
TestBatchUserAssignModel,
|
||||
)
|
||||
from module_business.service.test_batch_adoption_service import TestBatchAdoptionService
|
||||
from module_business.service.test_batch_purge_service import TestBatchPurgeService
|
||||
from module_business.service.test_batch_service import TestBatchService
|
||||
from utils.response_util import ResponseUtil
|
||||
|
||||
test_batch_controller = APIRouterPro(
|
||||
prefix='/system/test-batch',
|
||||
tags=['系统管理-测试数据批次'],
|
||||
dependencies=[PreAuthDependency()],
|
||||
)
|
||||
|
||||
|
||||
@test_batch_controller.get('/options')
|
||||
async def list_test_batch_options(
|
||||
request: Request,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.list_available_batches(query_db, current_user)
|
||||
return ResponseUtil.success(data=result)
|
||||
|
||||
|
||||
@test_batch_controller.get(
|
||||
'/list',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:list')],
|
||||
)
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.OTHER,
|
||||
request_log_mode='summary',
|
||||
response_log_mode='summary',
|
||||
)
|
||||
async def list_test_batches(
|
||||
request: Request,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.list_batches(query_db, current_user)
|
||||
return ResponseUtil.success(rows=result, dict_content={'total': len(result)})
|
||||
|
||||
|
||||
@test_batch_controller.post(
|
||||
'',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:add')],
|
||||
)
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.INSERT,
|
||||
request_log_mode='summary',
|
||||
response_log_mode='summary',
|
||||
)
|
||||
async def create_test_batch(
|
||||
request: Request,
|
||||
command: TestBatchCreateModel,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.create_batch(query_db, command, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@test_batch_controller.put(
|
||||
'/{batch_id}',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:edit')],
|
||||
)
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.UPDATE,
|
||||
request_log_mode='summary',
|
||||
response_log_mode='summary',
|
||||
)
|
||||
async def edit_test_batch(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
command: TestBatchEditModel,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.edit_batch(query_db, batch_id, command, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@test_batch_controller.put(
|
||||
'/{batch_id}/users',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:assign')],
|
||||
)
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.GRANT,
|
||||
request_log_mode='summary',
|
||||
response_log_mode='summary',
|
||||
)
|
||||
async def assign_test_batch_users(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
command: TestBatchUserAssignModel,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.replace_users(query_db, batch_id, command, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@test_batch_controller.put(
|
||||
'/{batch_id}/close',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:close')],
|
||||
)
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.UPDATE,
|
||||
request_log_mode='summary',
|
||||
response_log_mode='summary',
|
||||
)
|
||||
async def close_test_batch(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.close_batch(query_db, batch_id, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@test_batch_controller.put(
|
||||
'/{batch_id}/reopen',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:close')],
|
||||
)
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.UPDATE,
|
||||
request_log_mode='summary',
|
||||
response_log_mode='summary',
|
||||
)
|
||||
async def reopen_test_batch(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.reopen_batch(query_db, batch_id, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.CLEAN,
|
||||
request_log_mode='include',
|
||||
request_include_fields=(RequestLogFieldRoot.PATH_PARAMS.field('batch_id'),),
|
||||
response_log_mode='summary',
|
||||
)
|
||||
@test_batch_controller.post(
|
||||
'/{batch_id}/adoption/preview',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:adopt')],
|
||||
)
|
||||
async def preview_test_batch_adoption(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
command: AdoptionPreviewRequestModel,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchAdoptionService.preview(query_db, batch_id, command, current_user)
|
||||
return ResponseUtil.success(data=result)
|
||||
|
||||
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.CLEAN,
|
||||
request_log_mode='include',
|
||||
request_include_fields=(RequestLogFieldRoot.PATH_PARAMS.field('batch_id'),),
|
||||
response_log_mode='summary',
|
||||
)
|
||||
@test_batch_controller.post(
|
||||
'/{batch_id}/adoption/execute',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:adopt')],
|
||||
)
|
||||
async def execute_test_batch_adoption(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
command: AdoptionExecuteRequestModel,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchAdoptionService.execute(query_db, batch_id, command, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.CLEAN,
|
||||
request_log_mode='include',
|
||||
request_include_fields=(RequestLogFieldRoot.PATH_PARAMS.field('batch_id'),),
|
||||
response_log_mode='summary',
|
||||
)
|
||||
@test_batch_controller.post(
|
||||
'/{batch_id}/purge/preview',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:purge')],
|
||||
)
|
||||
async def preview_test_batch_purge(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchPurgeService.preview(query_db, batch_id, current_user)
|
||||
return ResponseUtil.success(data=result)
|
||||
|
||||
|
||||
@Log(
|
||||
title='测试数据批次',
|
||||
business_type=BusinessType.CLEAN,
|
||||
request_log_mode='include',
|
||||
request_include_fields=(RequestLogFieldRoot.PATH_PARAMS.field('batch_id'),),
|
||||
response_log_mode='summary',
|
||||
)
|
||||
@test_batch_controller.post(
|
||||
'/{batch_id}/purge',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:purge')],
|
||||
)
|
||||
async def purge_test_batch(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
command: PurgeExecuteRequestModel,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchPurgeService.purge(query_db, batch_id, command, current_user)
|
||||
return ResponseUtil.success(msg=result.message)
|
||||
|
||||
|
||||
@test_batch_controller.get(
|
||||
'/{batch_id}',
|
||||
dependencies=[UserInterfaceAuthDependency('system:testbatch:query')],
|
||||
)
|
||||
async def get_test_batch(
|
||||
request: Request,
|
||||
batch_id: Annotated[int, Path(gt=0, description='测试批次ID')],
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await TestBatchService.get_batch_detail(query_db, batch_id, current_user)
|
||||
return ResponseUtil.success(data=result)
|
||||
@@ -166,7 +166,7 @@ async def edit_master_warehouse(
|
||||
summary='兼容旧接口,固定拒绝,请使用测试数据批次清理',
|
||||
description='兼容旧接口,固定拒绝单条物理删除,请使用测试数据批次清理',
|
||||
response_model=ResponseBaseModel,
|
||||
dependencies=[UserInterfaceAuthDependency('master:warehouse:remove')],
|
||||
dependencies=[UserInterfaceAuthDependency('master:warehouse:list')],
|
||||
)
|
||||
@Log(title='仓库管理', business_type=BusinessType.DELETE)
|
||||
async def delete_master_warehouse(
|
||||
|
||||
@@ -135,3 +135,25 @@ ALTER TABLE biz_pallet_event
|
||||
ADD INDEX idx_biz_pallet_event_test_batch_id (test_batch_id),
|
||||
ADD CONSTRAINT fk_biz_pallet_event_test_batch_id
|
||||
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
|
||||
|
||||
-- 菜单迁移:移除旧物理删除权限,加入测试数据批次管理菜单。
|
||||
-- 新菜单不自动授予普通角色;超级管理员由现有 admin 权限访问。
|
||||
START TRANSACTION;
|
||||
|
||||
DELETE FROM sys_role_menu
|
||||
WHERE menu_id IN (1068, 1072, 1076, 1081, 1085, 1090, 1095, 1102);
|
||||
|
||||
DELETE FROM sys_menu
|
||||
WHERE menu_id IN (1068, 1072, 1076, 1081, 1085, 1090, 1095, 1102);
|
||||
|
||||
INSERT INTO sys_menu VALUES
|
||||
(519, '测试数据批次', 1, '7', 'testBatch', 'system/testBatch/index', '', '', 1, 0, 'C', '0', '0', 'system:testbatch:list', '#', 'admin', SYSDATE(), '', NULL, '测试数据批次菜单'),
|
||||
(1109, '批次查询', 519, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:query', '#', 'admin', SYSDATE(), '', NULL, ''),
|
||||
(1110, '批次新增', 519, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:add', '#', 'admin', SYSDATE(), '', NULL, ''),
|
||||
(1111, '批次修改', 519, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:edit', '#', 'admin', SYSDATE(), '', NULL, ''),
|
||||
(1112, '批次授权', 519, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:assign', '#', 'admin', SYSDATE(), '', NULL, ''),
|
||||
(1113, '批次关闭', 519, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:close', '#', 'admin', SYSDATE(), '', NULL, ''),
|
||||
(1114, '数据纳入', 519, '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:adopt', '#', 'admin', SYSDATE(), '', NULL, ''),
|
||||
(1115, '批次清理', 519, '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:purge', '#', 'admin', SYSDATE(), '', NULL, '');
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -137,3 +137,25 @@ COMMENT ON COLUMN biz_pallet_event.test_batch_id IS '测试数据批次ID;NULL
|
||||
CREATE INDEX idx_biz_pallet_event_test_batch_id ON biz_pallet_event (test_batch_id);
|
||||
ALTER TABLE biz_pallet_event ADD CONSTRAINT fk_biz_pallet_event_test_batch_id
|
||||
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
|
||||
|
||||
-- 菜单迁移:移除旧物理删除权限,加入测试数据批次管理菜单。
|
||||
-- 新菜单不自动授予普通角色;超级管理员由现有 admin 权限访问。
|
||||
BEGIN;
|
||||
|
||||
DELETE FROM sys_role_menu
|
||||
WHERE menu_id IN (1068, 1072, 1076, 1081, 1085, 1090, 1095, 1102);
|
||||
|
||||
DELETE FROM sys_menu
|
||||
WHERE menu_id IN (1068, 1072, 1076, 1081, 1085, 1090, 1095, 1102);
|
||||
|
||||
INSERT INTO sys_menu VALUES
|
||||
(519, '测试数据批次', 1, '7', 'testBatch', 'system/testBatch/index', '', '', 1, 0, 'C', '0', '0', 'system:testbatch:list', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '测试数据批次菜单'),
|
||||
(1109, '批次查询', 519, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:query', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, ''),
|
||||
(1110, '批次新增', 519, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:add', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, ''),
|
||||
(1111, '批次修改', 519, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:edit', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, ''),
|
||||
(1112, '批次授权', 519, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:assign', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, ''),
|
||||
(1113, '批次关闭', 519, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:close', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, ''),
|
||||
(1114, '数据纳入', 519, '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:adopt', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, ''),
|
||||
(1115, '批次清理', 519, '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:purge', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '');
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -1575,47 +1575,47 @@ insert into sys_menu values
|
||||
(516, '产线消耗', 123, '4', 'consumption', 'report/consumption/index', '', '', 1, 0, 'C', '0', '0', 'report:consumption:list', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(517, '退回仓库', 123, '5', 'reportReturn', 'report/return/index', '', '', 1, 0, 'C', '0', '0', 'report:return:list', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(518, '托盘追溯', 123, '6', 'palletTrace', 'report/palletTrace/index', '', '', 1, 0, 'C', '0', '0', 'report:pallettrace:list', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(519, '测试数据批次', 1, '7', 'testBatch', 'system/testBatch/index', '', '', 1, 0, 'C', '0', '0', 'system:testbatch:list', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1065, '菌种查询', 502, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1066, '菌种新增', 502, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1067, '菌种修改', 502, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1068, '菌种删除', 502, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1069, '客户查询', 503, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1070, '客户新增', 503, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1071, '客户修改', 503, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1072, '客户删除', 503, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1073, '现场查询', 504, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1074, '现场新增', 504, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1075, '现场修改', 504, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1076, '现场删除', 504, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1077, '分配用户', 504, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:assign', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1078, '产线查询', 505, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1079, '产线新增', 505, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1080, '产线修改', 505, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1081, '产线删除', 505, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1082, '仓库查询', 506, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1083, '仓库新增', 506, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1084, '仓库修改', 506, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1085, '仓库删除', 506, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1086, '分配用户', 506, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:assign', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1087, '托盘查询', 507, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1088, '托盘新增', 507, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1089, '托盘修改', 507, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1090, '托盘删除', 507, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1091, '托盘打印', 507, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:print', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1092, '入库查询', 508, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1093, '入库新增', 508, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1094, '入库修改', 508, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1095, '入库删除', 508, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1096, '入库确认', 508, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:confirm', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1097, '装填查询', 509, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:filling:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1098, '装填新增', 509, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:filling:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1099, '发货查询', 510, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1100, '发货新增', 510, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1101, '发货修改', 510, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1102, '发货删除', 510, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:remove', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1103, '发货确认', 510, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:confirm', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1104, '使用查询', 511, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:usage:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1105, '使用新增', 511, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:usage:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1106, '退回查询', 512, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1107, '退回申请', 512, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:request', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1108, '退回确认', 512, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:confirm', '#', 'admin', current_timestamp, '', null, '');
|
||||
(1108, '退回确认', 512, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:confirm', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1109, '批次查询', 519, '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:query', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1110, '批次新增', 519, '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:add', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1111, '批次修改', 519, '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:edit', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1112, '批次授权', 519, '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:assign', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1113, '批次关闭', 519, '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:close', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1114, '数据纳入', 519, '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:adopt', '#', 'admin', current_timestamp, '', null, ''),
|
||||
(1115, '批次清理', 519, '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:purge', '#', 'admin', current_timestamp, '', null, '');
|
||||
|
||||
@@ -307,52 +307,52 @@ insert into sys_menu values('515', '发货出库', '123', '3', 'reportShipment',
|
||||
insert into sys_menu values('516', '产线消耗', '123', '4', 'consumption', 'report/consumption/index', '', '', 1, 0, 'C', '0', '0', 'report:consumption:list', '#', 'admin', sysdate(), '', null, '产线消耗菜单');
|
||||
insert into sys_menu values('517', '退回仓库', '123', '5', 'reportReturn', 'report/return/index', '', '', 1, 0, 'C', '0', '0', 'report:return:list', '#', 'admin', sysdate(), '', null, '退回仓库报表菜单');
|
||||
insert into sys_menu values('518', '托盘追溯', '123', '6', 'palletTrace', 'report/palletTrace/index', '', '', 1, 0, 'C', '0', '0', 'report:pallettrace:list', '#', 'admin', sysdate(), '', null, '托盘追溯菜单');
|
||||
insert into sys_menu values('519', '测试数据批次', '1', '7', 'testBatch', 'system/testBatch/index', '', '', 1, 0, 'C', '0', '0', 'system:testbatch:list', '#', 'admin', sysdate(), '', null, '测试数据批次菜单');
|
||||
|
||||
-- 托盘业务按钮
|
||||
insert into sys_menu values('1065', '菌种查询', '502', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1066', '菌种新增', '502', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1067', '菌种修改', '502', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1068', '菌种删除', '502', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:strain:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1069', '客户查询', '503', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1070', '客户新增', '503', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1071', '客户修改', '503', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1072', '客户删除', '503', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:customer:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1073', '现场查询', '504', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1074', '现场新增', '504', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1075', '现场修改', '504', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1076', '现场删除', '504', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1077', '分配用户', '504', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'master:site:assign', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1078', '产线查询', '505', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1079', '产线新增', '505', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1080', '产线修改', '505', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1081', '产线删除', '505', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:line:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1082', '仓库查询', '506', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1083', '仓库新增', '506', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1084', '仓库修改', '506', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1085', '仓库删除', '506', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1086', '分配用户', '506', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'master:warehouse:assign', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1087', '托盘查询', '507', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1088', '托盘新增', '507', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1089', '托盘修改', '507', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1090', '托盘删除', '507', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1091', '托盘打印', '507', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'master:pallet:print', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1092', '入库查询', '508', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1093', '入库新增', '508', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1094', '入库修改', '508', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1095', '入库删除', '508', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1096', '入库确认', '508', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'business:inbound:confirm', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1097', '装填查询', '509', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:filling:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1098', '装填新增', '509', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:filling:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1099', '发货查询', '510', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1100', '发货新增', '510', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1101', '发货修改', '510', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1102', '发货删除', '510', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1103', '发货确认', '510', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'business:shipment:confirm', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1104', '使用查询', '511', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:usage:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1105', '使用新增', '511', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:usage:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1106', '退回查询', '512', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1107', '退回申请', '512', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:request', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1108', '退回确认', '512', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'business:return:confirm', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1109', '批次查询', '519', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1110', '批次新增', '519', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1111', '批次修改', '519', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1112', '批次授权', '519', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:assign', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1113', '批次关闭', '519', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:close', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1114', '数据纳入', '519', '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:adopt', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1115', '批次清理', '519', '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:testbatch:purge', '#', 'admin', sysdate(), '', null, '');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
|
||||
@@ -24,11 +24,13 @@ CONTROLLER_NAMES = (
|
||||
'usage',
|
||||
'return',
|
||||
'report',
|
||||
'test_batch',
|
||||
)
|
||||
TARGET_PREFIXES = (
|
||||
'/master',
|
||||
'/business',
|
||||
'/report',
|
||||
'/system/test-batch',
|
||||
)
|
||||
ROUTE_HTTP_METHODS = frozenset({'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'})
|
||||
WRITE_METHODS = frozenset({'DELETE', 'PATCH', 'POST', 'PUT'})
|
||||
@@ -52,6 +54,7 @@ EXPECTED_PAGE_PERMISSIONS = frozenset(
|
||||
'report:consumption:list',
|
||||
'report:return:list',
|
||||
'report:pallettrace:list',
|
||||
'system:testbatch:list',
|
||||
}
|
||||
)
|
||||
EXPECTED_BUTTON_PERMISSIONS = frozenset(
|
||||
@@ -59,50 +62,54 @@ EXPECTED_BUTTON_PERMISSIONS = frozenset(
|
||||
'master:strain:query',
|
||||
'master:strain:add',
|
||||
'master:strain:edit',
|
||||
'master:strain:remove',
|
||||
'master:customer:query',
|
||||
'master:customer:add',
|
||||
'master:customer:edit',
|
||||
'master:customer:remove',
|
||||
'master:site:query',
|
||||
'master:site:add',
|
||||
'master:site:edit',
|
||||
'master:site:remove',
|
||||
'master:site:assign',
|
||||
'master:line:query',
|
||||
'master:line:add',
|
||||
'master:line:edit',
|
||||
'master:line:remove',
|
||||
'master:warehouse:query',
|
||||
'master:warehouse:add',
|
||||
'master:warehouse:edit',
|
||||
'master:warehouse:remove',
|
||||
'master:warehouse:assign',
|
||||
'master:pallet:query',
|
||||
'master:pallet:add',
|
||||
'master:pallet:edit',
|
||||
'master:pallet:remove',
|
||||
'master:pallet:print',
|
||||
'business:inbound:query',
|
||||
'business:inbound:add',
|
||||
'business:inbound:edit',
|
||||
'business:inbound:remove',
|
||||
'business:inbound:confirm',
|
||||
'business:filling:query',
|
||||
'business:filling:add',
|
||||
'business:shipment:query',
|
||||
'business:shipment:add',
|
||||
'business:shipment:edit',
|
||||
'business:shipment:remove',
|
||||
'business:shipment:confirm',
|
||||
'business:usage:query',
|
||||
'business:usage:add',
|
||||
'business:return:query',
|
||||
'business:return:request',
|
||||
'business:return:confirm',
|
||||
'system:testbatch:query',
|
||||
'system:testbatch:add',
|
||||
'system:testbatch:edit',
|
||||
'system:testbatch:assign',
|
||||
'system:testbatch:close',
|
||||
'system:testbatch:adopt',
|
||||
'system:testbatch:purge',
|
||||
}
|
||||
)
|
||||
EXPECTED_PERMISSIONS = EXPECTED_PAGE_PERMISSIONS | EXPECTED_BUTTON_PERMISSIONS
|
||||
EXPECTED_WEB_PERMISSIONS = frozenset(
|
||||
permission
|
||||
for permission in EXPECTED_PERMISSIONS
|
||||
if not permission.startswith('system:testbatch:') or permission == 'system:testbatch:adopt'
|
||||
)
|
||||
VUE_PAGE_PATHS = (
|
||||
'src/views/master/strain/index.vue',
|
||||
'src/views/master/customer/index.vue',
|
||||
@@ -122,7 +129,30 @@ VUE_PAGE_PATHS = (
|
||||
'src/views/report/return/index.vue',
|
||||
'src/views/report/palletTrace/index.vue',
|
||||
)
|
||||
PERMISSION_LITERAL_PATTERN = re.compile(r'(?:master|business|report):[a-z]+:[a-z]+')
|
||||
PERMISSION_LITERAL_PATTERN = re.compile(r'(?:master|business|report|system):[a-z]+:[a-z]+')
|
||||
UNGUARDED_AUTHENTICATED_ROUTES = {('/system/test-batch/options', 'GET')}
|
||||
REMOVED_DELETE_SYMBOLS = (
|
||||
'delStrain',
|
||||
'delCustomer',
|
||||
'delSite',
|
||||
'delLine',
|
||||
'delWarehouse',
|
||||
'delPallet',
|
||||
'delInbound',
|
||||
'delShipment',
|
||||
)
|
||||
REMOVED_DELETE_PERMISSIONS = frozenset(
|
||||
{
|
||||
'master:strain:remove',
|
||||
'master:customer:remove',
|
||||
'master:site:remove',
|
||||
'master:line:remove',
|
||||
'master:warehouse:remove',
|
||||
'master:pallet:remove',
|
||||
'business:inbound:remove',
|
||||
'business:shipment:remove',
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _build_expected_route_permissions() -> dict[tuple[str, str], str]:
|
||||
@@ -136,7 +166,7 @@ def _build_expected_route_permissions() -> dict[tuple[str, str], str]:
|
||||
(f'{root}/{{{resource}_id}}', 'GET'): f'{permission_root}:query',
|
||||
(root, 'POST'): f'{permission_root}:add',
|
||||
(root, 'PUT'): f'{permission_root}:edit',
|
||||
(f'{root}/{{{resource}_ids}}', 'DELETE'): f'{permission_root}:remove',
|
||||
(f'{root}/{{{resource}_ids}}', 'DELETE'): f'{permission_root}:list',
|
||||
}
|
||||
)
|
||||
|
||||
@@ -153,7 +183,7 @@ def _build_expected_route_permissions() -> dict[tuple[str, str], str]:
|
||||
('/business/inbound/{inbound_id}', 'GET'): 'business:inbound:query',
|
||||
('/business/inbound', 'POST'): 'business:inbound:add',
|
||||
('/business/inbound', 'PUT'): 'business:inbound:edit',
|
||||
('/business/inbound/{inbound_ids}', 'DELETE'): 'business:inbound:remove',
|
||||
('/business/inbound/{inbound_ids}', 'DELETE'): 'business:inbound:list',
|
||||
('/business/inbound/{inbound_id}/confirm', 'PUT'): 'business:inbound:confirm',
|
||||
('/business/filling/list', 'GET'): 'business:filling:list',
|
||||
('/business/filling/strain-options', 'GET'): 'business:filling:query',
|
||||
@@ -167,7 +197,7 @@ def _build_expected_route_permissions() -> dict[tuple[str, str], str]:
|
||||
('/business/shipment/{shipment_id}', 'GET'): 'business:shipment:query',
|
||||
('/business/shipment', 'POST'): 'business:shipment:add',
|
||||
('/business/shipment', 'PUT'): 'business:shipment:edit',
|
||||
('/business/shipment/{shipment_ids}', 'DELETE'): 'business:shipment:remove',
|
||||
('/business/shipment/{shipment_ids}', 'DELETE'): 'business:shipment:list',
|
||||
('/business/shipment/{shipment_id}/confirm', 'PUT'): 'business:shipment:confirm',
|
||||
('/business/usage/list', 'GET'): 'business:usage:list',
|
||||
('/business/usage/line-options', 'GET'): 'business:usage:query',
|
||||
@@ -186,6 +216,17 @@ def _build_expected_route_permissions() -> dict[tuple[str, str], str]:
|
||||
('/report/consumption/list', 'GET'): 'report:consumption:list',
|
||||
('/report/return/list', 'GET'): 'report:return:list',
|
||||
('/report/pallet-trace/list', 'GET'): 'report:pallettrace:list',
|
||||
('/system/test-batch/list', 'GET'): 'system:testbatch:list',
|
||||
('/system/test-batch', 'POST'): 'system:testbatch:add',
|
||||
('/system/test-batch/{batch_id}', 'PUT'): 'system:testbatch:edit',
|
||||
('/system/test-batch/{batch_id}/users', 'PUT'): 'system:testbatch:assign',
|
||||
('/system/test-batch/{batch_id}/close', 'PUT'): 'system:testbatch:close',
|
||||
('/system/test-batch/{batch_id}/reopen', 'PUT'): 'system:testbatch:close',
|
||||
('/system/test-batch/{batch_id}/adoption/preview', 'POST'): 'system:testbatch:adopt',
|
||||
('/system/test-batch/{batch_id}/adoption/execute', 'POST'): 'system:testbatch:adopt',
|
||||
('/system/test-batch/{batch_id}/purge/preview', 'POST'): 'system:testbatch:purge',
|
||||
('/system/test-batch/{batch_id}/purge', 'POST'): 'system:testbatch:purge',
|
||||
('/system/test-batch/{batch_id}', 'GET'): 'system:testbatch:query',
|
||||
}
|
||||
)
|
||||
return expected
|
||||
@@ -214,6 +255,10 @@ STATIC_READS_BEFORE_DETAIL = {
|
||||
'/business/return/warehouse-options',
|
||||
'/business/return/scan/{qr_token}',
|
||||
),
|
||||
'/system/test-batch/{batch_id}': (
|
||||
'/system/test-batch/options',
|
||||
'/system/test-batch/list',
|
||||
),
|
||||
}
|
||||
EXACT_QUERY_PARAMETERS = {
|
||||
('/business/inbound/scan/{qr_token}', 'GET'): {'warehouseId'},
|
||||
@@ -241,7 +286,7 @@ def _auth_dependencies(route: APIRoute) -> list[CheckUserInterfaceAuth]:
|
||||
|
||||
def _assert_controller_permission_literals(test_case: unittest.TestCase, literals: list[str]) -> None:
|
||||
expected = Counter(EXPECTED_ROUTE_PERMISSIONS.values())
|
||||
test_case.assertEqual(74, expected.total())
|
||||
test_case.assertEqual(85, expected.total())
|
||||
test_case.assertEqual(expected, Counter(literals))
|
||||
test_case.assertEqual(EXPECTED_PERMISSIONS, frozenset(expected))
|
||||
|
||||
@@ -368,10 +413,18 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
]
|
||||
|
||||
def test_target_path_selector_uses_namespace_boundaries(self) -> None:
|
||||
for path in ('/master', '/master/foo', '/business', '/business/foo', '/report/foo'):
|
||||
for path in (
|
||||
'/master',
|
||||
'/master/foo',
|
||||
'/business',
|
||||
'/business/foo',
|
||||
'/report/foo',
|
||||
'/system/test-batch',
|
||||
'/system/test-batch/options',
|
||||
):
|
||||
with self.subTest(path=path):
|
||||
self.assertTrue(_is_target_path(path))
|
||||
for path in ('/masterish', '/business-other', '/reporting'):
|
||||
for path in ('/masterish', '/business-other', '/reporting', '/system/test-batches'):
|
||||
with self.subTest(path=path):
|
||||
self.assertFalse(_is_target_path(path))
|
||||
|
||||
@@ -384,8 +437,8 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
if method.upper() in ROUTE_HTTP_METHODS
|
||||
}
|
||||
|
||||
self.assertEqual(set(EXPECTED_ROUTE_PERMISSIONS), actual_operations)
|
||||
self.assertEqual(74, len(actual_operations))
|
||||
self.assertEqual(set(EXPECTED_ROUTE_PERMISSIONS) | UNGUARDED_AUTHENTICATED_ROUTES, actual_operations)
|
||||
self.assertEqual(86, len(actual_operations))
|
||||
|
||||
openapi_ai_paths = sorted(path for path in self.schema['paths'] if path == '/ai' or path.startswith('/ai/'))
|
||||
app_ai_paths = sorted(
|
||||
@@ -406,8 +459,11 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
operation_keys.append(key)
|
||||
|
||||
auth_dependencies = _auth_dependencies(route)
|
||||
self.assertEqual(1, len(auth_dependencies), key)
|
||||
actual_permissions[key] = auth_dependencies[0].perm
|
||||
if key in UNGUARDED_AUTHENTICATED_ROUTES:
|
||||
self.assertEqual([], auth_dependencies, key)
|
||||
else:
|
||||
self.assertEqual(1, len(auth_dependencies), key)
|
||||
actual_permissions[key] = auth_dependencies[0].perm
|
||||
|
||||
self.assertEqual(len(operation_keys), len(set(operation_keys)))
|
||||
self.assertEqual(EXPECTED_ROUTE_PERMISSIONS, actual_permissions)
|
||||
@@ -435,19 +491,19 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
literals.append(node.args[0].value)
|
||||
|
||||
self.assertEqual([], malformed_calls)
|
||||
self.assertEqual(17, len(EXPECTED_PAGE_PERMISSIONS))
|
||||
self.assertEqual(44, len(EXPECTED_BUTTON_PERMISSIONS))
|
||||
self.assertEqual(18, len(EXPECTED_PAGE_PERMISSIONS))
|
||||
self.assertEqual(43, len(EXPECTED_BUTTON_PERMISSIONS))
|
||||
self.assertFalse(EXPECTED_PAGE_PERMISSIONS & EXPECTED_BUTTON_PERMISSIONS)
|
||||
self.assertEqual(61, len(EXPECTED_PERMISSIONS))
|
||||
_assert_controller_permission_literals(self, literals)
|
||||
self.assertEqual(
|
||||
{'add', 'assign', 'confirm', 'edit', 'list', 'print', 'query', 'remove', 'request'},
|
||||
{'add', 'adopt', 'assign', 'close', 'confirm', 'edit', 'list', 'print', 'purge', 'query', 'request'},
|
||||
{permission.rsplit(':', maxsplit=1)[1] for permission in literals},
|
||||
)
|
||||
|
||||
def test_controller_ast_permission_contract_rejects_duplicate_call(self) -> None:
|
||||
literals = list(EXPECTED_ROUTE_PERMISSIONS.values())
|
||||
self.assertEqual(74, len(literals))
|
||||
self.assertEqual(85, len(literals))
|
||||
literals.append(literals[0])
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
@@ -473,7 +529,66 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
self.assertTrue(guarded, relative_path)
|
||||
actual_permissions.update(guarded)
|
||||
|
||||
_assert_exact_permission_layers(self, {'vue': actual_permissions})
|
||||
self.assertEqual(EXPECTED_WEB_PERMISSIONS, frozenset(actual_permissions))
|
||||
|
||||
def test_frontend_has_no_physical_delete_api_or_page_contract(self) -> None:
|
||||
relative_paths = (
|
||||
'src/api/master/strain.js',
|
||||
'src/api/master/customer.js',
|
||||
'src/api/master/site.js',
|
||||
'src/api/master/line.js',
|
||||
'src/api/master/warehouse.js',
|
||||
'src/api/master/pallet.js',
|
||||
'src/api/business/inbound.js',
|
||||
'src/api/business/shipment.js',
|
||||
*VUE_PAGE_PATHS,
|
||||
)
|
||||
for relative_path in relative_paths:
|
||||
source = (FRONTEND_ROOT / relative_path).read_text(encoding='utf-8')
|
||||
code, structure = _sanitize_vue_source(source)
|
||||
with self.subTest(relative_path=relative_path):
|
||||
for symbol in REMOVED_DELETE_SYMBOLS:
|
||||
self.assertIsNone(re.search(rf'\b{symbol}\b', structure), symbol)
|
||||
self.assertFalse(REMOVED_DELETE_PERMISSIONS & set(PERMISSION_LITERAL_PATTERN.findall(code)))
|
||||
|
||||
def test_sensitive_test_batch_logs_only_include_batch_id_and_response_summary(self) -> None:
|
||||
source_path = BACKEND_ROOT / 'module_business/controller/test_batch_controller.py'
|
||||
tree = ast.parse(source_path.read_text(encoding='utf-8'), filename=str(source_path))
|
||||
functions = {node.name: node for node in tree.body if isinstance(node, ast.AsyncFunctionDef)}
|
||||
sensitive_handlers = {
|
||||
'preview_test_batch_adoption',
|
||||
'execute_test_batch_adoption',
|
||||
'preview_test_batch_purge',
|
||||
'purge_test_batch',
|
||||
}
|
||||
self.assertEqual(sensitive_handlers, sensitive_handlers & functions.keys())
|
||||
|
||||
for handler_name in sensitive_handlers:
|
||||
log_calls = [
|
||||
decorator
|
||||
for decorator in functions[handler_name].decorator_list
|
||||
if isinstance(decorator, ast.Call)
|
||||
and isinstance(decorator.func, ast.Name)
|
||||
and decorator.func.id == 'Log'
|
||||
]
|
||||
with self.subTest(handler=handler_name):
|
||||
self.assertEqual(1, len(log_calls))
|
||||
keywords = {keyword.arg: keyword.value for keyword in log_calls[0].keywords}
|
||||
self.assertEqual('include', ast.literal_eval(keywords['request_log_mode']))
|
||||
self.assertEqual('summary', ast.literal_eval(keywords['response_log_mode']))
|
||||
include_fields = keywords['request_include_fields']
|
||||
self.assertIsInstance(include_fields, ast.Tuple)
|
||||
self.assertEqual(1, len(include_fields.elts))
|
||||
field_call = include_fields.elts[0]
|
||||
self.assertIsInstance(field_call, ast.Call)
|
||||
self.assertEqual('batch_id', ast.literal_eval(field_call.args[0]))
|
||||
self.assertIsInstance(field_call.func, ast.Attribute)
|
||||
self.assertEqual('field', field_call.func.attr)
|
||||
root = field_call.func.value
|
||||
self.assertIsInstance(root, ast.Attribute)
|
||||
self.assertEqual('PATH_PARAMS', root.attr)
|
||||
self.assertIsInstance(root.value, ast.Name)
|
||||
self.assertEqual('RequestLogFieldRoot', root.value.id)
|
||||
|
||||
def test_vue_guard_parser_rejects_dynamic_arrays_and_has_permi_or(self) -> None:
|
||||
dynamic_sources = (
|
||||
@@ -561,7 +676,7 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
self.assertLess(route_order[static_path], route_order[detail_path])
|
||||
|
||||
def test_openapi_parameter_names_are_exact(self) -> None:
|
||||
for path, method in EXPECTED_ROUTE_PERMISSIONS:
|
||||
for path, method in set(EXPECTED_ROUTE_PERMISSIONS) | UNGUARDED_AUTHENTICATED_ROUTES:
|
||||
parameters = self.schema['paths'][path][method.lower()].get('parameters', [])
|
||||
actual_path_parameters = {parameter['name'] for parameter in parameters if parameter['in'] == 'path'}
|
||||
self.assertEqual(set(re.findall(r'{([^{}]+)}', path)), actual_path_parameters, (path, method))
|
||||
@@ -593,7 +708,7 @@ class ApiPermissionContractTest(unittest.TestCase):
|
||||
for method in route.methods & WRITE_METHODS:
|
||||
actual_write_routes[(route.path, method)] = route
|
||||
|
||||
self.assertEqual(32, len(expected_write_permissions))
|
||||
self.assertEqual(41, len(expected_write_permissions))
|
||||
self.assertEqual(set(expected_write_permissions), set(actual_write_routes))
|
||||
for key, expected_permission in expected_write_permissions.items():
|
||||
with self.subTest(operation=key):
|
||||
|
||||
@@ -446,6 +446,7 @@ EXPECTED_CHECKS.update(
|
||||
)
|
||||
|
||||
EXPECTED_PAGES = {
|
||||
519: ('测试数据批次', 1, 7, 'testBatch', 'system/testBatch/index', 'system:testbatch:list'),
|
||||
502: ('菌种资料', 121, 1, 'strain', 'master/strain/index', 'master:strain:list'),
|
||||
503: ('客户资料', 121, 2, 'customer', 'master/customer/index', 'master:customer:list'),
|
||||
504: ('客户现场', 121, 3, 'site', 'master/site/index', 'master:site:list'),
|
||||
@@ -476,47 +477,46 @@ BUTTON_SPECS = """
|
||||
1065 502 1 菌种查询 master:strain:query
|
||||
1066 502 2 菌种新增 master:strain:add
|
||||
1067 502 3 菌种修改 master:strain:edit
|
||||
1068 502 4 菌种删除 master:strain:remove
|
||||
1069 503 1 客户查询 master:customer:query
|
||||
1070 503 2 客户新增 master:customer:add
|
||||
1071 503 3 客户修改 master:customer:edit
|
||||
1072 503 4 客户删除 master:customer:remove
|
||||
1073 504 1 现场查询 master:site:query
|
||||
1074 504 2 现场新增 master:site:add
|
||||
1075 504 3 现场修改 master:site:edit
|
||||
1076 504 4 现场删除 master:site:remove
|
||||
1077 504 5 分配用户 master:site:assign
|
||||
1078 505 1 产线查询 master:line:query
|
||||
1079 505 2 产线新增 master:line:add
|
||||
1080 505 3 产线修改 master:line:edit
|
||||
1081 505 4 产线删除 master:line:remove
|
||||
1082 506 1 仓库查询 master:warehouse:query
|
||||
1083 506 2 仓库新增 master:warehouse:add
|
||||
1084 506 3 仓库修改 master:warehouse:edit
|
||||
1085 506 4 仓库删除 master:warehouse:remove
|
||||
1086 506 5 分配用户 master:warehouse:assign
|
||||
1087 507 1 托盘查询 master:pallet:query
|
||||
1088 507 2 托盘新增 master:pallet:add
|
||||
1089 507 3 托盘修改 master:pallet:edit
|
||||
1090 507 4 托盘删除 master:pallet:remove
|
||||
1091 507 5 托盘打印 master:pallet:print
|
||||
1092 508 1 入库查询 business:inbound:query
|
||||
1093 508 2 入库新增 business:inbound:add
|
||||
1094 508 3 入库修改 business:inbound:edit
|
||||
1095 508 4 入库删除 business:inbound:remove
|
||||
1096 508 5 入库确认 business:inbound:confirm
|
||||
1097 509 1 装填查询 business:filling:query
|
||||
1098 509 2 装填新增 business:filling:add
|
||||
1099 510 1 发货查询 business:shipment:query
|
||||
1100 510 2 发货新增 business:shipment:add
|
||||
1101 510 3 发货修改 business:shipment:edit
|
||||
1102 510 4 发货删除 business:shipment:remove
|
||||
1103 510 5 发货确认 business:shipment:confirm
|
||||
1104 511 1 使用查询 business:usage:query
|
||||
1105 511 2 使用新增 business:usage:add
|
||||
1106 512 1 退回查询 business:return:query
|
||||
1107 512 2 退回申请 business:return:request
|
||||
1108 512 3 退回确认 business:return:confirm
|
||||
1109 519 1 批次查询 system:testbatch:query
|
||||
1110 519 2 批次新增 system:testbatch:add
|
||||
1111 519 3 批次修改 system:testbatch:edit
|
||||
1112 519 4 批次授权 system:testbatch:assign
|
||||
1113 519 5 批次关闭 system:testbatch:close
|
||||
1114 519 6 数据纳入 system:testbatch:adopt
|
||||
1115 519 7 批次清理 system:testbatch:purge
|
||||
"""
|
||||
EXPECTED_BUTTONS = {
|
||||
int(menu_id): (name, int(parent_id), int(order_num), permission)
|
||||
@@ -526,6 +526,7 @@ EXPECTED_BUTTONS = {
|
||||
}
|
||||
EXPECTED_PAGE_PERMISSIONS = frozenset(
|
||||
[
|
||||
'system:testbatch:list',
|
||||
'master:strain:list',
|
||||
'master:customer:list',
|
||||
'master:site:list',
|
||||
@@ -550,41 +551,40 @@ EXPECTED_BUTTON_PERMISSIONS = frozenset(
|
||||
'master:strain:query',
|
||||
'master:strain:add',
|
||||
'master:strain:edit',
|
||||
'master:strain:remove',
|
||||
'master:customer:query',
|
||||
'master:customer:add',
|
||||
'master:customer:edit',
|
||||
'master:customer:remove',
|
||||
'master:site:query',
|
||||
'master:site:add',
|
||||
'master:site:edit',
|
||||
'master:site:remove',
|
||||
'master:site:assign',
|
||||
'master:line:query',
|
||||
'master:line:add',
|
||||
'master:line:edit',
|
||||
'master:line:remove',
|
||||
'master:warehouse:query',
|
||||
'master:warehouse:add',
|
||||
'master:warehouse:edit',
|
||||
'master:warehouse:remove',
|
||||
'master:warehouse:assign',
|
||||
'master:pallet:query',
|
||||
'master:pallet:add',
|
||||
'master:pallet:edit',
|
||||
'master:pallet:remove',
|
||||
'master:pallet:print',
|
||||
'business:inbound:query',
|
||||
'business:inbound:add',
|
||||
'business:inbound:edit',
|
||||
'business:inbound:remove',
|
||||
'business:inbound:confirm',
|
||||
'business:filling:query',
|
||||
'business:filling:add',
|
||||
'business:shipment:query',
|
||||
'business:shipment:add',
|
||||
'business:shipment:edit',
|
||||
'business:shipment:remove',
|
||||
'system:testbatch:query',
|
||||
'system:testbatch:add',
|
||||
'system:testbatch:edit',
|
||||
'system:testbatch:assign',
|
||||
'system:testbatch:close',
|
||||
'system:testbatch:adopt',
|
||||
'system:testbatch:purge',
|
||||
'business:shipment:confirm',
|
||||
'business:usage:query',
|
||||
'business:usage:add',
|
||||
@@ -595,6 +595,7 @@ EXPECTED_BUTTON_PERMISSIONS = frozenset(
|
||||
)
|
||||
EXPECTED_PERMISSIONS = EXPECTED_PAGE_PERMISSIONS | EXPECTED_BUTTON_PERMISSIONS
|
||||
BUSINESS_MENU_SPECS = """
|
||||
519|1|测试数据批次|testBatch||7|system:testbatch:list|system/testBatch/index
|
||||
121|0|基础资料维护|businessMaster||1||<NULL>
|
||||
122|0|业务管理|businessOperation||2||<NULL>
|
||||
123|0|报表查询|businessReport||3||<NULL>
|
||||
@@ -618,47 +619,46 @@ BUSINESS_MENU_SPECS = """
|
||||
1065|502|菌种查询|||1|master:strain:query|
|
||||
1066|502|菌种新增|||2|master:strain:add|
|
||||
1067|502|菌种修改|||3|master:strain:edit|
|
||||
1068|502|菌种删除|||4|master:strain:remove|
|
||||
1069|503|客户查询|||1|master:customer:query|
|
||||
1070|503|客户新增|||2|master:customer:add|
|
||||
1071|503|客户修改|||3|master:customer:edit|
|
||||
1072|503|客户删除|||4|master:customer:remove|
|
||||
1073|504|现场查询|||1|master:site:query|
|
||||
1074|504|现场新增|||2|master:site:add|
|
||||
1075|504|现场修改|||3|master:site:edit|
|
||||
1076|504|现场删除|||4|master:site:remove|
|
||||
1077|504|分配用户|||5|master:site:assign|
|
||||
1078|505|产线查询|||1|master:line:query|
|
||||
1079|505|产线新增|||2|master:line:add|
|
||||
1080|505|产线修改|||3|master:line:edit|
|
||||
1081|505|产线删除|||4|master:line:remove|
|
||||
1082|506|仓库查询|||1|master:warehouse:query|
|
||||
1083|506|仓库新增|||2|master:warehouse:add|
|
||||
1084|506|仓库修改|||3|master:warehouse:edit|
|
||||
1085|506|仓库删除|||4|master:warehouse:remove|
|
||||
1086|506|分配用户|||5|master:warehouse:assign|
|
||||
1087|507|托盘查询|||1|master:pallet:query|
|
||||
1088|507|托盘新增|||2|master:pallet:add|
|
||||
1089|507|托盘修改|||3|master:pallet:edit|
|
||||
1090|507|托盘删除|||4|master:pallet:remove|
|
||||
1091|507|托盘打印|||5|master:pallet:print|
|
||||
1092|508|入库查询|||1|business:inbound:query|
|
||||
1093|508|入库新增|||2|business:inbound:add|
|
||||
1094|508|入库修改|||3|business:inbound:edit|
|
||||
1095|508|入库删除|||4|business:inbound:remove|
|
||||
1096|508|入库确认|||5|business:inbound:confirm|
|
||||
1097|509|装填查询|||1|business:filling:query|
|
||||
1098|509|装填新增|||2|business:filling:add|
|
||||
1099|510|发货查询|||1|business:shipment:query|
|
||||
1100|510|发货新增|||2|business:shipment:add|
|
||||
1101|510|发货修改|||3|business:shipment:edit|
|
||||
1102|510|发货删除|||4|business:shipment:remove|
|
||||
1103|510|发货确认|||5|business:shipment:confirm|
|
||||
1104|511|使用查询|||1|business:usage:query|
|
||||
1105|511|使用新增|||2|business:usage:add|
|
||||
1106|512|退回查询|||1|business:return:query|
|
||||
1107|512|退回申请|||2|business:return:request|
|
||||
1108|512|退回确认|||3|business:return:confirm|
|
||||
1109|519|批次查询|||1|system:testbatch:query|
|
||||
1110|519|批次新增|||2|system:testbatch:add|
|
||||
1111|519|批次修改|||3|system:testbatch:edit|
|
||||
1112|519|批次授权|||4|system:testbatch:assign|
|
||||
1113|519|批次关闭|||5|system:testbatch:close|
|
||||
1114|519|数据纳入|||6|system:testbatch:adopt|
|
||||
1115|519|批次清理|||7|system:testbatch:purge|
|
||||
""".strip()
|
||||
|
||||
|
||||
@@ -679,7 +679,33 @@ def _expected_business_menu_fields() -> dict[int, tuple]:
|
||||
|
||||
|
||||
EXPECTED_BUSINESS_MENU_FIELDS = _expected_business_menu_fields()
|
||||
LEGACY_PATCH_BUSINESS_MENU_FIELDS = EXPECTED_BUSINESS_MENU_FIELDS | {
|
||||
|
||||
LEGACY_REMOVED_BUTTON_SPECS = {
|
||||
1068: ('菌种删除', 502, 4, 'master:strain:remove'),
|
||||
1072: ('客户删除', 503, 4, 'master:customer:remove'),
|
||||
1076: ('现场删除', 504, 4, 'master:site:remove'),
|
||||
1081: ('产线删除', 505, 4, 'master:line:remove'),
|
||||
1085: ('仓库删除', 506, 4, 'master:warehouse:remove'),
|
||||
1090: ('托盘删除', 507, 4, 'master:pallet:remove'),
|
||||
1095: ('入库删除', 508, 4, 'business:inbound:remove'),
|
||||
1102: ('发货删除', 510, 4, 'business:shipment:remove'),
|
||||
}
|
||||
LEGACY_BUSINESS_MENU_IDS = set(range(121, 124)) | set(range(502, 519)) | set(range(1065, 1109))
|
||||
LEGACY_EXPECTED_BUSINESS_MENU_FIELDS = {
|
||||
menu_id: fields for menu_id, fields in EXPECTED_BUSINESS_MENU_FIELDS.items() if menu_id in LEGACY_BUSINESS_MENU_IDS
|
||||
}
|
||||
LEGACY_EXPECTED_BUSINESS_MENU_FIELDS.update(
|
||||
{
|
||||
menu_id: (parent_id, name, '', '', order_num, permission, '')
|
||||
for menu_id, (name, parent_id, order_num, permission) in LEGACY_REMOVED_BUTTON_SPECS.items()
|
||||
}
|
||||
)
|
||||
LEGACY_EXPECTED_PAGE_PERMISSIONS = EXPECTED_PAGE_PERMISSIONS - {'system:testbatch:list'}
|
||||
LEGACY_EXPECTED_BUTTON_PERMISSIONS = EXPECTED_BUTTON_PERMISSIONS - {
|
||||
permission for permission in EXPECTED_BUTTON_PERMISSIONS if permission.startswith('system:testbatch:')
|
||||
} | {spec[3] for spec in LEGACY_REMOVED_BUTTON_SPECS.values()}
|
||||
LEGACY_EXPECTED_PERMISSIONS = LEGACY_EXPECTED_PAGE_PERMISSIONS | LEGACY_EXPECTED_BUTTON_PERMISSIONS
|
||||
LEGACY_PATCH_BUSINESS_MENU_FIELDS = LEGACY_EXPECTED_BUSINESS_MENU_FIELDS | {
|
||||
121: (1, '基础资料维护', 'businessMaster', '', 10, '', None),
|
||||
122: (1, '业务管理', 'businessOperation', '', 11, '', None),
|
||||
123: (1, '报表查询', 'businessReport', '', 12, '', None),
|
||||
@@ -706,7 +732,28 @@ EXPECTED_TOP_LEVEL_MENU_STABLE_FIELDS = {
|
||||
3: ('系统工具', 'tool', None, '', '', '1', '0', 'M', '0', '0', '', 'tool'),
|
||||
}
|
||||
MENU_PROMOTION_IDS = set(EXPECTED_TOP_LEVEL_MENU_POSITIONS)
|
||||
BUSINESS_MENU_IDS = set(range(121, 124)) | set(range(502, 519)) | set(range(1065, 1109))
|
||||
BUSINESS_MENU_IDS = (
|
||||
set(range(121, 124))
|
||||
| set(range(502, 519))
|
||||
| {519}
|
||||
| set(range(1065, 1068))
|
||||
| set(range(1069, 1072))
|
||||
| set(range(1073, 1076))
|
||||
| {1077}
|
||||
| set(range(1078, 1081))
|
||||
| set(range(1082, 1085))
|
||||
| {1086}
|
||||
| set(range(1087, 1090))
|
||||
| {1091}
|
||||
| set(range(1092, 1095))
|
||||
| {1096}
|
||||
| set(range(1097, 1099))
|
||||
| set(range(1099, 1102))
|
||||
| {1103}
|
||||
| set(range(1104, 1109))
|
||||
| set(range(1109, 1116))
|
||||
)
|
||||
TEST_BATCH_MENU_IDS = {519, 1109, 1110, 1111, 1112, 1113, 1114, 1115}
|
||||
MYSQL_MENU_STABLE_COLUMNS = (
|
||||
'menu_name',
|
||||
'parent_id',
|
||||
@@ -1022,13 +1069,11 @@ def _assert_test_batch_sql_contract(
|
||||
test_case.assertRegex(normalized, index_pattern)
|
||||
test_case.assertIn("comment '测试数据批次id;null表示正式数据'", normalized)
|
||||
else:
|
||||
index_pattern = (
|
||||
rf'\bcreate\s+index\s+{index_name}\s+on\s+{table_name}\s*\(\s*test_batch_id\s*\)'
|
||||
)
|
||||
index_pattern = rf'\bcreate\s+index\s+{index_name}\s+on\s+{table_name}\s*\(\s*test_batch_id\s*\)'
|
||||
test_case.assertRegex(normalized, index_pattern)
|
||||
test_case.assertRegex(
|
||||
normalized,
|
||||
rf"comment\s+on\s+column\s+{table_name}\.test_batch_id\s+is\s+"
|
||||
rf'comment\s+on\s+column\s+{table_name}\.test_batch_id\s+is\s+'
|
||||
r"'测试数据批次id;null表示正式数据'",
|
||||
)
|
||||
|
||||
@@ -1049,8 +1094,8 @@ def _menu_rows(sql: str, menu_ids: set[int]) -> dict[int, list]:
|
||||
return {int(row[0]): row for row in selected}
|
||||
|
||||
|
||||
def _business_menu_rows(sql: str) -> dict[int, list]:
|
||||
return _menu_rows(sql, BUSINESS_MENU_IDS)
|
||||
def _business_menu_rows(sql: str, menu_ids: set[int] | None = None) -> dict[int, list]:
|
||||
return _menu_rows(sql, BUSINESS_MENU_IDS if menu_ids is None else menu_ids)
|
||||
|
||||
|
||||
def _assert_top_level_menu_fields(test_case: unittest.TestCase, sql: str) -> None:
|
||||
@@ -1067,7 +1112,7 @@ def _assert_business_menu_fields(
|
||||
sql: str,
|
||||
expected_fields: dict[int, tuple] = EXPECTED_BUSINESS_MENU_FIELDS,
|
||||
) -> None:
|
||||
rows = _business_menu_rows(sql)
|
||||
rows = _business_menu_rows(sql, set(expected_fields))
|
||||
invalid_widths = {menu_id: len(row) for menu_id, row in rows.items() if len(row) != SYS_MENU_VALUE_COUNT}
|
||||
test_case.assertEqual({}, invalid_widths)
|
||||
actual = {
|
||||
@@ -1085,17 +1130,21 @@ def _assert_business_menu_fields(
|
||||
test_case.assertEqual(expected_fields, actual)
|
||||
|
||||
|
||||
def _assert_business_permission_inventory(test_case: unittest.TestCase, sql: str) -> None:
|
||||
def _assert_business_permission_inventory(
|
||||
test_case: unittest.TestCase,
|
||||
sql: str,
|
||||
expected_permissions: frozenset[str] = EXPECTED_PERMISSIONS,
|
||||
) -> None:
|
||||
permission_rows = [
|
||||
row
|
||||
for row in _insert_rows(sql, 'sys_menu')
|
||||
if len(row) > SYS_MENU_PERMS_INDEX
|
||||
and row[SYS_MENU_PERMS_INDEX]
|
||||
and re.match(r'^(?:master|business|report):', row[SYS_MENU_PERMS_INDEX])
|
||||
and re.match(r'^(?:master|business|report|system:testbatch):', row[SYS_MENU_PERMS_INDEX])
|
||||
]
|
||||
test_case.assertTrue(all(len(row) == SYS_MENU_VALUE_COUNT for row in permission_rows))
|
||||
actual_permissions = Counter(row[SYS_MENU_PERMS_INDEX] for row in permission_rows)
|
||||
test_case.assertEqual(Counter(EXPECTED_PERMISSIONS), actual_permissions)
|
||||
test_case.assertEqual(Counter(expected_permissions), actual_permissions)
|
||||
|
||||
|
||||
MENU_PROMOTION_LOCK_STATEMENT = (
|
||||
@@ -1310,6 +1359,57 @@ class SqlContractTest(unittest.TestCase):
|
||||
is_patch=is_patch,
|
||||
)
|
||||
|
||||
def test_test_batch_patches_migrate_legacy_menu_permissions_without_role_grants(self) -> None:
|
||||
legacy_removed_ids = set(LEGACY_REMOVED_BUTTON_SPECS)
|
||||
for path in (TEST_BATCH_MYSQL_PATCH_PATH, TEST_BATCH_PG_PATCH_PATH):
|
||||
with self.subTest(path=path.name):
|
||||
raw = path.read_text(encoding='utf-8')
|
||||
statements = _sql_statements(raw)
|
||||
normalized = [_normalized_sql_statement(statement) for statement in statements]
|
||||
|
||||
role_delete_indexes = [
|
||||
index
|
||||
for index, statement in enumerate(normalized)
|
||||
if re.fullmatch(r'delete from sys_role_menu where menu_id in \([^)]+\)', statement)
|
||||
]
|
||||
menu_delete_indexes = [
|
||||
index
|
||||
for index, statement in enumerate(normalized)
|
||||
if re.fullmatch(r'delete from sys_menu where menu_id in \([^)]+\)', statement)
|
||||
]
|
||||
menu_insert_indexes = [
|
||||
index
|
||||
for index, statement in enumerate(normalized)
|
||||
if statement.startswith('insert into sys_menu values ')
|
||||
]
|
||||
self.assertEqual(1, len(role_delete_indexes))
|
||||
self.assertEqual(1, len(menu_delete_indexes))
|
||||
self.assertEqual(1, len(menu_insert_indexes))
|
||||
role_delete = normalized[role_delete_indexes[0]]
|
||||
menu_delete = normalized[menu_delete_indexes[0]]
|
||||
role_delete_ids = {
|
||||
int(value.strip()) for value in re.search(r'\(([^)]+)\)', role_delete).group(1).split(',')
|
||||
}
|
||||
menu_delete_ids = {
|
||||
int(value.strip()) for value in re.search(r'\(([^)]+)\)', menu_delete).group(1).split(',')
|
||||
}
|
||||
self.assertEqual(legacy_removed_ids, role_delete_ids)
|
||||
self.assertEqual(legacy_removed_ids, menu_delete_ids)
|
||||
self.assertLess(role_delete_indexes[0], menu_delete_indexes[0])
|
||||
self.assertLess(menu_delete_indexes[0], menu_insert_indexes[0])
|
||||
|
||||
inserted_rows = _insert_rows(raw, 'sys_menu')
|
||||
inserted_by_id = {int(row[0]): row for row in inserted_rows}
|
||||
self.assertEqual(TEST_BATCH_MENU_IDS, set(inserted_by_id))
|
||||
self.assertTrue(all(len(row) == SYS_MENU_VALUE_COUNT for row in inserted_by_id.values()))
|
||||
self.assertEqual('测试数据批次', inserted_by_id[519][1])
|
||||
self.assertEqual('1', inserted_by_id[519][2])
|
||||
self.assertEqual('7', inserted_by_id[519][3])
|
||||
self.assertEqual('system:testbatch:list', inserted_by_id[519][13])
|
||||
self.assertEqual(519, int(inserted_by_id[1109][2]))
|
||||
self.assertEqual('system:testbatch:purge', inserted_by_id[1115][13])
|
||||
self.assertNotRegex('\n'.join(normalized), r'\binsert into sys_role_menu\b')
|
||||
|
||||
def test_initializers_define_exact_business_table_set(self) -> None:
|
||||
for filename in INITIALIZERS:
|
||||
with self.subTest(filename=filename):
|
||||
@@ -1357,8 +1457,8 @@ class SqlContractTest(unittest.TestCase):
|
||||
self.assertFalse(_is_postgres_naive_timestamp_with_default_precision('occurred_at timestamp with time zone'))
|
||||
|
||||
def test_initializers_define_fixed_business_menus_and_permissions(self) -> None:
|
||||
self.assertEqual(17, len(EXPECTED_PAGE_PERMISSIONS))
|
||||
self.assertEqual(44, len(EXPECTED_BUTTON_PERMISSIONS))
|
||||
self.assertEqual(18, len(EXPECTED_PAGE_PERMISSIONS))
|
||||
self.assertEqual(43, len(EXPECTED_BUTTON_PERMISSIONS))
|
||||
self.assertFalse(EXPECTED_PAGE_PERMISSIONS & EXPECTED_BUTTON_PERMISSIONS)
|
||||
self.assertEqual(61, len(EXPECTED_PERMISSIONS))
|
||||
self.assertEqual(64, len(EXPECTED_BUSINESS_MENU_FIELDS))
|
||||
@@ -1969,20 +2069,26 @@ class SqlContractTest(unittest.TestCase):
|
||||
self.assertEqual(LEGACY_EXPECTED_FOREIGN_KEYS[table], foreign_keys)
|
||||
self.assertEqual(LEGACY_EXPECTED_CHECKS[table], checks)
|
||||
_assert_business_menu_fields(self, raw, LEGACY_PATCH_BUSINESS_MENU_FIELDS)
|
||||
_assert_business_permission_inventory(self, raw)
|
||||
patch_rows = _business_menu_rows(raw)
|
||||
_assert_business_permission_inventory(self, raw, LEGACY_EXPECTED_PERMISSIONS)
|
||||
patch_rows = _business_menu_rows(raw, LEGACY_BUSINESS_MENU_IDS)
|
||||
mysql_rows = _business_menu_rows((SQL_ROOT / 'shierfeng-fastapi.sql').read_text(encoding='utf-8'))
|
||||
compared_indexes = (0, 1, *range(4, 15))
|
||||
common_menu_ids = LEGACY_BUSINESS_MENU_IDS & BUSINESS_MENU_IDS
|
||||
expected_legacy_rows = {
|
||||
menu_id: tuple(
|
||||
'#' if index == SYS_MENU_ICON_INDEX and menu_id in EXPECTED_BUSINESS_ROOT_ICONS else row[index]
|
||||
for index in compared_indexes
|
||||
)
|
||||
for menu_id, row in mysql_rows.items()
|
||||
if menu_id in common_menu_ids
|
||||
}
|
||||
self.assertEqual(
|
||||
expected_legacy_rows,
|
||||
{menu_id: tuple(row[index] for index in compared_indexes) for menu_id, row in patch_rows.items()},
|
||||
{
|
||||
menu_id: tuple(row[index] for index in compared_indexes)
|
||||
for menu_id, row in patch_rows.items()
|
||||
if menu_id in common_menu_ids
|
||||
},
|
||||
)
|
||||
self.assertRegex(lower, r'\bon\s+duplicate\s+key\s+update\b')
|
||||
self.assertNotRegex(lower, r'\binsert\s+ignore\b')
|
||||
@@ -2017,7 +2123,7 @@ class SqlContractTest(unittest.TestCase):
|
||||
flags=re.S,
|
||||
)
|
||||
self.assertIsNotNone(menu_insert, 'sys_menu seed must use a fail-closed upsert')
|
||||
self.assertEqual(len(BUSINESS_MENU_IDS), len(_insert_rows(menu_insert_statement, 'sys_menu')))
|
||||
self.assertEqual(len(LEGACY_BUSINESS_MENU_IDS), len(_insert_rows(menu_insert_statement, 'sys_menu')))
|
||||
expected_guard = ' and '.join(f'{column} <=> values({column})' for column in MYSQL_MENU_STABLE_COLUMNS)
|
||||
actual_guard = re.sub(r'\s+', ' ', menu_insert.group('guard')).strip()
|
||||
self.assertEqual(expected_guard, actual_guard)
|
||||
@@ -2039,8 +2145,8 @@ class SqlContractTest(unittest.TestCase):
|
||||
verification_columns = tuple(column.strip() for column in verification.group('columns').split(','))
|
||||
self.assertEqual(('menu_id', *MYSQL_MENU_STABLE_COLUMNS), verification_columns)
|
||||
verification_ids = [int(value.strip()) for value in verification.group('ids').split(',')]
|
||||
self.assertEqual(len(BUSINESS_MENU_IDS), len(verification_ids))
|
||||
self.assertEqual(BUSINESS_MENU_IDS, set(verification_ids))
|
||||
self.assertEqual(len(LEGACY_BUSINESS_MENU_IDS), len(verification_ids))
|
||||
self.assertEqual(LEGACY_BUSINESS_MENU_IDS, set(verification_ids))
|
||||
self.assertRegex(raw, r'查询结果必须为\s*64')
|
||||
|
||||
normalized = [_normalized_sql_statement(statement) for statement in statements]
|
||||
@@ -2149,11 +2255,12 @@ class SqlContractTest(unittest.TestCase):
|
||||
self.assertEqual(('menu_id', *MYSQL_MENU_STABLE_COLUMNS), expected_columns)
|
||||
|
||||
expected_rows = _insert_rows(statements[expected_inserts[0]], expected_table)
|
||||
self.assertEqual(len(BUSINESS_MENU_IDS), len(expected_rows))
|
||||
self.assertEqual(len(LEGACY_BUSINESS_MENU_IDS), len(expected_rows))
|
||||
expected_rows_by_id = {int(row[0]): tuple(row) for row in expected_rows}
|
||||
self.assertEqual(BUSINESS_MENU_IDS, set(expected_rows_by_id))
|
||||
self.assertEqual(LEGACY_BUSINESS_MENU_IDS, set(expected_rows_by_id))
|
||||
seed_rows_by_id = {
|
||||
menu_id: tuple(row[: len(expected_columns)]) for menu_id, row in _business_menu_rows(raw).items()
|
||||
menu_id: tuple(row[: len(expected_columns)])
|
||||
for menu_id, row in _business_menu_rows(raw, LEGACY_BUSINESS_MENU_IDS).items()
|
||||
}
|
||||
self.assertEqual(seed_rows_by_id, expected_rows_by_id)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user