功能:新增业务基础资料接口

This commit is contained in:
焦龙言
2026-07-26 10:41:14 +08:00
parent f5d47ad2bb
commit f3eda856b0
8 changed files with 2114 additions and 0 deletions
@@ -0,0 +1,123 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
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 common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.entity.vo.master_vo import CustomerModel, CustomerPageQueryModel, DeleteCustomerModel
from module_business.service.master_service import MasterService
from utils.response_util import ResponseUtil
customer_controller = APIRouterPro(
prefix='/master/customer', tags=['基础资料-客户管理'], dependencies=[PreAuthDependency()]
)
@customer_controller.get(
'/list',
summary='获取客户分页列表接口',
description='用于获取客户分页列表',
response_model=PageResponseModel[CustomerModel],
dependencies=[UserInterfaceAuthDependency('master:customer:list')],
)
async def get_master_customer_list(
request: Request,
customer_page_query: Annotated[CustomerPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
customer_page_query_result = await MasterService.list_customer(query_db, customer_page_query, is_page=True)
return ResponseUtil.success(model_content=customer_page_query_result)
@customer_controller.get(
'/{customer_id}',
summary='获取客户详情接口',
description='用于获取指定客户的详细信息',
response_model=DataResponseModel[CustomerModel],
dependencies=[UserInterfaceAuthDependency('master:customer:query')],
)
async def query_detail_master_customer(
request: Request,
customer_id: Annotated[int, Path(gt=0, description='客户ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
customer_detail_result = await MasterService.detail_customer(query_db, customer_id)
return ResponseUtil.success(data=customer_detail_result)
@customer_controller.post(
'',
summary='新增客户接口',
description='用于新增客户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:customer:add')],
)
@Log(title='客户管理', business_type=BusinessType.INSERT)
async def add_master_customer(
request: Request,
add_customer: CustomerModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
current_time = datetime.now()
add_customer.create_by = current_user.user.user_name
add_customer.create_time = current_time
add_customer.update_by = current_user.user.user_name
add_customer.update_time = current_time
add_customer_result = await MasterService.add_customer(query_db, add_customer)
return ResponseUtil.success(msg=add_customer_result.message)
@customer_controller.put(
'',
summary='编辑客户接口',
description='用于编辑客户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:customer:edit')],
)
@Log(title='客户管理', business_type=BusinessType.UPDATE)
async def edit_master_customer(
request: Request,
edit_customer: CustomerModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_customer.update_by = current_user.user.user_name
edit_customer.update_time = datetime.now()
edit_customer_result = await MasterService.edit_customer(query_db, edit_customer)
return ResponseUtil.success(msg=edit_customer_result.message)
@customer_controller.delete(
'/{customer_ids}',
summary='删除客户接口',
description='用于删除客户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:customer:remove')],
)
@Log(title='客户管理', business_type=BusinessType.DELETE)
async def delete_master_customer(
request: Request,
customer_ids: Annotated[
str,
Path(pattern=r'^[1-9]\d*(,[1-9]\d*)*$', description='需要删除的客户ID'),
],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
delete_customer = DeleteCustomerModel(customerIds=[int(customer_id) for customer_id in customer_ids.split(',')])
delete_customer_result = await MasterService.remove_customer(query_db, delete_customer)
return ResponseUtil.success(msg=delete_customer_result.message)
@@ -0,0 +1,121 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
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 common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.entity.vo.master_vo import DeleteLineModel, LineModel, LinePageQueryModel
from module_business.service.master_service import MasterService
from utils.response_util import ResponseUtil
line_controller = APIRouterPro(prefix='/master/line', tags=['基础资料-生产线管理'], dependencies=[PreAuthDependency()])
@line_controller.get(
'/list',
summary='获取生产线分页列表接口',
description='用于获取生产线分页列表',
response_model=PageResponseModel[LineModel],
dependencies=[UserInterfaceAuthDependency('master:line:list')],
)
async def get_master_line_list(
request: Request,
line_page_query: Annotated[LinePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
line_page_query_result = await MasterService.list_line(query_db, line_page_query, is_page=True)
return ResponseUtil.success(model_content=line_page_query_result)
@line_controller.get(
'/{line_id}',
summary='获取生产线详情接口',
description='用于获取指定生产线的详细信息',
response_model=DataResponseModel[LineModel],
dependencies=[UserInterfaceAuthDependency('master:line:query')],
)
async def query_detail_master_line(
request: Request,
line_id: Annotated[int, Path(gt=0, description='生产线ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
line_detail_result = await MasterService.detail_line(query_db, line_id)
return ResponseUtil.success(data=line_detail_result)
@line_controller.post(
'',
summary='新增生产线接口',
description='用于新增生产线',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:line:add')],
)
@Log(title='生产线管理', business_type=BusinessType.INSERT)
async def add_master_line(
request: Request,
add_line: LineModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
current_time = datetime.now()
add_line.create_by = current_user.user.user_name
add_line.create_time = current_time
add_line.update_by = current_user.user.user_name
add_line.update_time = current_time
add_line_result = await MasterService.add_line(query_db, add_line)
return ResponseUtil.success(msg=add_line_result.message)
@line_controller.put(
'',
summary='编辑生产线接口',
description='用于编辑生产线',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:line:edit')],
)
@Log(title='生产线管理', business_type=BusinessType.UPDATE)
async def edit_master_line(
request: Request,
edit_line: LineModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_line.update_by = current_user.user.user_name
edit_line.update_time = datetime.now()
edit_line_result = await MasterService.edit_line(query_db, edit_line)
return ResponseUtil.success(msg=edit_line_result.message)
@line_controller.delete(
'/{line_ids}',
summary='删除生产线接口',
description='用于删除生产线',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:line:remove')],
)
@Log(title='生产线管理', business_type=BusinessType.DELETE)
async def delete_master_line(
request: Request,
line_ids: Annotated[
str,
Path(pattern=r'^[1-9]\d*(,[1-9]\d*)*$', description='需要删除的生产线ID'),
],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
delete_line = DeleteLineModel(lineIds=[int(line_id) for line_id in line_ids.split(',')])
delete_line_result = await MasterService.remove_line(query_db, delete_line)
return ResponseUtil.success(msg=delete_line_result.message)
@@ -0,0 +1,123 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
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 common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.entity.vo.master_vo import DeleteSiteModel, SiteModel, SitePageQueryModel
from module_business.service.master_service import MasterService
from utils.response_util import ResponseUtil
site_controller = APIRouterPro(
prefix='/master/site', tags=['基础资料-客户现场管理'], dependencies=[PreAuthDependency()]
)
@site_controller.get(
'/list',
summary='获取客户现场分页列表接口',
description='用于获取客户现场分页列表',
response_model=PageResponseModel[SiteModel],
dependencies=[UserInterfaceAuthDependency('master:site:list')],
)
async def get_master_site_list(
request: Request,
site_page_query: Annotated[SitePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
site_page_query_result = await MasterService.list_site(query_db, site_page_query, is_page=True)
return ResponseUtil.success(model_content=site_page_query_result)
@site_controller.get(
'/{site_id}',
summary='获取客户现场详情接口',
description='用于获取指定客户现场的详细信息',
response_model=DataResponseModel[SiteModel],
dependencies=[UserInterfaceAuthDependency('master:site:query')],
)
async def query_detail_master_site(
request: Request,
site_id: Annotated[int, Path(gt=0, description='客户现场ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
site_detail_result = await MasterService.detail_site(query_db, site_id)
return ResponseUtil.success(data=site_detail_result)
@site_controller.post(
'',
summary='新增客户现场接口',
description='用于新增客户现场',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:site:add')],
)
@Log(title='客户现场管理', business_type=BusinessType.INSERT)
async def add_master_site(
request: Request,
add_site: SiteModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
current_time = datetime.now()
add_site.create_by = current_user.user.user_name
add_site.create_time = current_time
add_site.update_by = current_user.user.user_name
add_site.update_time = current_time
add_site_result = await MasterService.add_site(query_db, add_site)
return ResponseUtil.success(msg=add_site_result.message)
@site_controller.put(
'',
summary='编辑客户现场接口',
description='用于编辑客户现场',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:site:edit')],
)
@Log(title='客户现场管理', business_type=BusinessType.UPDATE)
async def edit_master_site(
request: Request,
edit_site: SiteModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_site.update_by = current_user.user.user_name
edit_site.update_time = datetime.now()
edit_site_result = await MasterService.edit_site(query_db, edit_site)
return ResponseUtil.success(msg=edit_site_result.message)
@site_controller.delete(
'/{site_ids}',
summary='删除客户现场接口',
description='用于删除客户现场',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:site:remove')],
)
@Log(title='客户现场管理', business_type=BusinessType.DELETE)
async def delete_master_site(
request: Request,
site_ids: Annotated[
str,
Path(pattern=r'^[1-9]\d*(,[1-9]\d*)*$', description='需要删除的客户现场ID'),
],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
delete_site = DeleteSiteModel(siteIds=[int(site_id) for site_id in site_ids.split(',')])
delete_site_result = await MasterService.remove_site(query_db, delete_site)
return ResponseUtil.success(msg=delete_site_result.message)
@@ -0,0 +1,123 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
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 common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.entity.vo.master_vo import DeleteStrainModel, StrainModel, StrainPageQueryModel
from module_business.service.master_service import MasterService
from utils.response_util import ResponseUtil
strain_controller = APIRouterPro(
prefix='/master/strain', tags=['基础资料-菌种管理'], dependencies=[PreAuthDependency()]
)
@strain_controller.get(
'/list',
summary='获取菌种分页列表接口',
description='用于获取菌种分页列表',
response_model=PageResponseModel[StrainModel],
dependencies=[UserInterfaceAuthDependency('master:strain:list')],
)
async def get_master_strain_list(
request: Request,
strain_page_query: Annotated[StrainPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
strain_page_query_result = await MasterService.list_strain(query_db, strain_page_query, is_page=True)
return ResponseUtil.success(model_content=strain_page_query_result)
@strain_controller.get(
'/{strain_id}',
summary='获取菌种详情接口',
description='用于获取指定菌种的详细信息',
response_model=DataResponseModel[StrainModel],
dependencies=[UserInterfaceAuthDependency('master:strain:query')],
)
async def query_detail_master_strain(
request: Request,
strain_id: Annotated[int, Path(gt=0, description='菌种ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
strain_detail_result = await MasterService.detail_strain(query_db, strain_id)
return ResponseUtil.success(data=strain_detail_result)
@strain_controller.post(
'',
summary='新增菌种接口',
description='用于新增菌种',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:strain:add')],
)
@Log(title='菌种管理', business_type=BusinessType.INSERT)
async def add_master_strain(
request: Request,
add_strain: StrainModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
current_time = datetime.now()
add_strain.create_by = current_user.user.user_name
add_strain.create_time = current_time
add_strain.update_by = current_user.user.user_name
add_strain.update_time = current_time
add_strain_result = await MasterService.add_strain(query_db, add_strain)
return ResponseUtil.success(msg=add_strain_result.message)
@strain_controller.put(
'',
summary='编辑菌种接口',
description='用于编辑菌种',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:strain:edit')],
)
@Log(title='菌种管理', business_type=BusinessType.UPDATE)
async def edit_master_strain(
request: Request,
edit_strain: StrainModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_strain.update_by = current_user.user.user_name
edit_strain.update_time = datetime.now()
edit_strain_result = await MasterService.edit_strain(query_db, edit_strain)
return ResponseUtil.success(msg=edit_strain_result.message)
@strain_controller.delete(
'/{strain_ids}',
summary='删除菌种接口',
description='用于删除菌种',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:strain:remove')],
)
@Log(title='菌种管理', business_type=BusinessType.DELETE)
async def delete_master_strain(
request: Request,
strain_ids: Annotated[
str,
Path(pattern=r'^[1-9]\d*(,[1-9]\d*)*$', description='需要删除的菌种ID'),
],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
delete_strain = DeleteStrainModel(strainIds=[int(strain_id) for strain_id in strain_ids.split(',')])
delete_strain_result = await MasterService.remove_strain(query_db, delete_strain)
return ResponseUtil.success(msg=delete_strain_result.message)
@@ -0,0 +1,125 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
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 common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_business.entity.vo.master_vo import DeleteWarehouseModel, WarehouseModel, WarehousePageQueryModel
from module_business.service.master_service import MasterService
from utils.response_util import ResponseUtil
warehouse_controller = APIRouterPro(
prefix='/master/warehouse', tags=['基础资料-仓库管理'], dependencies=[PreAuthDependency()]
)
@warehouse_controller.get(
'/list',
summary='获取仓库分页列表接口',
description='用于获取仓库分页列表',
response_model=PageResponseModel[WarehouseModel],
dependencies=[UserInterfaceAuthDependency('master:warehouse:list')],
)
async def get_master_warehouse_list(
request: Request,
warehouse_page_query: Annotated[WarehousePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
warehouse_page_query_result = await MasterService.list_warehouse(query_db, warehouse_page_query, is_page=True)
return ResponseUtil.success(model_content=warehouse_page_query_result)
@warehouse_controller.get(
'/{warehouse_id}',
summary='获取仓库详情接口',
description='用于获取指定仓库的详细信息',
response_model=DataResponseModel[WarehouseModel],
dependencies=[UserInterfaceAuthDependency('master:warehouse:query')],
)
async def query_detail_master_warehouse(
request: Request,
warehouse_id: Annotated[int, Path(gt=0, description='仓库ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
warehouse_detail_result = await MasterService.detail_warehouse(query_db, warehouse_id)
return ResponseUtil.success(data=warehouse_detail_result)
@warehouse_controller.post(
'',
summary='新增仓库接口',
description='用于新增仓库',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:warehouse:add')],
)
@Log(title='仓库管理', business_type=BusinessType.INSERT)
async def add_master_warehouse(
request: Request,
add_warehouse: WarehouseModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
current_time = datetime.now()
add_warehouse.create_by = current_user.user.user_name
add_warehouse.create_time = current_time
add_warehouse.update_by = current_user.user.user_name
add_warehouse.update_time = current_time
add_warehouse_result = await MasterService.add_warehouse(query_db, add_warehouse)
return ResponseUtil.success(msg=add_warehouse_result.message)
@warehouse_controller.put(
'',
summary='编辑仓库接口',
description='用于编辑仓库',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:warehouse:edit')],
)
@Log(title='仓库管理', business_type=BusinessType.UPDATE)
async def edit_master_warehouse(
request: Request,
edit_warehouse: WarehouseModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_warehouse.update_by = current_user.user.user_name
edit_warehouse.update_time = datetime.now()
edit_warehouse_result = await MasterService.edit_warehouse(query_db, edit_warehouse)
return ResponseUtil.success(msg=edit_warehouse_result.message)
@warehouse_controller.delete(
'/{warehouse_ids}',
summary='删除仓库接口',
description='用于删除仓库',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('master:warehouse:remove')],
)
@Log(title='仓库管理', business_type=BusinessType.DELETE)
async def delete_master_warehouse(
request: Request,
warehouse_ids: Annotated[
str,
Path(pattern=r'^[1-9]\d*(,[1-9]\d*)*$', description='需要删除的仓库ID'),
],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
delete_warehouse = DeleteWarehouseModel(
warehouseIds=[int(warehouse_id) for warehouse_id in warehouse_ids.split(',')]
)
delete_warehouse_result = await MasterService.remove_warehouse(query_db, delete_warehouse)
return ResponseUtil.success(msg=delete_warehouse_result.message)
@@ -0,0 +1,378 @@
from typing import Any, Literal
from pydantic import BaseModel
from sqlalchemy import ColumnElement, Select, delete, func, or_, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm.attributes import InstrumentedAttribute
from common.vo import PageModel
from module_business.entity.do.master_do import (
BizCustomer,
BizCustomerSite,
BizProductionLine,
BizStrain,
BizUserSite,
BizUserWarehouse,
BizWarehouse,
)
from module_business.entity.do.operation_do import (
BizFillingRecord,
BizInboundOrder,
BizPalletEvent,
BizPalletInventory,
BizReturnOrder,
BizShipmentOrder,
BizUsageRecord,
)
from module_business.entity.vo.master_vo import (
CustomerModel,
CustomerPageQueryModel,
LineModel,
LinePageQueryModel,
SiteModel,
SitePageQueryModel,
StrainModel,
StrainPageQueryModel,
WarehouseModel,
WarehousePageQueryModel,
)
from utils.page_util import PageUtil
MasterResource = Literal['strain', 'customer', 'site', 'line', 'warehouse']
_REFERENCE_COLUMNS: dict[MasterResource, tuple[tuple[InstrumentedAttribute, ...], ...]] = {
'strain': ((BizFillingRecord.strain_id,),),
'customer': ((BizCustomerSite.customer_id,),),
'site': (
(BizProductionLine.site_id,),
(BizUserSite.site_id,),
(BizShipmentOrder.target_site_id,),
(BizUsageRecord.site_id,),
(BizReturnOrder.source_site_id,),
(BizPalletInventory.site_id,),
(BizPalletEvent.before_site_id, BizPalletEvent.after_site_id),
),
'line': (
(BizUsageRecord.line_id,),
(BizPalletInventory.current_line_id,),
(BizPalletEvent.before_line_id, BizPalletEvent.after_line_id),
),
'warehouse': (
(BizUserWarehouse.warehouse_id,),
(BizInboundOrder.warehouse_id,),
(BizFillingRecord.warehouse_id,),
(BizShipmentOrder.source_warehouse_id,),
(BizReturnOrder.target_warehouse_id,),
(BizPalletInventory.warehouse_id,),
(BizPalletEvent.before_warehouse_id, BizPalletEvent.after_warehouse_id),
),
}
class MasterDao:
"""菌种、客户、现场、产线和仓库主数据数据库操作层。"""
@staticmethod
async def _paginate(
db: AsyncSession,
statement: Select,
query_object: BaseModel,
is_page: bool,
) -> PageModel | list[dict[str, Any]]:
return await PageUtil.paginate(
db,
statement,
query_object.page_num,
query_object.page_size,
is_page,
)
@staticmethod
async def _get(
db: AsyncSession,
model: type[Any],
id_column: InstrumentedAttribute,
resource_id: int,
) -> Any | None:
result = await db.execute(select(model).where(id_column == resource_id))
return result.scalar_one_or_none()
@staticmethod
async def _find(
db: AsyncSession,
model: type[Any],
code_column: InstrumentedAttribute,
code: str,
*scope_predicates: ColumnElement[bool],
) -> Any | None:
result = await db.execute(select(model).where(code_column == code, *scope_predicates))
return result.scalar_one_or_none()
@staticmethod
async def _add(
db: AsyncSession,
model: type[Any],
id_field: str,
page_object: BaseModel,
) -> Any:
payload = page_object.model_dump(exclude={id_field})
record = model(**payload)
db.add(record)
await db.flush()
return record
@staticmethod
async def _update(
db: AsyncSession,
model: type[Any],
id_column: InstrumentedAttribute,
id_field: str,
page_object: BaseModel,
) -> None:
payload = page_object.model_dump(
exclude_unset=True,
exclude={'create_by', 'create_time'},
)
resource_id = payload.pop(id_field)
await db.execute(update(model).where(id_column == resource_id).values(**payload))
@staticmethod
async def _delete(
db: AsyncSession,
model: type[Any],
id_column: InstrumentedAttribute,
resource_id: int,
) -> None:
await db.execute(delete(model).where(id_column == resource_id))
@classmethod
async def list_strain(
cls,
db: AsyncSession,
query_object: StrainPageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = []
if query_object.strain_code:
conditions.append(BizStrain.strain_code.like(f'%{query_object.strain_code}%'))
if query_object.strain_name:
conditions.append(BizStrain.strain_name.like(f'%{query_object.strain_name}%'))
if query_object.status:
conditions.append(BizStrain.status == query_object.status)
statement = select(BizStrain).where(*conditions).order_by(BizStrain.strain_id)
return await cls._paginate(db, statement, query_object, is_page)
@classmethod
async def get_strain(cls, db: AsyncSession, strain_id: int) -> BizStrain | None:
return await cls._get(db, BizStrain, BizStrain.strain_id, strain_id)
@classmethod
async def find_strain_by_code(cls, db: AsyncSession, strain_code: str) -> BizStrain | None:
return await cls._find(db, BizStrain, BizStrain.strain_code, strain_code)
@classmethod
async def add_strain(cls, db: AsyncSession, strain: StrainModel) -> BizStrain:
return await cls._add(db, BizStrain, 'strain_id', strain)
@classmethod
async def update_strain(cls, db: AsyncSession, strain: StrainModel) -> None:
await cls._update(db, BizStrain, BizStrain.strain_id, 'strain_id', strain)
@classmethod
async def delete_strain(cls, db: AsyncSession, strain_id: int) -> None:
await cls._delete(db, BizStrain, BizStrain.strain_id, strain_id)
@classmethod
async def list_customer(
cls,
db: AsyncSession,
query_object: CustomerPageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = []
if query_object.customer_code:
conditions.append(BizCustomer.customer_code.like(f'%{query_object.customer_code}%'))
if query_object.customer_name:
conditions.append(BizCustomer.customer_name.like(f'%{query_object.customer_name}%'))
if query_object.status:
conditions.append(BizCustomer.status == query_object.status)
statement = select(BizCustomer).where(*conditions).order_by(BizCustomer.customer_id)
return await cls._paginate(db, statement, query_object, is_page)
@classmethod
async def get_customer(cls, db: AsyncSession, customer_id: int) -> BizCustomer | None:
return await cls._get(db, BizCustomer, BizCustomer.customer_id, customer_id)
@classmethod
async def find_customer_by_code(cls, db: AsyncSession, customer_code: str) -> BizCustomer | None:
return await cls._find(db, BizCustomer, BizCustomer.customer_code, customer_code)
@classmethod
async def add_customer(cls, db: AsyncSession, customer: CustomerModel) -> BizCustomer:
return await cls._add(db, BizCustomer, 'customer_id', customer)
@classmethod
async def update_customer(cls, db: AsyncSession, customer: CustomerModel) -> None:
await cls._update(db, BizCustomer, BizCustomer.customer_id, 'customer_id', customer)
@classmethod
async def delete_customer(cls, db: AsyncSession, customer_id: int) -> None:
await cls._delete(db, BizCustomer, BizCustomer.customer_id, customer_id)
@classmethod
async def list_site(
cls,
db: AsyncSession,
query_object: SitePageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = []
if query_object.customer_id:
conditions.append(BizCustomerSite.customer_id == query_object.customer_id)
if query_object.site_code:
conditions.append(BizCustomerSite.site_code.like(f'%{query_object.site_code}%'))
if query_object.site_name:
conditions.append(BizCustomerSite.site_name.like(f'%{query_object.site_name}%'))
if query_object.status:
conditions.append(BizCustomerSite.status == query_object.status)
statement = select(BizCustomerSite).where(*conditions).order_by(BizCustomerSite.site_id)
return await cls._paginate(db, statement, query_object, is_page)
@classmethod
async def get_site(cls, db: AsyncSession, site_id: int) -> BizCustomerSite | None:
return await cls._get(db, BizCustomerSite, BizCustomerSite.site_id, site_id)
@classmethod
async def find_site_by_code(
cls,
db: AsyncSession,
site_code: str,
customer_id: int,
) -> BizCustomerSite | None:
return await cls._find(
db,
BizCustomerSite,
BizCustomerSite.site_code,
site_code,
BizCustomerSite.customer_id == customer_id,
)
@classmethod
async def add_site(cls, db: AsyncSession, site: SiteModel) -> BizCustomerSite:
return await cls._add(db, BizCustomerSite, 'site_id', site)
@classmethod
async def update_site(cls, db: AsyncSession, site: SiteModel) -> None:
await cls._update(db, BizCustomerSite, BizCustomerSite.site_id, 'site_id', site)
@classmethod
async def delete_site(cls, db: AsyncSession, site_id: int) -> None:
await cls._delete(db, BizCustomerSite, BizCustomerSite.site_id, site_id)
@classmethod
async def list_line(
cls,
db: AsyncSession,
query_object: LinePageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = []
if query_object.site_id:
conditions.append(BizProductionLine.site_id == query_object.site_id)
if query_object.line_code:
conditions.append(BizProductionLine.line_code.like(f'%{query_object.line_code}%'))
if query_object.line_name:
conditions.append(BizProductionLine.line_name.like(f'%{query_object.line_name}%'))
if query_object.status:
conditions.append(BizProductionLine.status == query_object.status)
statement = select(BizProductionLine).where(*conditions).order_by(BizProductionLine.line_id)
return await cls._paginate(db, statement, query_object, is_page)
@classmethod
async def get_line(cls, db: AsyncSession, line_id: int) -> BizProductionLine | None:
return await cls._get(db, BizProductionLine, BizProductionLine.line_id, line_id)
@classmethod
async def find_line_by_code(
cls,
db: AsyncSession,
line_code: str,
site_id: int,
) -> BizProductionLine | None:
return await cls._find(
db,
BizProductionLine,
BizProductionLine.line_code,
line_code,
BizProductionLine.site_id == site_id,
)
@classmethod
async def add_line(cls, db: AsyncSession, line: LineModel) -> BizProductionLine:
return await cls._add(db, BizProductionLine, 'line_id', line)
@classmethod
async def update_line(cls, db: AsyncSession, line: LineModel) -> None:
await cls._update(db, BizProductionLine, BizProductionLine.line_id, 'line_id', line)
@classmethod
async def delete_line(cls, db: AsyncSession, line_id: int) -> None:
await cls._delete(db, BizProductionLine, BizProductionLine.line_id, line_id)
@classmethod
async def list_warehouse(
cls,
db: AsyncSession,
query_object: WarehousePageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = []
if query_object.warehouse_code:
conditions.append(BizWarehouse.warehouse_code.like(f'%{query_object.warehouse_code}%'))
if query_object.warehouse_name:
conditions.append(BizWarehouse.warehouse_name.like(f'%{query_object.warehouse_name}%'))
if query_object.status:
conditions.append(BizWarehouse.status == query_object.status)
statement = select(BizWarehouse).where(*conditions).order_by(BizWarehouse.warehouse_id)
return await cls._paginate(db, statement, query_object, is_page)
@classmethod
async def get_warehouse(cls, db: AsyncSession, warehouse_id: int) -> BizWarehouse | None:
return await cls._get(db, BizWarehouse, BizWarehouse.warehouse_id, warehouse_id)
@classmethod
async def find_warehouse_by_code(cls, db: AsyncSession, warehouse_code: str) -> BizWarehouse | None:
return await cls._find(db, BizWarehouse, BizWarehouse.warehouse_code, warehouse_code)
@classmethod
async def add_warehouse(cls, db: AsyncSession, warehouse: WarehouseModel) -> BizWarehouse:
return await cls._add(db, BizWarehouse, 'warehouse_id', warehouse)
@classmethod
async def update_warehouse(cls, db: AsyncSession, warehouse: WarehouseModel) -> None:
await cls._update(db, BizWarehouse, BizWarehouse.warehouse_id, 'warehouse_id', warehouse)
@classmethod
async def delete_warehouse(cls, db: AsyncSession, warehouse_id: int) -> None:
await cls._delete(db, BizWarehouse, BizWarehouse.warehouse_id, warehouse_id)
@classmethod
async def count_references(
cls,
db: AsyncSession,
resource_type: MasterResource,
resource_id: int,
) -> int:
"""统计主数据的所有直接外键引用;同表的多个位置字段按一行计数。"""
references = _REFERENCE_COLUMNS.get(resource_type)
if references is None:
raise ValueError(f'不支持的主数据类型:{resource_type}')
total = 0
for columns in references:
predicates = [column == resource_id for column in columns]
predicate = predicates[0] if len(predicates) == 1 else or_(*predicates)
result = await db.execute(select(func.count('*')).select_from(columns[0].class_).where(predicate))
total += result.scalar() or 0
return total
@@ -0,0 +1,375 @@
from typing import Any, Literal
from pydantic import BaseModel
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from common.vo import CrudResponseModel, PageModel
from exceptions.exception import ServiceException, ServiceWarning
from module_business.dao.master_dao import MasterDao
from module_business.entity.vo.master_vo import (
CustomerModel,
CustomerPageQueryModel,
DeleteCustomerModel,
DeleteLineModel,
DeleteSiteModel,
DeleteStrainModel,
DeleteWarehouseModel,
LineModel,
LinePageQueryModel,
SiteModel,
SitePageQueryModel,
StrainModel,
StrainPageQueryModel,
WarehouseModel,
WarehousePageQueryModel,
)
MasterResource = Literal['strain', 'customer', 'site', 'line', 'warehouse']
_RESOURCE_CONFIG: dict[MasterResource, dict[str, Any]] = {
'strain': {
'label': '菌种',
'id_field': 'strain_id',
'code_field': 'strain_code',
'ids_field': 'strain_ids',
'vo': StrainModel,
},
'customer': {
'label': '客户',
'id_field': 'customer_id',
'code_field': 'customer_code',
'ids_field': 'customer_ids',
'vo': CustomerModel,
},
'site': {
'label': '客户现场',
'id_field': 'site_id',
'code_field': 'site_code',
'ids_field': 'site_ids',
'vo': SiteModel,
},
'line': {
'label': '生产线',
'id_field': 'line_id',
'code_field': 'line_code',
'ids_field': 'line_ids',
'vo': LineModel,
},
'warehouse': {
'label': '仓库',
'id_field': 'warehouse_id',
'code_field': 'warehouse_code',
'ids_field': 'warehouse_ids',
'vo': WarehouseModel,
},
}
class MasterService:
"""菌种、客户、现场、产线和仓库主数据服务层。"""
@staticmethod
async def _validate_parent(db: AsyncSession, resource: MasterResource, page_object: BaseModel) -> None:
if resource == 'site':
customer = await MasterDao.get_customer(db, page_object.customer_id)
if customer is None:
raise ServiceException(message='目标客户不存在')
if customer.status != '0':
raise ServiceException(message='目标客户已停用')
elif resource == 'line':
site = await MasterDao.get_site(db, page_object.site_id)
if site is None:
raise ServiceException(message='目标客户现场不存在')
if site.status != '0':
raise ServiceException(message='目标客户现场已停用')
@staticmethod
async def _find_duplicate(
db: AsyncSession,
resource: MasterResource,
page_object: BaseModel,
) -> Any | None:
if resource == 'site':
return await MasterDao.find_site_by_code(
db,
page_object.site_code,
page_object.customer_id,
)
if resource == 'line':
return await MasterDao.find_line_by_code(
db,
page_object.line_code,
page_object.site_id,
)
code_field = _RESOURCE_CONFIG[resource]['code_field']
return await getattr(MasterDao, f'find_{resource}_by_code')(
db,
getattr(page_object, code_field),
)
@classmethod
async def _validate_unique(
cls,
db: AsyncSession,
resource: MasterResource,
page_object: BaseModel,
current_id: int | None = None,
) -> None:
duplicate = await cls._find_duplicate(db, resource, page_object)
if duplicate is None:
return
config = _RESOURCE_CONFIG[resource]
duplicate_id = getattr(duplicate, config['id_field'], None)
if current_id is None or duplicate_id != current_id:
code = getattr(page_object, config['code_field'])
raise ServiceException(message=f'{config["label"]}编码{code}已存在')
@staticmethod
def _extract_ids(resource: MasterResource, value: int | BaseModel) -> list[int]:
ids = [value] if isinstance(value, int) else list(getattr(value, _RESOURCE_CONFIG[resource]['ids_field']))
if not ids or any(resource_id <= 0 for resource_id in ids):
raise ServiceException(message='主数据ID必须为正整数')
if len(ids) != len(set(ids)):
raise ServiceException(message='主数据ID不能重复')
return ids
@classmethod
async def _list(
cls,
db: AsyncSession,
resource: MasterResource,
query_object: BaseModel,
is_page: bool,
) -> PageModel | list[dict[str, Any]]:
return await getattr(MasterDao, f'list_{resource}')(db, query_object, is_page)
@classmethod
async def _detail(cls, db: AsyncSession, resource: MasterResource, resource_id: int) -> BaseModel:
config = _RESOURCE_CONFIG[resource]
record = await getattr(MasterDao, f'get_{resource}')(db, resource_id)
if record is None:
raise ServiceException(message=f'{config["label"]}不存在')
return config['vo'].model_validate(record)
@classmethod
async def _add(
cls,
db: AsyncSession,
resource: MasterResource,
page_object: BaseModel,
) -> CrudResponseModel:
config = _RESOURCE_CONFIG[resource]
try:
await cls._validate_parent(db, resource, page_object)
await cls._validate_unique(db, resource, page_object)
safe_object = page_object.model_copy(update={config['id_field']: None})
await getattr(MasterDao, f'add_{resource}')(db, safe_object)
await db.commit()
return CrudResponseModel(is_success=True, message='新增成功')
except IntegrityError:
await db.rollback()
raise ServiceException(message=f'新增{config["label"]}失败,编码已存在或关联数据无效') from None
except Exception:
await db.rollback()
raise
@classmethod
async def _edit(
cls,
db: AsyncSession,
resource: MasterResource,
page_object: BaseModel,
) -> CrudResponseModel:
config = _RESOURCE_CONFIG[resource]
try:
resource_id = getattr(page_object, config['id_field'])
if resource_id is None:
raise ServiceException(message=f'{config["label"]}ID不能为空')
current = await getattr(MasterDao, f'get_{resource}')(db, resource_id)
if current is None:
raise ServiceException(message=f'{config["label"]}不存在')
await cls._validate_parent(db, resource, page_object)
await cls._validate_unique(db, resource, page_object, resource_id)
await getattr(MasterDao, f'update_{resource}')(db, page_object)
await db.commit()
return CrudResponseModel(is_success=True, message='更新成功')
except IntegrityError:
await db.rollback()
raise ServiceException(message=f'修改{config["label"]}失败,编码已存在或关联数据无效') from None
except Exception:
await db.rollback()
raise
@classmethod
async def _remove(
cls,
db: AsyncSession,
resource: MasterResource,
value: int | BaseModel,
) -> CrudResponseModel:
config = _RESOURCE_CONFIG[resource]
try:
resource_ids = cls._extract_ids(resource, value)
for resource_id in resource_ids:
if await MasterDao.count_references(db, resource, resource_id) > 0:
raise ServiceWarning(message=f'{config["label"]}已被引用,只能停用,不能删除')
if await getattr(MasterDao, f'get_{resource}')(db, resource_id) is None:
raise ServiceException(message=f'{config["label"]}不存在')
for resource_id in resource_ids:
await getattr(MasterDao, f'delete_{resource}')(db, resource_id)
await db.commit()
return CrudResponseModel(is_success=True, message='删除成功')
except IntegrityError:
await db.rollback()
raise ServiceException(message=f'删除{config["label"]}失败,该数据仍被引用') from None
except Exception:
await db.rollback()
raise
@classmethod
async def list_strain(
cls,
db: AsyncSession,
query_object: StrainPageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
return await cls._list(db, 'strain', query_object, is_page)
@classmethod
async def detail_strain(cls, db: AsyncSession, strain_id: int) -> StrainModel:
return await cls._detail(db, 'strain', strain_id)
@classmethod
async def add_strain(cls, db: AsyncSession, strain: StrainModel) -> CrudResponseModel:
return await cls._add(db, 'strain', strain)
@classmethod
async def edit_strain(cls, db: AsyncSession, strain: StrainModel) -> CrudResponseModel:
return await cls._edit(db, 'strain', strain)
@classmethod
async def remove_strain(
cls,
db: AsyncSession,
value: int | DeleteStrainModel,
) -> CrudResponseModel:
return await cls._remove(db, 'strain', value)
@classmethod
async def list_customer(
cls,
db: AsyncSession,
query_object: CustomerPageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
return await cls._list(db, 'customer', query_object, is_page)
@classmethod
async def detail_customer(cls, db: AsyncSession, customer_id: int) -> CustomerModel:
return await cls._detail(db, 'customer', customer_id)
@classmethod
async def add_customer(cls, db: AsyncSession, customer: CustomerModel) -> CrudResponseModel:
return await cls._add(db, 'customer', customer)
@classmethod
async def edit_customer(cls, db: AsyncSession, customer: CustomerModel) -> CrudResponseModel:
return await cls._edit(db, 'customer', customer)
@classmethod
async def remove_customer(
cls,
db: AsyncSession,
value: int | DeleteCustomerModel,
) -> CrudResponseModel:
return await cls._remove(db, 'customer', value)
@classmethod
async def list_site(
cls,
db: AsyncSession,
query_object: SitePageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
return await cls._list(db, 'site', query_object, is_page)
@classmethod
async def detail_site(cls, db: AsyncSession, site_id: int) -> SiteModel:
return await cls._detail(db, 'site', site_id)
@classmethod
async def add_site(cls, db: AsyncSession, site: SiteModel) -> CrudResponseModel:
return await cls._add(db, 'site', site)
@classmethod
async def edit_site(cls, db: AsyncSession, site: SiteModel) -> CrudResponseModel:
return await cls._edit(db, 'site', site)
@classmethod
async def remove_site(
cls,
db: AsyncSession,
value: int | DeleteSiteModel,
) -> CrudResponseModel:
return await cls._remove(db, 'site', value)
@classmethod
async def list_line(
cls,
db: AsyncSession,
query_object: LinePageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
return await cls._list(db, 'line', query_object, is_page)
@classmethod
async def detail_line(cls, db: AsyncSession, line_id: int) -> LineModel:
return await cls._detail(db, 'line', line_id)
@classmethod
async def add_line(cls, db: AsyncSession, line: LineModel) -> CrudResponseModel:
return await cls._add(db, 'line', line)
@classmethod
async def edit_line(cls, db: AsyncSession, line: LineModel) -> CrudResponseModel:
return await cls._edit(db, 'line', line)
@classmethod
async def remove_line(
cls,
db: AsyncSession,
value: int | DeleteLineModel,
) -> CrudResponseModel:
return await cls._remove(db, 'line', value)
@classmethod
async def list_warehouse(
cls,
db: AsyncSession,
query_object: WarehousePageQueryModel,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
return await cls._list(db, 'warehouse', query_object, is_page)
@classmethod
async def detail_warehouse(cls, db: AsyncSession, warehouse_id: int) -> WarehouseModel:
return await cls._detail(db, 'warehouse', warehouse_id)
@classmethod
async def add_warehouse(cls, db: AsyncSession, warehouse: WarehouseModel) -> CrudResponseModel:
return await cls._add(db, 'warehouse', warehouse)
@classmethod
async def edit_warehouse(cls, db: AsyncSession, warehouse: WarehouseModel) -> CrudResponseModel:
return await cls._edit(db, 'warehouse', warehouse)
@classmethod
async def remove_warehouse(
cls,
db: AsyncSession,
value: int | DeleteWarehouseModel,
) -> CrudResponseModel:
return await cls._remove(db, 'warehouse', value)