安全:补齐业务批次归属校验

This commit is contained in:
焦龙言
2026-09-23 11:49:35 +08:00
parent 97b4dc8508
commit 5a76fe7521
10 changed files with 509 additions and 58 deletions
@@ -16,7 +16,7 @@ from module_business.dao.master_dao import MasterDao
from module_business.dao.operation_dao import OperationDao
from module_business.domain.enums import DocumentStatus, PalletEventType, PalletFlowState
from module_business.domain.pallet_state_machine import PalletStateMachine
from module_business.domain.test_batch_scope import TestBatchScope
from module_business.domain.test_batch_scope import TestBatchScope, assert_record_in_scope
from module_business.entity.do.master_do import BizPallet
from module_business.entity.do.operation_do import (
BizFillingRecord,
@@ -105,12 +105,14 @@ class ShipmentService:
warehouse = await MasterDao.get_warehouse(query_db, source_warehouse_id, test_scope)
if warehouse is None:
raise ServiceException(message='来源仓库不存在')
assert_record_in_scope(warehouse, test_scope, '仓库')
if warehouse.status != '0':
raise ServiceException(message='来源仓库已停用')
await AccessService.assert_site_access(query_db, current_user, target_site_id)
site = await MasterDao.get_site(query_db, target_site_id, test_scope)
if site is None:
raise ServiceException(message='目标现场不存在')
assert_record_in_scope(site, test_scope, '现场')
if site.status != '0':
raise ServiceException(message='目标现场已停用')
return warehouse, site
@@ -166,6 +168,10 @@ class ShipmentService:
ordered_ids = cls._validate_pallet_ids(pallet_ids)
inventories = await InventoryDao.get_inventories_for_update(query_db, ordered_ids, test_scope)
pallets = await InventoryDao.get_pallets_by_ids(query_db, ordered_ids, test_scope)
for inventory in inventories:
assert_record_in_scope(inventory, test_scope, '库存')
for pallet in pallets:
assert_record_in_scope(pallet, test_scope, '托盘')
if (
len(inventories) != len(ordered_ids)
or len(pallets) != len(ordered_ids)
@@ -188,6 +194,7 @@ class ShipmentService:
filling = await OperationDao.get_active_filling_for_update(query_db, filling_id, test_scope)
if filling is None:
raise ServiceException(message='托盘活动装填周期不存在或已关闭')
assert_record_in_scope(filling, test_scope, '活动装填')
fillings.append(filling)
if len(fillings) != len(ordered_ids):
raise ServiceException(message='托盘活动装填周期不完整')
@@ -412,6 +419,7 @@ class ShipmentService:
warehouse = await MasterDao.get_warehouse(query_db, query_object.source_warehouse_id, test_scope)
if warehouse is None:
raise ServiceException(message='来源仓库不存在')
assert_record_in_scope(warehouse, test_scope, '仓库')
if warehouse.status != '0':
raise ServiceException(message='来源仓库已停用')
await AccessService.assert_site_access(
@@ -422,15 +430,18 @@ class ShipmentService:
site = await MasterDao.get_site(query_db, query_object.target_site_id, test_scope)
if site is None:
raise ServiceException(message='目标现场不存在')
assert_record_in_scope(site, test_scope, '现场')
if site.status != '0':
raise ServiceException(message='目标现场已停用')
pallet = await InventoryDao.get_pallet_by_qr_token(query_db, qr_token, test_scope)
if pallet is None:
cls._raise_pallet_not_accessible(current_user)
assert_record_in_scope(pallet, test_scope, '托盘')
inventory = await MasterDao.get_pallet_inventory(query_db, pallet.pallet_id, test_scope)
if inventory is None:
cls._raise_pallet_not_accessible(current_user, '托盘库存不存在')
assert_record_in_scope(inventory, test_scope, '库存')
if inventory.pallet_id != pallet.pallet_id or inventory.warehouse_id != query_object.source_warehouse_id:
cls._raise_pallet_not_accessible(current_user, '托盘不在来源仓库')
if inventory.site_id is not None or inventory.current_line_id is not None:
@@ -440,6 +451,7 @@ class ShipmentService:
filling = await OperationDao.get_filling_by_id(query_db, inventory.active_filling_id, test_scope)
if filling is None:
raise ServiceException(message='托盘活动装填周期不存在')
assert_record_in_scope(filling, test_scope, '活动装填')
cls._validate_scan_pallet(
pallet,
inventory,
@@ -629,7 +641,7 @@ class ShipmentService:
)
@classmethod
async def _lock_and_authorize_routes(
async def _lock_and_authorize_routes( # noqa: PLR0912
cls,
query_db: AsyncSession,
current_user: CurrentUserModel,
@@ -651,6 +663,8 @@ class ShipmentService:
for_update=True,
)
warehouses[warehouse_id] = warehouse
if warehouse is not None:
assert_record_in_scope(warehouse, test_scope, '仓库')
try:
await AccessService.assert_warehouse_access(
query_db,
@@ -671,6 +685,8 @@ class ShipmentService:
for_update=True,
)
sites[site_id] = site
if site is not None:
assert_record_in_scope(site, test_scope, '现场')
try:
await AccessService.assert_site_access(
query_db,
@@ -749,6 +765,7 @@ class ShipmentService:
)
if current is None:
cls._raise_shipment_not_accessible(current_user)
assert_record_in_scope(current, test_scope, '发货单')
recovered = await OperationDao.get_shipment_by_confirm_idempotency_key(
query_db,
idempotency_key,
@@ -758,6 +775,7 @@ class ShipmentService:
)
if recovered is None:
raise ServiceException(message='确认发货失败,幂等冲突')
assert_record_in_scope(recovered, test_scope, '发货单')
if not cls._is_exact_confirmed(
recovered,
shipment_id,
@@ -774,6 +792,7 @@ class ShipmentService:
)
if locked_recovered is None:
cls._raise_shipment_not_accessible(current_user)
assert_record_in_scope(locked_recovered, test_scope, '发货单')
if not cls._is_exact_confirmed(
locked_recovered,
shipment_id,
@@ -814,6 +833,7 @@ class ShipmentService:
)
if shipment is None:
cls._raise_shipment_not_accessible(current_user)
assert_record_in_scope(shipment, test_scope, '发货单')
request_hash = cls._build_confirm_request_hash(shipment_id)
idempotency_key = page_object.idempotency_key
@@ -841,6 +861,7 @@ class ShipmentService:
)
if locked_shipment is None:
cls._raise_shipment_not_accessible(current_user)
assert_record_in_scope(locked_shipment, test_scope, '发货单')
if locked_shipment.status == DocumentStatus.CONFIRMED.value:
if cls._is_exact_confirmed(
locked_shipment,