修复确认预装后重新分配失败
This commit is contained in:
@@ -136,8 +136,14 @@ public class SmartLoadingService {
|
|||||||
if (candidate == null) throw conflict("入库货物不存在或尚未完成入库");
|
if (candidate == null) throw conflict("入库货物不存在或尚未完成入库");
|
||||||
requireSameChannel(booking, candidate);
|
requireSameChannel(booking, candidate);
|
||||||
requireSameCustomerScope(booking, candidate);
|
requireSameCustomerScope(booking, candidate);
|
||||||
splitPreloadService.ensurePendingForLoadingAllocation(candidate.accountId(), candidate.inboundId(),
|
var task = loadingPickService.mutationSnapshot(planId);
|
||||||
operatorId, operatorName);
|
if (task.taskId() != null && "LOADING".equals(task.taskStatus())) {
|
||||||
|
splitPreloadService.ensureForRunningLoadingAllocation(candidate.accountId(), candidate.inboundId(),
|
||||||
|
operatorId, operatorName);
|
||||||
|
} else {
|
||||||
|
splitPreloadService.ensurePendingForLoadingAllocation(candidate.accountId(), candidate.inboundId(),
|
||||||
|
operatorId, operatorName);
|
||||||
|
}
|
||||||
OrderCargoClient.CargoBinding cargo = loadCargo(candidate);
|
OrderCargoClient.CargoBinding cargo = loadCargo(candidate);
|
||||||
LoadingPlanItemEntity existing = repository.activeItem(planId, candidate.accountId(), request.inboundDetailId());
|
LoadingPlanItemEntity existing = repository.activeItem(planId, candidate.accountId(), request.inboundDetailId());
|
||||||
int total = request.packageCount() + (existing == null ? 0 : existing.getPackageCount());
|
int total = request.packageCount() + (existing == null ? 0 : existing.getPackageCount());
|
||||||
|
|||||||
@@ -68,11 +68,28 @@ public class SplitPreloadService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void ensurePendingForLoadingAllocation(long tenantId, long inboundId, long operatorId,
|
public void ensurePendingForLoadingAllocation(long tenantId, long inboundId, long operatorId,
|
||||||
String operatorName) {
|
String operatorName) {
|
||||||
|
ensureLoadingAllocationLifecycle(tenantId, inboundId, operatorId, operatorName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A running PDA task may restore or add an unpicked allocation after the plan-level preload
|
||||||
|
* confirmation. CONFIRMING remains immutable; CONFIRMED is accepted because the caller owns
|
||||||
|
* the active PDA task lock and will synchronise the restored loading item immediately.
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public void ensureForRunningLoadingAllocation(long tenantId, long inboundId, long operatorId,
|
||||||
|
String operatorName) {
|
||||||
|
ensureLoadingAllocationLifecycle(tenantId, inboundId, operatorId, operatorName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureLoadingAllocationLifecycle(long tenantId, long inboundId, long operatorId,
|
||||||
|
String operatorName, boolean allowConfirmed) {
|
||||||
InboundSnapshot inbound = requireInbound(tenantId, inboundId);
|
InboundSnapshot inbound = requireInbound(tenantId, inboundId);
|
||||||
requireWaitingSplit(inbound, "仅待分柜订单可以建立智能装柜预装计划");
|
requireWaitingSplit(inbound, "仅待分柜订单可以建立智能装柜预装计划");
|
||||||
PreloadPlanEntity plan = repository.findPlan(tenantId, inboundId);
|
PreloadPlanEntity plan = repository.findPlan(tenantId, inboundId);
|
||||||
if (plan != null) {
|
if (plan != null) {
|
||||||
if (!PreloadStatus.PENDING.equals(plan.getStatus())) {
|
if (!PreloadStatus.PENDING.equals(plan.getStatus())
|
||||||
|
&& !(allowConfirmed && PreloadStatus.CONFIRMED.equals(plan.getStatus()))) {
|
||||||
throw new BizException(ResultCode.CONFLICT, "预装计划已进入确认流程,不能修改智能装柜分配");
|
throw new BizException(ResultCode.CONFLICT, "预装计划已进入确认流程,不能修改智能装柜分配");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ class SmartLoadingServiceTest {
|
|||||||
when(repository.items(1)).thenReturn(List.of());
|
when(repository.items(1)).thenReturn(List.of());
|
||||||
when(repository.candidate(100, 10, 20)).thenReturn(candidate(10));
|
when(repository.candidate(100, 10, 20)).thenReturn(candidate(10));
|
||||||
when(repository.activeItem(1L, 9L, 20L)).thenReturn(null);
|
when(repository.activeItem(1L, 9L, 20L)).thenReturn(null);
|
||||||
|
when(loadingPickService.mutationSnapshot(1L)).thenReturn(
|
||||||
|
new LoadingPickService.MutationSnapshot(77L, "LOADING", 6, Map.of()));
|
||||||
when(cargoClient.detail(anyString(), anyLong(), anyLong(), anyLong())).thenReturn(ApiResponse.success(
|
when(cargoClient.detail(anyString(), anyLong(), anyLong(), anyLong())).thenReturn(ApiResponse.success(
|
||||||
new OrderCargoClient.CargoBinding(20L, 30L, 1, "货物", 1,
|
new OrderCargoClient.CargoBinding(20L, 30L, 1, "货物", 1,
|
||||||
BigDecimal.ONE, BigDecimal.ONE, null, null, null, null, null, null)));
|
BigDecimal.ONE, BigDecimal.ONE, null, null, null, null, null, null)));
|
||||||
@@ -365,12 +367,14 @@ class SmartLoadingServiceTest {
|
|||||||
Plan result = service.assign(1, new AssignRequest(10L, 20L, 1, 5, "assign-loading"), 7, "u");
|
Plan result = service.assign(1, new AssignRequest(10L, 20L, 1, 5, "assign-loading"), 7, "u");
|
||||||
|
|
||||||
assertThat(result.status()).isEqualTo("LOADING");
|
assertThat(result.status()).isEqualTo("LOADING");
|
||||||
var order = inOrder(loadingPickService, repository, loadingModelBridge);
|
var order = inOrder(loadingPickService, splitPreloadService, repository, loadingModelBridge);
|
||||||
order.verify(loadingPickService).lockMutable(1L);
|
order.verify(loadingPickService).lockMutable(1L);
|
||||||
|
order.verify(splitPreloadService).ensureForRunningLoadingAllocation(9L, 10L, 7L, "u");
|
||||||
order.verify(repository).touch(1, 5, 7, "u");
|
order.verify(repository).touch(1, 5, 7, "u");
|
||||||
order.verify(loadingModelBridge).bindIncrementalAllocation(1L, 9L, 10L,
|
order.verify(loadingModelBridge).bindIncrementalAllocation(1L, 9L, 10L,
|
||||||
7L, "u", "assign-loading");
|
7L, "u", "assign-loading");
|
||||||
order.verify(loadingPickService).sync(eq(1L), any(LoadingPlanItemEntity.class));
|
order.verify(loadingPickService).sync(eq(1L), any(LoadingPlanItemEntity.class));
|
||||||
|
verify(splitPreloadService, never()).ensurePendingForLoadingAllocation(9L, 10L, 7L, "u");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -80,4 +80,27 @@ class SplitPreloadServiceTest {
|
|||||||
verify(repository, never()).createPlan(any());
|
verify(repository, never()).createPlan(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void runningPdaAllocationMayReuseConfirmedPreload() {
|
||||||
|
when(repository.findInbound(10, 20)).thenReturn(new InboundSnapshot(20L, 10L, "WAIT_SPLIT", 3));
|
||||||
|
PreloadPlanEntity plan = new PreloadPlanEntity();
|
||||||
|
plan.setStatus("CONFIRMED");
|
||||||
|
when(repository.findPlan(10, 20)).thenReturn(plan);
|
||||||
|
|
||||||
|
service.ensureForRunningLoadingAllocation(10, 20, 7, "admin");
|
||||||
|
|
||||||
|
verify(repository, never()).createPlan(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void runningPdaAllocationStillRejectsConfirmingPreload() {
|
||||||
|
when(repository.findInbound(10, 20)).thenReturn(new InboundSnapshot(20L, 10L, "WAIT_SPLIT", 3));
|
||||||
|
PreloadPlanEntity plan = new PreloadPlanEntity();
|
||||||
|
plan.setStatus("CONFIRMING");
|
||||||
|
when(repository.findPlan(10, 20)).thenReturn(plan);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> service.ensureForRunningLoadingAllocation(10, 20, 7, "admin"))
|
||||||
|
.hasMessageContaining("已进入确认流程");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user