功能:隔离五类测试业务链路
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user