安全:隔离报表选项扫码与首页数据

This commit is contained in:
焦龙言
2026-09-23 12:37:30 +08:00
parent 5a76fe7521
commit c97f6ed3bd
8 changed files with 429 additions and 62 deletions
@@ -11,6 +11,8 @@ from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.router import APIRouterPro
from common.vo import PageResponseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.dependency.test_batch_dependency import TestBatchScopeDependency
from module_business.domain.test_batch_scope import TestBatchScope
from module_business.entity.vo.report_vo import (
ConsumptionReportModel,
ConsumptionReportQueryModel,
@@ -46,8 +48,9 @@ async def get_pallet_inventory_report_list(
query_object: Annotated[PalletInventoryReportQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
test_scope: Annotated[TestBatchScope, TestBatchScopeDependency()],
) -> Response:
result = await ReportService.get_pallet_inventory_list_services(query_db, query_object, current_user)
result = await ReportService.get_pallet_inventory_list_services(query_db, query_object, current_user, test_scope)
return ResponseUtil.success(model_content=result)
@@ -62,8 +65,9 @@ async def get_filling_report_list(
query_object: Annotated[FillingReportQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
test_scope: Annotated[TestBatchScope, TestBatchScopeDependency()],
) -> Response:
result = await ReportService.get_filling_report_list_services(query_db, query_object, current_user)
result = await ReportService.get_filling_report_list_services(query_db, query_object, current_user, test_scope)
return ResponseUtil.success(model_content=result)
@@ -78,8 +82,9 @@ async def get_shipment_report_list(
query_object: Annotated[ShipmentReportQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
test_scope: Annotated[TestBatchScope, TestBatchScopeDependency()],
) -> Response:
result = await ReportService.get_shipment_report_list_services(query_db, query_object, current_user)
result = await ReportService.get_shipment_report_list_services(query_db, query_object, current_user, test_scope)
return ResponseUtil.success(model_content=result)
@@ -94,8 +99,9 @@ async def get_consumption_report_list(
query_object: Annotated[ConsumptionReportQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
test_scope: Annotated[TestBatchScope, TestBatchScopeDependency()],
) -> Response:
result = await ReportService.get_consumption_report_list_services(query_db, query_object, current_user)
result = await ReportService.get_consumption_report_list_services(query_db, query_object, current_user, test_scope)
return ResponseUtil.success(model_content=result)
@@ -110,8 +116,9 @@ async def get_return_report_list(
query_object: Annotated[ReturnReportQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
test_scope: Annotated[TestBatchScope, TestBatchScopeDependency()],
) -> Response:
result = await ReportService.get_return_report_list_services(query_db, query_object, current_user)
result = await ReportService.get_return_report_list_services(query_db, query_object, current_user, test_scope)
return ResponseUtil.success(model_content=result)
@@ -126,6 +133,7 @@ async def get_pallet_trace_report_list(
query_object: Annotated[PalletTraceReportQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
test_scope: Annotated[TestBatchScope, TestBatchScopeDependency()],
) -> Response:
result = await ReportService.get_pallet_trace_list_services(query_db, query_object, current_user)
result = await ReportService.get_pallet_trace_list_services(query_db, query_object, current_user, test_scope)
return ResponseUtil.success(model_content=result)
@@ -1,7 +1,8 @@
from sqlalchemy import delete, select
from sqlalchemy.ext.asyncio import AsyncSession
from module_business.entity.do.master_do import BizUserSite, BizUserWarehouse
from module_business.domain.test_batch_scope import TestBatchScope, batch_scope_condition
from module_business.entity.do.master_do import BizCustomerSite, BizUserSite, BizUserWarehouse, BizWarehouse
class AccessDao:
@@ -48,16 +49,44 @@ class AccessDao:
return mapped_user_id is not None
@classmethod
async def list_user_warehouse_ids(cls, db: AsyncSession, user_id: int) -> list[int]:
"""获取用户关联的仓库 ID 列表。"""
result = await db.execute(select(BizUserWarehouse.warehouse_id).where(BizUserWarehouse.user_id == user_id))
async def list_user_warehouse_ids(
cls,
db: AsyncSession,
user_id: int,
scope: TestBatchScope | None = None,
) -> list[int]:
"""获取用户关联且处于当前批次作用域的仓库 ID 列表。"""
conditions = [BizUserWarehouse.user_id == user_id]
if scope is not None:
conditions.append(batch_scope_condition(BizWarehouse.test_batch_id, scope))
statement = (
select(BizUserWarehouse.warehouse_id)
.select_from(BizUserWarehouse)
.join(BizWarehouse, BizWarehouse.warehouse_id == BizUserWarehouse.warehouse_id)
.where(*conditions)
)
result = await db.execute(statement)
return list(result.scalars().all())
@classmethod
async def list_user_site_ids(cls, db: AsyncSession, user_id: int) -> list[int]:
"""获取用户关联的客户现场 ID 列表。"""
result = await db.execute(select(BizUserSite.site_id).where(BizUserSite.user_id == user_id))
async def list_user_site_ids(
cls,
db: AsyncSession,
user_id: int,
scope: TestBatchScope | None = None,
) -> list[int]:
"""获取用户关联且处于当前批次作用域的客户现场 ID 列表。"""
conditions = [BizUserSite.user_id == user_id]
if scope is not None:
conditions.append(batch_scope_condition(BizCustomerSite.test_batch_id, scope))
statement = (
select(BizUserSite.site_id)
.select_from(BizUserSite)
.join(BizCustomerSite, BizCustomerSite.site_id == BizUserSite.site_id)
.where(*conditions)
)
result = await db.execute(statement)
return list(result.scalars().all())
@@ -9,6 +9,7 @@ from sqlalchemy.orm.attributes import InstrumentedAttribute
from common.vo import PageModel
from module_admin.entity.do.user_do import SysUser
from module_business.domain.enums import DocumentStatus, PalletEventType
from module_business.domain.test_batch_scope import TestBatchScope, batch_scope_condition
from module_business.entity.do.master_do import (
BizCustomer,
BizCustomerSite,
@@ -74,6 +75,15 @@ class ReportDao:
normalized_ids = sorted(set(scope_ids))
return column.in_(normalized_ids) if normalized_ids else false()
@staticmethod
def _joined_scope_condition(
id_column: InstrumentedAttribute,
scope_column: InstrumentedAttribute,
scope: TestBatchScope,
) -> ColumnElement[bool]:
"""保留空的可选 join,同时拒绝已存在的跨批次关联记录。"""
return or_(id_column.is_(None), batch_scope_condition(scope_column, scope))
@classmethod
def _or_scope_conditions(
cls,
@@ -140,6 +150,7 @@ class ReportDao:
cls,
db: AsyncSession,
query_object: PalletInventoryReportQueryModel,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> PageModel[PalletInventoryReportModel]:
@@ -148,9 +159,19 @@ class ReportDao:
current_line = aliased(BizProductionLine, name='current_line')
active_filling = aliased(BizFillingRecord, name='active_filling')
conditions = cls._or_scope_conditions(
(BizPalletInventory.warehouse_id, warehouse_ids),
(BizPalletInventory.site_id, site_ids),
conditions = [
batch_scope_condition(BizPalletInventory.test_batch_id, scope),
batch_scope_condition(BizPallet.test_batch_id, scope),
cls._joined_scope_condition(active_filling.filling_id, active_filling.test_batch_id, scope),
cls._joined_scope_condition(current_warehouse.warehouse_id, current_warehouse.test_batch_id, scope),
cls._joined_scope_condition(current_site.site_id, current_site.test_batch_id, scope),
cls._joined_scope_condition(current_line.line_id, current_line.test_batch_id, scope),
]
conditions.extend(
cls._or_scope_conditions(
(BizPalletInventory.warehouse_id, warehouse_ids),
(BizPalletInventory.site_id, site_ids),
)
)
if query_object.pallet_code:
conditions.append(BizPallet.pallet_code.like(f'%{query_object.pallet_code}%'))
@@ -209,10 +230,15 @@ class ReportDao:
cls,
db: AsyncSession,
query_object: FillingReportQueryModel,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
) -> PageModel[FillingReportModel]:
operator_user = aliased(SysUser, name='operator_user')
conditions = []
conditions = [
batch_scope_condition(BizFillingRecord.test_batch_id, scope),
batch_scope_condition(BizPallet.test_batch_id, scope),
cls._joined_scope_condition(BizWarehouse.warehouse_id, BizWarehouse.test_batch_id, scope),
]
warehouse_scope = cls._scope_condition(BizFillingRecord.warehouse_id, warehouse_ids)
if warehouse_scope is not None:
conditions.append(warehouse_scope)
@@ -264,13 +290,22 @@ class ReportDao:
cls,
db: AsyncSession,
query_object: ShipmentReportQueryModel,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> PageModel[ShipmentReportModel]:
source_warehouse = aliased(BizWarehouse, name='source_warehouse')
target_site = aliased(BizCustomerSite, name='target_site')
target_customer = aliased(BizCustomer, name='target_customer')
conditions = [BizShipmentOrder.status == DocumentStatus.CONFIRMED.value]
conditions = [
batch_scope_condition(BizShipmentOrder.test_batch_id, scope),
batch_scope_condition(BizShipmentItem.test_batch_id, scope),
batch_scope_condition(BizPallet.test_batch_id, scope),
cls._joined_scope_condition(source_warehouse.warehouse_id, source_warehouse.test_batch_id, scope),
cls._joined_scope_condition(target_site.site_id, target_site.test_batch_id, scope),
cls._joined_scope_condition(target_customer.customer_id, target_customer.test_batch_id, scope),
BizShipmentOrder.status == DocumentStatus.CONFIRMED.value,
]
warehouse_scope = cls._scope_condition(BizShipmentOrder.source_warehouse_id, warehouse_ids)
site_scope = cls._scope_condition(BizShipmentOrder.target_site_id, site_ids)
if warehouse_scope is not None:
@@ -334,10 +369,18 @@ class ReportDao:
cls,
db: AsyncSession,
query_object: ConsumptionReportQueryModel,
scope: TestBatchScope,
site_ids: list[int] | None = None,
) -> PageModel[ConsumptionReportModel]:
operator_user = aliased(SysUser, name='operator_user')
conditions = []
conditions = [
batch_scope_condition(BizUsageRecord.test_batch_id, scope),
batch_scope_condition(BizPallet.test_batch_id, scope),
batch_scope_condition(BizFillingRecord.test_batch_id, scope),
batch_scope_condition(BizCustomerSite.test_batch_id, scope),
batch_scope_condition(BizProductionLine.test_batch_id, scope),
cls._joined_scope_condition(BizCustomer.customer_id, BizCustomer.test_batch_id, scope),
]
site_scope = cls._scope_condition(BizUsageRecord.site_id, site_ids)
if site_scope is not None:
conditions.append(site_scope)
@@ -400,14 +443,24 @@ class ReportDao:
cls,
db: AsyncSession,
query_object: ReturnReportQueryModel,
scope: TestBatchScope,
site_ids: list[int] | None = None,
warehouse_ids: list[int] | None = None,
) -> PageModel[ReturnReportModel]:
source_site = aliased(BizCustomerSite, name='source_site')
target_warehouse = aliased(BizWarehouse, name='target_warehouse')
conditions = cls._or_scope_conditions(
(BizReturnOrder.source_site_id, site_ids),
(BizReturnOrder.target_warehouse_id, warehouse_ids),
conditions = [
batch_scope_condition(BizReturnOrder.test_batch_id, scope),
batch_scope_condition(BizReturnItem.test_batch_id, scope),
batch_scope_condition(BizPallet.test_batch_id, scope),
cls._joined_scope_condition(source_site.site_id, source_site.test_batch_id, scope),
cls._joined_scope_condition(target_warehouse.warehouse_id, target_warehouse.test_batch_id, scope),
]
conditions.extend(
cls._or_scope_conditions(
(BizReturnOrder.source_site_id, site_ids),
(BizReturnOrder.target_warehouse_id, warehouse_ids),
)
)
if query_object.return_no:
conditions.append(BizReturnOrder.return_no.like(f'%{query_object.return_no}%'))
@@ -458,6 +511,7 @@ class ReportDao:
cls,
db: AsyncSession,
query_object: PalletTraceReportQueryModel,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> PageModel[PalletTraceReportModel]:
@@ -468,7 +522,17 @@ class ReportDao:
before_line = aliased(BizProductionLine, name='before_line')
after_line = aliased(BizProductionLine, name='after_line')
operator_user = aliased(SysUser, name='operator_user')
conditions = cls._pallet_trace_scope_conditions(warehouse_ids, site_ids)
conditions = [
batch_scope_condition(BizPalletEvent.test_batch_id, scope),
batch_scope_condition(BizPallet.test_batch_id, scope),
cls._joined_scope_condition(before_warehouse.warehouse_id, before_warehouse.test_batch_id, scope),
cls._joined_scope_condition(after_warehouse.warehouse_id, after_warehouse.test_batch_id, scope),
cls._joined_scope_condition(before_site.site_id, before_site.test_batch_id, scope),
cls._joined_scope_condition(after_site.site_id, after_site.test_batch_id, scope),
cls._joined_scope_condition(before_line.line_id, before_line.test_batch_id, scope),
cls._joined_scope_condition(after_line.line_id, after_line.test_batch_id, scope),
]
conditions.extend(cls._pallet_trace_scope_conditions(warehouse_ids, site_ids))
if query_object.pallet_code:
conditions.append(BizPallet.pallet_code.like(f'%{query_object.pallet_code}%'))
if query_object.event_type:
@@ -8,6 +8,7 @@ from exceptions.exception import ServiceException
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.dao.access_dao import AccessDao
from module_business.dao.report_dao import ReportDao
from module_business.domain.test_batch_scope import TestBatchScope
from module_business.entity.vo.report_vo import (
ConsumptionReportModel,
ConsumptionReportQueryModel,
@@ -44,10 +45,11 @@ class ReportService:
cls,
query_db: AsyncSession,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> list[int] | None:
if cls._is_admin(current_user):
return None
warehouse_ids = await AccessDao.list_user_warehouse_ids(query_db, cls._user_id(current_user))
warehouse_ids = await AccessDao.list_user_warehouse_ids(query_db, cls._user_id(current_user), test_scope)
return sorted(set(warehouse_ids))
@classmethod
@@ -55,10 +57,11 @@ class ReportService:
cls,
query_db: AsyncSession,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> list[int] | None:
if cls._is_admin(current_user):
return None
site_ids = await AccessDao.list_user_site_ids(query_db, cls._user_id(current_user))
site_ids = await AccessDao.list_user_site_ids(query_db, cls._user_id(current_user), test_scope)
return sorted(set(site_ids))
@classmethod
@@ -66,12 +69,13 @@ class ReportService:
cls,
query_db: AsyncSession,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> tuple[list[int] | None, list[int] | None]:
if cls._is_admin(current_user):
return None, None
return (
await cls._warehouse_scope(query_db, current_user),
await cls._site_scope(query_db, current_user),
await cls._warehouse_scope(query_db, current_user, test_scope),
await cls._site_scope(query_db, current_user, test_scope),
)
@staticmethod
@@ -95,13 +99,15 @@ class ReportService:
query_db: AsyncSession,
query_object: PalletInventoryReportQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PageModel[PalletInventoryReportModel]:
warehouse_ids, site_ids = await cls._scopes(query_db, current_user)
warehouse_ids, site_ids = await cls._scopes(query_db, current_user, test_scope)
if warehouse_ids == [] and site_ids == []:
return cls._empty_page(query_object)
page = await ReportDao.get_pallet_inventory_list(
query_db,
query_object,
test_scope,
warehouse_ids=warehouse_ids,
site_ids=site_ids,
)
@@ -113,13 +119,15 @@ class ReportService:
query_db: AsyncSession,
query_object: FillingReportQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PageModel[FillingReportModel]:
warehouse_ids = await cls._warehouse_scope(query_db, current_user)
warehouse_ids = await cls._warehouse_scope(query_db, current_user, test_scope)
if warehouse_ids == []:
return cls._empty_page(query_object)
page = await ReportDao.get_filling_report_list(
query_db,
query_object,
test_scope,
warehouse_ids=warehouse_ids,
)
return cls._convert_page(page, FillingReportModel)
@@ -130,13 +138,15 @@ class ReportService:
query_db: AsyncSession,
query_object: ShipmentReportQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PageModel[ShipmentReportModel]:
warehouse_ids, site_ids = await cls._scopes(query_db, current_user)
warehouse_ids, site_ids = await cls._scopes(query_db, current_user, test_scope)
if warehouse_ids == [] or site_ids == []:
return cls._empty_page(query_object)
page = await ReportDao.get_shipment_report_list(
query_db,
query_object,
test_scope,
warehouse_ids=warehouse_ids,
site_ids=site_ids,
)
@@ -148,13 +158,15 @@ class ReportService:
query_db: AsyncSession,
query_object: ConsumptionReportQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PageModel[ConsumptionReportModel]:
site_ids = await cls._site_scope(query_db, current_user)
site_ids = await cls._site_scope(query_db, current_user, test_scope)
if site_ids == []:
return cls._empty_page(query_object)
page = await ReportDao.get_consumption_report_list(
query_db,
query_object,
test_scope,
site_ids=site_ids,
)
return cls._convert_page(page, ConsumptionReportModel)
@@ -165,13 +177,15 @@ class ReportService:
query_db: AsyncSession,
query_object: ReturnReportQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PageModel[ReturnReportModel]:
warehouse_ids, site_ids = await cls._scopes(query_db, current_user)
warehouse_ids, site_ids = await cls._scopes(query_db, current_user, test_scope)
if warehouse_ids == [] and site_ids == []:
return cls._empty_page(query_object)
page = await ReportDao.get_return_report_list(
query_db,
query_object,
test_scope,
site_ids=site_ids,
warehouse_ids=warehouse_ids,
)
@@ -183,13 +197,15 @@ class ReportService:
query_db: AsyncSession,
query_object: PalletTraceReportQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PageModel[PalletTraceReportModel]:
warehouse_ids, site_ids = await cls._scopes(query_db, current_user)
warehouse_ids, site_ids = await cls._scopes(query_db, current_user, test_scope)
if warehouse_ids == [] and site_ids == []:
return cls._empty_page(query_object)
page = await ReportDao.get_pallet_trace_list(
query_db,
query_object,
test_scope,
warehouse_ids=warehouse_ids,
site_ids=site_ids,
)