fix: block receiving before pallet materialization

This commit is contained in:
2026-09-10 16:43:08 +08:00
parent 1ce99e710d
commit 343c6e278a
4 changed files with 41 additions and 4 deletions
@@ -128,6 +128,7 @@ public class ReceivingContainerService {
public ReceivingContainerResponses.Session detail(String operatorKey, long overseasWarehouseId, String containerNo) {
requireReadyContainer(containerNo, overseasWarehouseId, false);
List<InboundPlan> containerPlans = requirePlans(containerNo);
requireMaterializedPlans(containerPlans);
if (!warehouseEligible(containerPlans, overseasWarehouseId)) throw conflict("当前柜已分配至其他海外接柜仓,无法在本仓操作");
ReceivingContainerSession current = sessions.findActiveByOperator(activeOperatorKey(operatorKey));
requireSessionWarehouse(current, overseasWarehouseId);
@@ -158,6 +159,7 @@ public class ReceivingContainerService {
return result;
}
List<InboundPlan> containerPlans = requirePlans(containerNo);
requireMaterializedPlans(containerPlans);
if (!warehouseEligible(containerPlans, overseasWarehouseId)) throw conflict("当前柜已分配至其他海外接柜仓,无法在本仓操作");
String activeOperatorKey = activeOperatorKey(operatorKey);
ReceivingContainerSession active = sessions.lockActiveByOperator(activeOperatorKey);
@@ -210,10 +212,11 @@ public class ReceivingContainerService {
List<ReceivingContainerResponses.SignedPhoto> photos = validateSignPhotos(request);
List<Long> photoFileIds = photos.stream().map(photo -> positiveFileId(photo.fileId())).toList();
photoFileIds.forEach(fileId -> unloadPhotos.validate(PLATFORM_SCOPE, session.getId(), fileId));
List<InboundPlan> containerPlans = requirePlans(session.getContainerNo());
requireMaterializedPlans(containerPlans);
LocalDateTime now = LocalDateTime.now();
session.setSignPhotos(write(photos)); session.setStatus("SIGNED"); session.setSignedAt(now);
session.setOperatorName(operatorName); session.setUpdatedAt(now); update(session);
List<InboundPlan> containerPlans = requirePlans(session.getContainerNo());
for (InboundPlan plan : containerPlans) {
workflow.ensureSignedTask(plan.getCustomerId(), plan, operatorKey, operatorName, photoFileIds, now);
}
@@ -661,6 +664,21 @@ public class ReceivingContainerService {
|| "LOCKED".equals(pallet.getAssignmentStatus()));
}
private void requireMaterializedPlans(List<InboundPlan> containerPlans) {
for (InboundPlan plan : containerPlans) {
int expected = plan.getPalletCount() == null ? 0 : plan.getPalletCount();
long materialized = pallets.selectCount(new LambdaQueryWrapper<InboundPlanPallet>()
.eq(InboundPlanPallet::getCustomerId, plan.getCustomerId())
.eq(InboundPlanPallet::getPlanId, plan.getId())
.isNotNull(InboundPlanPallet::getWarehousePalletId)
.isNotNull(InboundPlanPallet::getWarehouseLocationId)
.isNotNull(InboundPlanPallet::getWarehouseResourceLockId));
if (expected <= 0 || materialized < expected) {
throw conflict("入库计划尚未完整绑定真实托盘,请先在平台按柜生成入库计划");
}
}
}
private void validatePallet(InboundRef ref, WarehouseResourceGateway.WarehousePalletReference pallet) {
if ("SCRAPPED".equals(pallet.status())) throw conflict("Pallet is scrapped");
long actualWarehouse;
@@ -42,7 +42,8 @@ public interface LastlegOrderMapper extends BaseMapper<LastlegOrder> {
"AND NULLIF(TRIM(p.status),'') IS NOT NULL THEN NULLIF(TRIM(o.inbound_code),'') END) AS plannedInboundCodeCount," +
"SUM(CASE WHEN p.id IS NULL OR NULLIF(TRIM(p.plan_no),'') IS NULL OR NULLIF(TRIM(p.status),'') IS NULL " +
"THEN 1 ELSE 0 END) AS pendingPlanCount," +
"SUM(CASE WHEN p.id IS NOT NULL AND COALESCE(p.pallet_count,0)&gt;0 AND " +
"SUM(CASE WHEN p.id IS NOT NULL AND p.status IN ('PENDING_ASSIGNMENT','SIGNED') " +
"AND COALESCE(p.pallet_count,0)&gt;0 AND " +
"(SELECT COUNT(*) FROM ll_inbound_plan_pallet pp WHERE pp.customer_id=p.customer_id " +
"AND pp.plan_id=p.id AND pp.warehouse_pallet_id IS NOT NULL)&lt;COALESCE(p.pallet_count,0) " +
"THEN 1 ELSE 0 END) AS resourcePendingPlanCount," +