功能:隔离五类测试业务链路

This commit is contained in:
焦龙言
2026-09-23 08:27:14 +08:00
parent 43fe17cc70
commit f5df2150d8
18 changed files with 1206 additions and 831 deletions
@@ -7,6 +7,7 @@ from sqlalchemy.orm.attributes import InstrumentedAttribute
from common.vo import PageModel
from module_business.domain.enums import DocumentStatus, PalletFlowState
from module_business.domain.test_batch_scope import TestBatchScope, batch_scope_condition
from module_business.entity.do.master_do import BizPallet
from module_business.entity.do.operation_do import (
BizFillingRecord,
@@ -56,36 +57,49 @@ class OperationDao:
@staticmethod
def _inbound_scope_conditions(
warehouse_ids: list[int] | None,
scope: TestBatchScope,
) -> list[ColumnElement[bool]]:
if warehouse_ids is None:
return []
return [batch_scope_condition(BizInboundOrder.test_batch_id, scope)]
scoped_warehouse_ids = sorted(set(warehouse_ids))
return [BizInboundOrder.warehouse_id.in_(scoped_warehouse_ids) if scoped_warehouse_ids else false()]
return [
batch_scope_condition(BizInboundOrder.test_batch_id, scope),
BizInboundOrder.warehouse_id.in_(scoped_warehouse_ids) if scoped_warehouse_ids else false(),
]
@staticmethod
def _filling_scope_conditions(
warehouse_ids: list[int] | None,
scope: TestBatchScope,
) -> list[ColumnElement[bool]]:
if warehouse_ids is None:
return []
return [batch_scope_condition(BizFillingRecord.test_batch_id, scope)]
scoped_warehouse_ids = sorted(set(warehouse_ids))
return [BizFillingRecord.warehouse_id.in_(scoped_warehouse_ids) if scoped_warehouse_ids else false()]
return [
batch_scope_condition(BizFillingRecord.test_batch_id, scope),
BizFillingRecord.warehouse_id.in_(scoped_warehouse_ids) if scoped_warehouse_ids else false(),
]
@staticmethod
def _usage_scope_conditions(
site_ids: list[int] | None,
scope: TestBatchScope,
) -> list[ColumnElement[bool]]:
if site_ids is None:
return []
return [batch_scope_condition(BizUsageRecord.test_batch_id, scope)]
scoped_site_ids = sorted(set(site_ids))
return [BizUsageRecord.site_id.in_(scoped_site_ids) if scoped_site_ids else false()]
return [
batch_scope_condition(BizUsageRecord.test_batch_id, scope),
BizUsageRecord.site_id.in_(scoped_site_ids) if scoped_site_ids else false(),
]
@staticmethod
def _shipment_scope_conditions(
warehouse_ids: list[int] | None,
site_ids: list[int] | None,
scope: TestBatchScope,
) -> list[ColumnElement[bool]]:
conditions = []
conditions = [batch_scope_condition(BizShipmentOrder.test_batch_id, scope)]
if warehouse_ids is not None:
scoped_warehouse_ids = sorted(set(warehouse_ids))
conditions.append(
@@ -100,9 +114,10 @@ class OperationDao:
def _return_scope_conditions(
site_ids: list[int] | None,
warehouse_ids: list[int] | None,
scope: TestBatchScope,
) -> list[ColumnElement[bool]]:
if site_ids is None and warehouse_ids is None:
return []
return [batch_scope_condition(BizReturnOrder.test_batch_id, scope)]
visibility_conditions: list[ColumnElement[bool]] = []
if site_ids is not None:
@@ -115,7 +130,7 @@ class OperationDao:
visibility_conditions.append(
BizReturnOrder.target_warehouse_id.in_(scoped_warehouse_ids) if scoped_warehouse_ids else false()
)
return [or_(*visibility_conditions)]
return [batch_scope_condition(BizReturnOrder.test_batch_id, scope), or_(*visibility_conditions)]
@staticmethod
async def _paginate(
@@ -180,6 +195,7 @@ class OperationDao:
item_model: type[Any],
item_order_id_column: InstrumentedAttribute,
item_id_column: InstrumentedAttribute,
scope: TestBatchScope,
*order_conditions: ColumnElement[bool],
) -> Any | None:
order = await cls._get_by_id(
@@ -193,7 +209,9 @@ class OperationDao:
return None
item_result = await db.execute(
select(item_model).where(item_order_id_column == order_id).order_by(item_id_column)
select(item_model)
.where(item_order_id_column == order_id, batch_scope_condition(item_model.test_batch_id, scope))
.order_by(item_id_column)
)
order.items = list(item_result.scalars().all())
return order
@@ -260,6 +278,7 @@ class OperationDao:
cls,
db: AsyncSession,
inbound_id: int,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
) -> BizInboundOrder | None:
inbound = await cls._get_for_update(
@@ -267,7 +286,7 @@ class OperationDao:
BizInboundOrder,
BizInboundOrder.inbound_id,
inbound_id,
*cls._inbound_scope_conditions(warehouse_ids),
*cls._inbound_scope_conditions(warehouse_ids, scope),
)
if inbound is None:
return None
@@ -275,7 +294,10 @@ class OperationDao:
# 父单锁定后用 locking read 获取最新明细,避免 MySQL RR 继续读取确认前的旧快照。
item_result = await db.execute(
select(BizInboundItem)
.where(BizInboundItem.inbound_id == inbound_id)
.where(
BizInboundItem.inbound_id == inbound_id,
batch_scope_condition(BizInboundItem.test_batch_id, scope),
)
.order_by(BizInboundItem.pallet_id, BizInboundItem.inbound_item_id)
.with_for_update()
.execution_options(populate_existing=True)
@@ -291,6 +313,7 @@ class OperationDao:
cls,
db: AsyncSession,
shipment_id: int,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> BizShipmentOrder | None:
@@ -299,7 +322,7 @@ class OperationDao:
BizShipmentOrder,
BizShipmentOrder.shipment_id,
shipment_id,
*cls._shipment_scope_conditions(warehouse_ids, site_ids),
*cls._shipment_scope_conditions(warehouse_ids, site_ids, scope),
)
if shipment is None:
return None
@@ -307,7 +330,10 @@ class OperationDao:
# 父单锁定后读取当前明细,避免 MySQL RR 沿用确认前的快照。
item_result = await db.execute(
select(BizShipmentItem)
.where(BizShipmentItem.shipment_id == shipment_id)
.where(
BizShipmentItem.shipment_id == shipment_id,
batch_scope_condition(BizShipmentItem.test_batch_id, scope),
)
.order_by(BizShipmentItem.pallet_id, BizShipmentItem.shipment_item_id)
.with_for_update()
.execution_options(populate_existing=True)
@@ -323,6 +349,7 @@ class OperationDao:
cls,
db: AsyncSession,
return_id: int,
scope: TestBatchScope,
site_ids: list[int] | None = None,
warehouse_ids: list[int] | None = None,
) -> BizReturnOrder | None:
@@ -331,7 +358,7 @@ class OperationDao:
BizReturnOrder,
BizReturnOrder.return_id,
return_id,
*cls._return_scope_conditions(site_ids, warehouse_ids),
*cls._return_scope_conditions(site_ids, warehouse_ids, scope),
)
if return_order is None:
return None
@@ -339,7 +366,10 @@ class OperationDao:
# 父单锁定后使用 locking read 获取当前明细,避免 MySQL RR 沿用旧快照。
item_result = await db.execute(
select(BizReturnItem)
.where(BizReturnItem.return_id == return_id)
.where(
BizReturnItem.return_id == return_id,
batch_scope_condition(BizReturnItem.test_batch_id, scope),
)
.order_by(BizReturnItem.pallet_id, BizReturnItem.return_item_id)
.with_for_update()
.execution_options(populate_existing=True)
@@ -355,6 +385,7 @@ class OperationDao:
cls,
db: AsyncSession,
filling_id: int,
scope: TestBatchScope,
) -> BizFillingRecord | None:
"""按已锁库存的 active_filling_id 锁定仍处于活动状态的装填周期。"""
return await cls._get_for_update(
@@ -362,6 +393,7 @@ class OperationDao:
BizFillingRecord,
BizFillingRecord.filling_id,
filling_id,
batch_scope_condition(BizFillingRecord.test_batch_id, scope),
BizFillingRecord.active_slot == 'ACTIVE',
)
@@ -370,6 +402,7 @@ class OperationDao:
cls,
db: AsyncSession,
idempotency_key: str,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
) -> BizInboundOrder | None:
return await cls._get_by_key(
@@ -377,7 +410,7 @@ class OperationDao:
BizInboundOrder,
BizInboundOrder.confirm_idempotency_key,
idempotency_key,
*cls._inbound_scope_conditions(warehouse_ids),
*cls._inbound_scope_conditions(warehouse_ids, scope),
)
@classmethod
@@ -385,6 +418,7 @@ class OperationDao:
cls,
db: AsyncSession,
idempotency_key: str,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> BizShipmentOrder | None:
@@ -393,7 +427,7 @@ class OperationDao:
BizShipmentOrder,
BizShipmentOrder.confirm_idempotency_key,
idempotency_key,
*cls._shipment_scope_conditions(warehouse_ids, site_ids),
*cls._shipment_scope_conditions(warehouse_ids, site_ids, scope),
)
@classmethod
@@ -401,6 +435,7 @@ class OperationDao:
cls,
db: AsyncSession,
idempotency_key: str,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
) -> BizFillingRecord | None:
return await cls._get_by_key(
@@ -408,7 +443,7 @@ class OperationDao:
BizFillingRecord,
BizFillingRecord.idempotency_key,
idempotency_key,
*cls._filling_scope_conditions(warehouse_ids),
*cls._filling_scope_conditions(warehouse_ids, scope),
)
@classmethod
@@ -416,6 +451,7 @@ class OperationDao:
cls,
db: AsyncSession,
idempotency_key: str,
scope: TestBatchScope,
site_ids: list[int] | None = None,
) -> BizUsageRecord | None:
return await cls._get_by_key(
@@ -423,7 +459,7 @@ class OperationDao:
BizUsageRecord,
BizUsageRecord.idempotency_key,
idempotency_key,
*cls._usage_scope_conditions(site_ids),
*cls._usage_scope_conditions(site_ids, scope),
)
@classmethod
@@ -433,6 +469,7 @@ class OperationDao:
idempotency_key: str,
source_site_id: int,
target_warehouse_id: int,
scope: TestBatchScope,
) -> BizReturnOrder | None:
return await cls._get_by_key(
db,
@@ -441,6 +478,7 @@ class OperationDao:
idempotency_key,
BizReturnOrder.source_site_id == source_site_id,
BizReturnOrder.target_warehouse_id == target_warehouse_id,
batch_scope_condition(BizReturnOrder.test_batch_id, scope),
)
@classmethod
@@ -450,6 +488,7 @@ class OperationDao:
idempotency_key: str,
source_site_id: int,
target_warehouse_id: int,
scope: TestBatchScope,
) -> BizReturnOrder | None:
return await cls._get_by_key(
db,
@@ -458,6 +497,7 @@ class OperationDao:
idempotency_key,
BizReturnOrder.source_site_id == source_site_id,
BizReturnOrder.target_warehouse_id == target_warehouse_id,
batch_scope_condition(BizReturnOrder.test_batch_id, scope),
)
@classmethod
@@ -465,10 +505,11 @@ class OperationDao:
cls,
db: AsyncSession,
query_object: InboundPageQueryModel,
warehouse_ids: list[int] | None,
scope: TestBatchScope,
is_page: bool = True,
warehouse_ids: list[int] | None = None,
) -> PageModel | list[dict[str, Any]]:
conditions = cls._inbound_scope_conditions(warehouse_ids)
conditions = cls._inbound_scope_conditions(warehouse_ids, scope)
if query_object.inbound_no:
conditions.append(BizInboundOrder.inbound_no.like(f'%{query_object.inbound_no}%'))
if query_object.warehouse_id:
@@ -490,6 +531,7 @@ class OperationDao:
cls,
db: AsyncSession,
inbound_id: int,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
) -> BizInboundOrder | None:
return await cls._get_order_detail(
@@ -500,7 +542,8 @@ class OperationDao:
BizInboundItem,
BizInboundItem.inbound_id,
BizInboundItem.inbound_item_id,
*cls._inbound_scope_conditions(warehouse_ids),
scope,
*cls._inbound_scope_conditions(warehouse_ids, scope),
)
@classmethod
@@ -549,10 +592,11 @@ class OperationDao:
cls,
db: AsyncSession,
query_object: FillingPageQueryModel,
warehouse_ids: list[int] | None,
scope: TestBatchScope,
is_page: bool = True,
warehouse_ids: list[int] | None = None,
) -> PageModel | list[dict[str, Any]]:
conditions = cls._filling_scope_conditions(warehouse_ids)
conditions = cls._filling_scope_conditions(warehouse_ids, scope)
if query_object.filling_no:
conditions.append(BizFillingRecord.filling_no.like(f'%{query_object.filling_no}%'))
if query_object.warehouse_id:
@@ -584,6 +628,7 @@ class OperationDao:
cls,
db: AsyncSession,
filling_id: int,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
) -> BizFillingRecord | None:
return await cls._get_by_id(
@@ -591,7 +636,7 @@ class OperationDao:
BizFillingRecord,
BizFillingRecord.filling_id,
filling_id,
*cls._filling_scope_conditions(warehouse_ids),
*cls._filling_scope_conditions(warehouse_ids, scope),
)
@classmethod
@@ -620,11 +665,12 @@ class OperationDao:
cls,
db: AsyncSession,
query_object: ShipmentPageQueryModel,
warehouse_ids: list[int] | None,
site_ids: list[int] | None,
scope: TestBatchScope,
is_page: bool = True,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> PageModel | list[dict[str, Any]]:
conditions = cls._shipment_scope_conditions(warehouse_ids, site_ids)
conditions = cls._shipment_scope_conditions(warehouse_ids, site_ids, scope)
if query_object.shipment_no:
conditions.append(BizShipmentOrder.shipment_no.like(f'%{query_object.shipment_no}%'))
if query_object.source_warehouse_id:
@@ -648,6 +694,7 @@ class OperationDao:
cls,
db: AsyncSession,
shipment_id: int,
scope: TestBatchScope,
warehouse_ids: list[int] | None = None,
site_ids: list[int] | None = None,
) -> BizShipmentOrder | None:
@@ -656,7 +703,7 @@ class OperationDao:
BizShipmentOrder,
BizShipmentOrder.shipment_id,
shipment_id,
*cls._shipment_scope_conditions(warehouse_ids, site_ids),
*cls._shipment_scope_conditions(warehouse_ids, site_ids, scope),
)
if shipment is None:
return None
@@ -674,9 +721,13 @@ class OperationDao:
BizPalletInventory.current_line_id.is_(None),
BizPalletInventory.active_filling_id.is_not(None),
BizPalletInventory.remaining_packages > 0,
batch_scope_condition(BizPalletInventory.test_batch_id, scope),
),
)
.where(BizShipmentItem.shipment_id == shipment_id)
.where(
BizShipmentItem.shipment_id == shipment_id,
batch_scope_condition(BizShipmentItem.test_batch_id, scope),
)
.order_by(BizShipmentItem.shipment_item_id)
)
items = []
@@ -686,7 +737,10 @@ class OperationDao:
else:
item_result = await db.execute(
select(BizShipmentItem)
.where(BizShipmentItem.shipment_id == shipment_id)
.where(
BizShipmentItem.shipment_id == shipment_id,
batch_scope_condition(BizShipmentItem.test_batch_id, scope),
)
.order_by(BizShipmentItem.shipment_item_id)
)
items = list(item_result.scalars().all())
@@ -746,10 +800,11 @@ class OperationDao:
cls,
db: AsyncSession,
query_object: UsagePageQueryModel,
site_ids: list[int] | None,
scope: TestBatchScope,
is_page: bool = True,
site_ids: list[int] | None = None,
) -> PageModel | list[dict[str, Any]]:
conditions = cls._usage_scope_conditions(site_ids)
conditions = cls._usage_scope_conditions(site_ids, scope)
if query_object.usage_no:
conditions.append(BizUsageRecord.usage_no.like(f'%{query_object.usage_no}%'))
if query_object.site_id:
@@ -779,6 +834,7 @@ class OperationDao:
cls,
db: AsyncSession,
usage_id: int,
scope: TestBatchScope,
site_ids: list[int] | None = None,
) -> BizUsageRecord | None:
return await cls._get_by_id(
@@ -786,7 +842,7 @@ class OperationDao:
BizUsageRecord,
BizUsageRecord.usage_id,
usage_id,
*cls._usage_scope_conditions(site_ids),
*cls._usage_scope_conditions(site_ids, scope),
)
@classmethod
@@ -802,11 +858,12 @@ class OperationDao:
cls,
db: AsyncSession,
query_object: ReturnPageQueryModel,
site_ids: list[int] | None,
warehouse_ids: list[int] | None,
scope: TestBatchScope,
is_page: bool = True,
site_ids: list[int] | None = None,
warehouse_ids: list[int] | None = None,
) -> PageModel | list[dict[str, Any]]:
conditions = cls._return_scope_conditions(site_ids, warehouse_ids)
conditions = cls._return_scope_conditions(site_ids, warehouse_ids, scope)
if query_object.return_no:
conditions.append(BizReturnOrder.return_no.like(f'%{query_object.return_no}%'))
if query_object.source_site_id:
@@ -830,6 +887,7 @@ class OperationDao:
cls,
db: AsyncSession,
return_id: int,
scope: TestBatchScope,
site_ids: list[int] | None = None,
warehouse_ids: list[int] | None = None,
) -> BizReturnOrder | None:
@@ -841,7 +899,8 @@ class OperationDao:
BizReturnItem,
BizReturnItem.return_id,
BizReturnItem.return_item_id,
*cls._return_scope_conditions(site_ids, warehouse_ids),
scope,
*cls._return_scope_conditions(site_ids, warehouse_ids, scope),
)
@classmethod