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

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
@@ -18,6 +18,7 @@ from module_business.dao.master_dao import MasterDao
from module_business.dao.operation_dao import OperationDao
from module_business.domain.enums import PalletEventType, PalletFlowState
from module_business.domain.pallet_state_machine import PalletStateMachine
from module_business.domain.test_batch_scope import TestBatchScope
from module_business.entity.do.operation_do import BizPalletEvent, BizUsageRecord
from module_business.entity.vo.master_vo import LinePageQueryModel
from module_business.entity.vo.operation_vo import (
@@ -29,6 +30,7 @@ from module_business.entity.vo.operation_vo import (
UsageSuccessResponseModel,
)
from module_business.service.access_service import AccessService
from module_business.service.test_batch_access_service import TestBatchAccessService
class UsageService:
@@ -147,8 +149,9 @@ class UsageService:
query_db: AsyncSession,
site_id: int,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> None:
site = await MasterDao.get_site(query_db, site_id, for_update=True)
site = await MasterDao.get_site(query_db, site_id, test_scope, for_update=True)
try:
await AccessService.assert_site_access(
query_db,
@@ -171,6 +174,7 @@ class UsageService:
request_hash: str,
current_user: CurrentUserModel,
expected_site_id: int,
test_scope: TestBatchScope,
) -> CrudResponseModel:
try:
site_ids = await cls._site_scope(query_db, current_user)
@@ -179,6 +183,7 @@ class UsageService:
recovered = await OperationDao.get_usage_by_idempotency_key(
query_db,
page_object.idempotency_key,
test_scope,
site_ids=[expected_site_id],
)
if recovered is None:
@@ -191,6 +196,7 @@ class UsageService:
query_db,
recovered.site_id,
current_user,
test_scope,
)
return cls._success(recovered)
finally:
@@ -202,6 +208,7 @@ class UsageService:
query_db: AsyncSession,
query_object: UsagePageQueryModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
is_page: bool = True,
) -> PageModel | list[UsageModel]:
site_ids = await cls._site_scope(query_db, current_user)
@@ -220,8 +227,9 @@ class UsageService:
result = await OperationDao.get_usage_list(
query_db,
query_object,
is_page,
site_ids=site_ids,
scope=test_scope,
is_page=is_page,
)
rows = result.rows if isinstance(result, PageModel) else result
models = [UsageModel.model_validate(record) for record in rows]
@@ -235,11 +243,13 @@ class UsageService:
query_db: AsyncSession,
usage_id: int,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> UsageModel:
site_ids = await cls._site_scope(query_db, current_user)
usage = await OperationDao.get_usage_by_id(
query_db,
usage_id,
test_scope,
site_ids=site_ids,
)
if usage is None:
@@ -252,10 +262,11 @@ class UsageService:
query_db: AsyncSession,
site_id: int,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> list[BusinessOptionModel]:
cls._current_identity(current_user)
await AccessService.assert_site_access(query_db, current_user, site_id)
site = await MasterDao.get_site(query_db, site_id)
site = await MasterDao.get_site(query_db, site_id, test_scope)
if site is None:
raise ServiceException(message='客户现场不存在')
if site.status != '0':
@@ -263,6 +274,7 @@ class UsageService:
lines = await MasterDao.list_line(
query_db,
LinePageQueryModel(siteId=site_id, status='0'),
test_scope,
False,
)
options = [
@@ -282,12 +294,13 @@ class UsageService:
query_db: AsyncSession,
qr_token: str,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> PalletScanResponseModel:
normalized_qr = qr_token.strip()
pallet = await InventoryDao.get_pallet_by_qr_token(query_db, normalized_qr)
pallet = await InventoryDao.get_pallet_by_qr_token(query_db, normalized_qr, test_scope)
if pallet is None:
cls._raise_pallet_not_accessible(current_user)
inventory = await MasterDao.get_pallet_inventory(query_db, pallet.pallet_id)
inventory = await MasterDao.get_pallet_inventory(query_db, pallet.pallet_id, test_scope)
if inventory is None:
cls._raise_pallet_not_accessible(current_user, '托盘库存不存在')
if inventory.site_id is None:
@@ -311,7 +324,7 @@ class UsageService:
or inventory.remaining_packages > pallet.capacity_packages
):
raise ServiceException(message='托盘当前状态不允许使用')
filling = await OperationDao.get_filling_by_id(query_db, inventory.active_filling_id)
filling = await OperationDao.get_filling_by_id(query_db, inventory.active_filling_id, test_scope)
if filling is None:
raise ServiceException(message='托盘活动装填周期不存在')
if (
@@ -345,14 +358,16 @@ class UsageService:
query_db: AsyncSession,
page_object: UsageCreateModel,
current_user: CurrentUserModel,
test_scope: TestBatchScope,
) -> CrudResponseModel:
expected_site_id: int | None = None
try:
await TestBatchAccessService.lock_active_batch(query_db, test_scope)
request_hash = cls._build_request_hash(page_object)
user_id, user_name = cls._current_identity(current_user)
preflight_site_ids = await cls._site_scope(query_db, current_user)
# 产线归属是请求内稳定路由;锁事务仍以库存中的实际现场复核。
preflight_line = await MasterDao.get_line(query_db, page_object.line_id)
preflight_line = await MasterDao.get_line(query_db, page_object.line_id, test_scope)
preflight_site_id = preflight_line.site_id if preflight_line is not None else None
existing = None
if preflight_site_id is not None and (
@@ -361,6 +376,7 @@ class UsageService:
existing = await OperationDao.get_usage_by_idempotency_key(
query_db,
page_object.idempotency_key,
test_scope,
site_ids=[preflight_site_id],
)
if existing is not None:
@@ -372,6 +388,7 @@ class UsageService:
query_db,
existing.site_id,
current_user,
test_scope,
)
result = cls._success(existing)
await query_db.rollback()
@@ -380,6 +397,7 @@ class UsageService:
scanned_pallet = await InventoryDao.get_pallet_by_qr_token(
query_db,
page_object.qr_token.strip(),
test_scope,
)
if scanned_pallet is None:
cls._raise_pallet_not_accessible(current_user)
@@ -389,6 +407,7 @@ class UsageService:
inventory = await InventoryDao.get_inventory_for_update(
query_db,
scanned_pallet_id,
test_scope,
)
if inventory is None:
cls._raise_pallet_not_accessible(current_user, '托盘库存不存在')
@@ -403,6 +422,7 @@ class UsageService:
locked_pallets = await InventoryDao.get_pallets_by_ids(
query_db,
[inventory.pallet_id],
test_scope,
)
if len(locked_pallets) != 1 or locked_pallets[0].pallet_id != inventory.pallet_id:
cls._raise_pallet_not_accessible(current_user)
@@ -412,6 +432,7 @@ class UsageService:
await OperationDao.get_active_filling_for_update(
query_db,
inventory.active_filling_id,
test_scope,
)
if inventory.active_filling_id is not None
else None
@@ -419,6 +440,7 @@ class UsageService:
locked_existing = await OperationDao.get_usage_by_idempotency_key(
query_db,
page_object.idempotency_key,
test_scope,
site_ids=[inventory.site_id],
)
if locked_existing is not None:
@@ -432,6 +454,7 @@ class UsageService:
query_db,
locked_existing.site_id,
current_user,
test_scope,
)
result = cls._success(locked_existing)
await query_db.rollback()
@@ -442,7 +465,7 @@ class UsageService:
if filling is None:
raise ServiceException(message='托盘活动装填周期不存在或已关闭')
site = await MasterDao.get_site(query_db, inventory.site_id, for_update=True)
site = await MasterDao.get_site(query_db, inventory.site_id, test_scope, for_update=True)
await cls._assert_pallet_site_access(
query_db,
current_user,
@@ -453,7 +476,7 @@ class UsageService:
raise ServiceException(message='客户现场不存在')
if site.status != '0':
raise ServiceException(message='客户现场已停用')
line = await MasterDao.get_line(query_db, page_object.line_id, for_update=True)
line = await MasterDao.get_line(query_db, page_object.line_id, test_scope, for_update=True)
if line is None:
raise ServiceException(message='产线不存在')
if line.status != '0':
@@ -512,6 +535,7 @@ class UsageService:
request_hash=request_hash,
operator_id=user_id,
occurred_at=current_time,
test_batch_id=test_scope.batch_id,
)
usage = await OperationDao.add_usage_record(query_db, usage)
usage_id = usage.usage_id
@@ -553,6 +577,7 @@ class UsageService:
occurred_at=current_time,
idempotency_key=page_object.idempotency_key,
request_hash=request_hash,
test_batch_id=test_scope.batch_id,
)
await InventoryDao.add_event(query_db, inventory, event)
await query_db.commit()
@@ -567,6 +592,7 @@ class UsageService:
request_hash,
current_user,
expected_site_id,
test_scope,
)
except Exception:
await query_db.rollback()