from typing import Any, TypeVar from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from common.vo import PageModel 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, FillingReportModel, FillingReportQueryModel, PalletInventoryReportModel, PalletInventoryReportQueryModel, PalletTraceReportModel, PalletTraceReportQueryModel, ReturnReportModel, ReturnReportQueryModel, ShipmentReportModel, ShipmentReportQueryModel, ) RowModelT = TypeVar('RowModelT', bound=BaseModel) class ReportService: """六类只读业务报表服务。""" @staticmethod def _is_admin(current_user: CurrentUserModel) -> bool: return bool(current_user.user and current_user.user.admin) @classmethod def _user_id(cls, current_user: CurrentUserModel) -> int: if current_user.user is None or current_user.user.user_id is None: raise ServiceException(message='当前用户信息无效') return current_user.user.user_id @classmethod async def _warehouse_scope( 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), test_scope) return sorted(set(warehouse_ids)) @classmethod async def _site_scope( 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), test_scope) return sorted(set(site_ids)) @classmethod async def _scopes( 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, test_scope), await cls._site_scope(query_db, current_user, test_scope), ) @staticmethod def _empty_page(query_object: Any) -> PageModel: return PageModel( rows=[], pageNum=query_object.page_num, pageSize=query_object.page_size, total=0, hasNext=False, ) @staticmethod def _convert_page(page: PageModel, row_model: type[RowModelT]) -> PageModel[RowModelT]: rows = [row_model.model_validate(row) for row in page.rows] return page.model_copy(update={'rows': rows}) @classmethod async def get_pallet_inventory_list_services( cls, 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, 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, ) return cls._convert_page(page, PalletInventoryReportModel) @classmethod async def get_filling_report_list_services( cls, query_db: AsyncSession, query_object: FillingReportQueryModel, current_user: CurrentUserModel, test_scope: TestBatchScope, ) -> PageModel[FillingReportModel]: 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) @classmethod async def get_shipment_report_list_services( cls, 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, 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, ) return cls._convert_page(page, ShipmentReportModel) @classmethod async def get_consumption_report_list_services( cls, query_db: AsyncSession, query_object: ConsumptionReportQueryModel, current_user: CurrentUserModel, test_scope: TestBatchScope, ) -> PageModel[ConsumptionReportModel]: 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) @classmethod async def get_return_report_list_services( cls, 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, 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, ) return cls._convert_page(page, ReturnReportModel) @classmethod async def get_pallet_trace_list_services( cls, 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, 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, ) return cls._convert_page(page, PalletTraceReportModel)