Files
ShiErFeng/shierfeng-fastapi-backend/module_business/dao/master_dao.py
T

542 lines
19 KiB
Python

from datetime import datetime
from typing import Any
from pydantic import BaseModel
from sqlalchemy import ColumnElement, Select, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm.attributes import InstrumentedAttribute
from common.vo import PageModel
from module_admin.entity.do.user_do import SysUser
from module_business.domain.test_batch_scope import TestBatchScope, batch_scope_condition
from module_business.entity.do.master_do import (
BizCustomer,
BizCustomerSite,
BizPallet,
BizProductionLine,
BizStrain,
BizUserSite,
BizUserWarehouse,
BizWarehouse,
)
from module_business.entity.do.operation_do import BizPalletInventory
from module_business.entity.vo.master_vo import (
CustomerModel,
CustomerPageQueryModel,
LineModel,
LinePageQueryModel,
PalletEditModel,
PalletPageQueryModel,
SiteModel,
SitePageQueryModel,
StrainModel,
StrainPageQueryModel,
WarehouseModel,
WarehousePageQueryModel,
)
from utils.page_util import PageUtil
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,
scope_predicate: ColumnElement[bool],
*,
for_update: bool = False,
) -> Any | None:
statement = select(model).where(id_column == resource_id, scope_predicate)
if for_update:
statement = statement.with_for_update().execution_options(populate_existing=True)
result = await db.execute(statement)
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,
test_batch_id: int | None,
) -> Any:
payload = page_object.model_dump(exclude={id_field, 'can_remove', 'test_batch_id'})
payload['test_batch_id'] = test_batch_id
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,
scope: TestBatchScope,
) -> None:
payload = page_object.model_dump(
exclude_unset=True,
exclude={'can_remove', 'create_by', 'create_time', 'test_batch_id'},
)
resource_id = payload.pop(id_field)
await db.execute(
update(model)
.where(
id_column == resource_id,
batch_scope_condition(model.test_batch_id, scope),
)
.values(**payload)
)
@classmethod
async def list_strain(
cls,
db: AsyncSession,
query_object: StrainPageQueryModel,
scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = [batch_scope_condition(BizStrain.test_batch_id, scope)]
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,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizStrain | None:
return await cls._get(
db,
BizStrain,
BizStrain.strain_id,
strain_id,
batch_scope_condition(BizStrain.test_batch_id, scope),
for_update=for_update,
)
@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, test_batch_id: int | None) -> BizStrain:
return await cls._add(db, BizStrain, 'strain_id', strain, test_batch_id)
@classmethod
async def update_strain(cls, db: AsyncSession, strain: StrainModel, scope: TestBatchScope) -> None:
await cls._update(db, BizStrain, BizStrain.strain_id, 'strain_id', strain, scope)
@classmethod
async def list_customer(
cls,
db: AsyncSession,
query_object: CustomerPageQueryModel,
scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = [batch_scope_condition(BizCustomer.test_batch_id, scope)]
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,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizCustomer | None:
return await cls._get(
db,
BizCustomer,
BizCustomer.customer_id,
customer_id,
batch_scope_condition(BizCustomer.test_batch_id, scope),
for_update=for_update,
)
@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, test_batch_id: int | None) -> BizCustomer:
return await cls._add(db, BizCustomer, 'customer_id', customer, test_batch_id)
@classmethod
async def update_customer(cls, db: AsyncSession, customer: CustomerModel, scope: TestBatchScope) -> None:
await cls._update(db, BizCustomer, BizCustomer.customer_id, 'customer_id', customer, scope)
@classmethod
async def list_site(
cls,
db: AsyncSession,
query_object: SitePageQueryModel,
scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = [batch_scope_condition(BizCustomerSite.test_batch_id, scope)]
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,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizCustomerSite | None:
return await cls._get(
db,
BizCustomerSite,
BizCustomerSite.site_id,
site_id,
batch_scope_condition(BizCustomerSite.test_batch_id, scope),
for_update=for_update,
)
@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, test_batch_id: int | None) -> BizCustomerSite:
return await cls._add(db, BizCustomerSite, 'site_id', site, test_batch_id)
@classmethod
async def update_site(cls, db: AsyncSession, site: SiteModel, scope: TestBatchScope) -> None:
await cls._update(db, BizCustomerSite, BizCustomerSite.site_id, 'site_id', site, scope)
@classmethod
async def list_line(
cls,
db: AsyncSession,
query_object: LinePageQueryModel,
scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = [batch_scope_condition(BizProductionLine.test_batch_id, scope)]
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,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizProductionLine | None:
return await cls._get(
db,
BizProductionLine,
BizProductionLine.line_id,
line_id,
batch_scope_condition(BizProductionLine.test_batch_id, scope),
for_update=for_update,
)
@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, test_batch_id: int | None) -> BizProductionLine:
return await cls._add(db, BizProductionLine, 'line_id', line, test_batch_id)
@classmethod
async def update_line(cls, db: AsyncSession, line: LineModel, scope: TestBatchScope) -> None:
await cls._update(db, BizProductionLine, BizProductionLine.line_id, 'line_id', line, scope)
@classmethod
async def list_warehouse(
cls,
db: AsyncSession,
query_object: WarehousePageQueryModel,
scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = [batch_scope_condition(BizWarehouse.test_batch_id, scope)]
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,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizWarehouse | None:
return await cls._get(
db,
BizWarehouse,
BizWarehouse.warehouse_id,
warehouse_id,
batch_scope_condition(BizWarehouse.test_batch_id, scope),
for_update=for_update,
)
@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, test_batch_id: int | None) -> BizWarehouse:
return await cls._add(db, BizWarehouse, 'warehouse_id', warehouse, test_batch_id)
@classmethod
async def update_warehouse(cls, db: AsyncSession, warehouse: WarehouseModel, scope: TestBatchScope) -> None:
await cls._update(db, BizWarehouse, BizWarehouse.warehouse_id, 'warehouse_id', warehouse, scope)
@classmethod
async def list_pallet(
cls,
db: AsyncSession,
query_object: PalletPageQueryModel,
scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[dict[str, Any]]:
conditions = [batch_scope_condition(BizPallet.test_batch_id, scope)]
if query_object.pallet_code:
conditions.append(BizPallet.pallet_code.like(f'%{query_object.pallet_code}%'))
if query_object.asset_status:
conditions.append(BizPallet.asset_status == query_object.asset_status)
statement = select(BizPallet).where(*conditions).order_by(BizPallet.pallet_id)
return await cls._paginate(db, statement, query_object, is_page)
@classmethod
async def get_pallet(
cls,
db: AsyncSession,
pallet_id: int,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizPallet | None:
return await cls._get(
db,
BizPallet,
BizPallet.pallet_id,
pallet_id,
batch_scope_condition(BizPallet.test_batch_id, scope),
for_update=for_update,
)
@classmethod
async def find_pallet_by_code(cls, db: AsyncSession, pallet_code: str) -> BizPallet | None:
return await cls._find(db, BizPallet, BizPallet.pallet_code, pallet_code)
@classmethod
async def add_pallet(cls, db: AsyncSession, pallet: BizPallet) -> BizPallet:
db.add(pallet)
await db.flush()
return pallet
@classmethod
async def update_pallet(
cls,
db: AsyncSession,
pallet: PalletEditModel,
scope: TestBatchScope,
update_by: str,
update_time: datetime,
) -> None:
await db.execute(
update(BizPallet)
.where(
BizPallet.pallet_id == pallet.pallet_id,
batch_scope_condition(BizPallet.test_batch_id, scope),
)
.values(
capacity_packages=pallet.capacity_packages,
asset_status=pallet.asset_status,
remark=pallet.remark,
update_by=update_by,
update_time=update_time,
)
)
@classmethod
async def get_pallet_inventory(
cls,
db: AsyncSession,
pallet_id: int,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizPalletInventory | None:
statement = select(BizPalletInventory).where(
BizPalletInventory.pallet_id == pallet_id,
batch_scope_condition(BizPalletInventory.test_batch_id, scope),
)
if for_update:
statement = statement.with_for_update().execution_options(populate_existing=True)
result = await db.execute(statement)
return result.scalar_one_or_none()
@classmethod
async def add_pallet_inventory(
cls,
db: AsyncSession,
inventory: BizPalletInventory,
) -> BizPalletInventory:
db.add(inventory)
await db.flush()
return inventory
@classmethod
async def list_assignable_users(cls, db: AsyncSession) -> list[Any]:
result = await db.execute(
select(SysUser.user_id, SysUser.user_name, SysUser.nick_name)
.where(SysUser.status == '0', SysUser.del_flag == '0')
.order_by(SysUser.user_id)
)
return list(result.all())
@classmethod
async def list_assignable_users_by_ids(cls, db: AsyncSession, user_ids: list[int]) -> list[Any]:
if not user_ids:
return []
result = await db.execute(
select(SysUser.user_id, SysUser.user_name, SysUser.nick_name)
.where(
SysUser.user_id.in_(user_ids),
SysUser.status == '0',
SysUser.del_flag == '0',
)
.order_by(SysUser.user_id)
)
return list(result.all())
@classmethod
async def list_warehouse_assigned_user_ids(
cls,
db: AsyncSession,
warehouse_id: int,
scope: TestBatchScope,
) -> list[int]:
result = await db.execute(
select(BizUserWarehouse.user_id)
.join(BizWarehouse, BizWarehouse.warehouse_id == BizUserWarehouse.warehouse_id)
.where(
BizUserWarehouse.warehouse_id == warehouse_id,
batch_scope_condition(BizWarehouse.test_batch_id, scope),
)
)
return list(result.scalars().all())
@classmethod
async def list_site_assigned_user_ids(
cls,
db: AsyncSession,
site_id: int,
scope: TestBatchScope,
) -> list[int]:
result = await db.execute(
select(BizUserSite.user_id)
.join(BizCustomerSite, BizCustomerSite.site_id == BizUserSite.site_id)
.where(
BizUserSite.site_id == site_id,
batch_scope_condition(BizCustomerSite.test_batch_id, scope),
)
)
return list(result.scalars().all())