优化
This commit is contained in:
+2
-2
@@ -100,10 +100,10 @@ class LoadingListControllerContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void transportCorrectionRequiresReasonAndKeepsNullContainerAsUnchanged() {
|
||||
void transportCorrectionReasonIsRuntimeConditionalAndNullContainerKeepsCurrentValue() {
|
||||
assertThat(component(TransportUpdateRequest.class, "operationReason").getAccessor()
|
||||
.getAnnotation(NotBlank.class))
|
||||
.isNotNull();
|
||||
.isNull();
|
||||
assertThat(component(TransportUpdateRequest.class, "containerNo").getAccessor()
|
||||
.getAnnotation(NotBlank.class))
|
||||
.isNull();
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ class LoadingListQueryMapperContractTest {
|
||||
.contains("SET b.container_no = #{containerNo}, b.voyage_no = #{voyageNo}")
|
||||
.contains("p.plan_status='EDITING'")
|
||||
.contains("preload_pushed_at IS NOT NULL")
|
||||
.contains("#{containerNo} IS NOT NULL")
|
||||
.doesNotContain("#{containerNo} IS NOT NULL")
|
||||
.contains("fl_loading_pick_task", "fl_loading_pick_assignment")
|
||||
.doesNotContain("DELETE")
|
||||
.doesNotContain("fl_loading_plan_item");
|
||||
|
||||
@@ -72,4 +72,30 @@ class LoadingListRepositoryTest {
|
||||
assertThat(confirmed.planId()).isEqualTo(41L);
|
||||
assertThat(confirmed.containerBookingId()).isEqualTo(61L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingContainerNumberDoesNotBlockPreloadConfirmationOrPdaReadiness() {
|
||||
AggregateRow row = new AggregateRow();
|
||||
row.setPlanId(41L);
|
||||
row.setContainerBookingId(61L);
|
||||
row.setPlanNo("LP-41");
|
||||
row.setPlanStatus("EDITING");
|
||||
row.setVersion(1);
|
||||
row.setPreloadPushedAt(java.time.LocalDateTime.now());
|
||||
row.setPreloadLinkCount(2L);
|
||||
row.setConfirmedPreloadCount(0L);
|
||||
row.setOceanBookingId(81L);
|
||||
row.setOceanBookingStatus("RELEASED");
|
||||
when(mapper.selectItems(41L)).thenReturn(List.of());
|
||||
when(mapper.selectHistories(41L)).thenReturn(List.of());
|
||||
|
||||
var pending = repository.preloadDetail(row).summary().readiness();
|
||||
assertThat(pending.containerNoReady()).isFalse();
|
||||
assertThat(pending.canConfirm()).isTrue();
|
||||
assertThat(pending.blockingReasons()).doesNotContain("CONTAINER_NO_MISSING");
|
||||
|
||||
row.setConfirmedPreloadCount(2L);
|
||||
var confirmed = repository.preloadDetail(row).summary().readiness();
|
||||
assertThat(confirmed.readyForPda()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,20 +208,43 @@ class LoadingListServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadingPlanAndMissingInitialOceanBookingNumberBothRejectCorrection() {
|
||||
void loadingPlanRejectsTransportUpdateButPushedEditingPlanAllowsFirstContainerFill() {
|
||||
AggregateRow loading = row("LOADING", 3);
|
||||
loading.setPreloadPushedAt(java.time.LocalDateTime.now());
|
||||
loading.setContainerNo("MSCU6639870");
|
||||
AggregateRow missing = row("EDITING", 3);
|
||||
missing.setPreloadPushedAt(java.time.LocalDateTime.now());
|
||||
when(repository.aggregate(10L)).thenReturn(loading, missing);
|
||||
AggregateRow afterFill = row("EDITING", 4);
|
||||
afterFill.setPreloadPushedAt(missing.getPreloadPushedAt());
|
||||
afterFill.setContainerNo("CSQU3054383");
|
||||
when(repository.aggregate(10L)).thenReturn(loading, missing, afterFill);
|
||||
when(repository.updateTransport(10L, 3, "CSQU3054383", null, 9L, "operator"))
|
||||
.thenReturn(1);
|
||||
when(repository.preloadDetail(afterFill)).thenReturn(
|
||||
new com.baiyue.firstleg.dto.LoadingListDtos.PreloadDetail(null, List.of(), List.of()));
|
||||
|
||||
assertThatThrownBy(() -> service.updateTransport(10L, 100L, 9L, "operator", "loading-key",
|
||||
new TransportUpdateRequest("CSQU3054383", null, 3, "作业后纠错")))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("PDA尚未开始");
|
||||
assertThatThrownBy(() -> service.updateTransport(10L, 100L, 9L, "operator", "missing-key",
|
||||
new TransportUpdateRequest("CSQU3054383", null, 3, "首次补录")))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("首次写入");
|
||||
service.updateTransport(10L, 100L, 9L, "operator", "missing-key",
|
||||
new TransportUpdateRequest("CSQU3054383", null, 3, null));
|
||||
|
||||
verify(repository).updateTransport(10L, 3, "CSQU3054383", null, 9L, "operator");
|
||||
verify(loadingPickService).beginIfReady(30L, 9L, "operator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void correctingExistingContainerNumberStillRequiresReason() {
|
||||
AggregateRow before = row("EDITING", 3);
|
||||
before.setPreloadPushedAt(java.time.LocalDateTime.now());
|
||||
before.setContainerNo("MSCU6639870");
|
||||
when(repository.aggregate(10L)).thenReturn(before);
|
||||
|
||||
assertThatThrownBy(() -> service.updateTransport(10L, 100L, 9L, "operator", "reason-key",
|
||||
new TransportUpdateRequest("CSQU3054383", null, 3, null)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("纠错原因");
|
||||
|
||||
verify(repository, never()).updateTransport(anyLong(), anyInt(), any(), any(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -113,7 +113,7 @@ class LoadingPickServiceTest {
|
||||
}).when(completionTransaction).executeWithoutResult(any());
|
||||
ContainerBookingEntity booking = new ContainerBookingEntity();
|
||||
booking.setId(99L);
|
||||
booking.setContainerNo("CSLU1234567");
|
||||
booking.setContainerNo("MSCU6639870");
|
||||
booking.setWarehouseId(101L);
|
||||
booking.setSourceType("SIMULATION");
|
||||
booking.setRecordStatus("ACTIVE");
|
||||
@@ -124,9 +124,9 @@ class LoadingPickServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void opensTaskOnlyAfterReleasedBookingAndRealContainerNumber() {
|
||||
void opensTaskAfterReleasedBookingWithoutWaitingForRealContainerNumber() {
|
||||
var booking = new com.baiyue.firstleg.entity.ContainerBookingEntity();
|
||||
booking.setId(40L); booking.setContainerNo("MSCU-001");
|
||||
booking.setId(40L);
|
||||
var plan = new com.baiyue.firstleg.entity.LoadingPlanEntity();
|
||||
plan.setId(10L); plan.setContainerBookingId(40L); plan.setPlanStatus("EDITING");
|
||||
plan.setPreloadPushedAt(java.time.LocalDateTime.now());
|
||||
@@ -136,7 +136,7 @@ class LoadingPickServiceTest {
|
||||
when(smartLoadingRepository.planByBooking(40L)).thenReturn(plan);
|
||||
when(smartLoadingRepository.plan(10L)).thenReturn(plan);
|
||||
when(loadingModelBridge.byLoadingPlan(10L)).thenReturn(List.of(
|
||||
new Link(1L, 1L, 50L, 2L, "CONFIRMED", 1, 10L, 40L, "MSCU-001", "EDITING", 1, 1, null)));
|
||||
new Link(1L, 1L, 50L, 2L, "CONFIRMED", 1, 10L, 40L, null, "EDITING", 1, 1, null)));
|
||||
when(oceanBookingRepository.allocationByContainer(40L)).thenReturn(allocation);
|
||||
when(oceanBookingRepository.find(90L)).thenReturn(ocean);
|
||||
when(repository.taskByPlan(10L)).thenReturn(null);
|
||||
@@ -191,11 +191,11 @@ class LoadingPickServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void planConfirmationGateRequiresRealContainerAndReleasedBooking() {
|
||||
void planConfirmationGateRequiresReleasedBookingButNotRealContainerNumber() {
|
||||
Link link = new Link(1L, 1L, 50L, 2L, "PENDING", 1,
|
||||
10L, 40L, "MSCU-001", "EDITING", 3, 2, null);
|
||||
var booking = new com.baiyue.firstleg.entity.ContainerBookingEntity();
|
||||
booking.setId(40L); booking.setContainerNo("MSCU-001");
|
||||
booking.setId(40L);
|
||||
var allocation = new OceanBookingContainerAllocationEntity();
|
||||
allocation.setOceanBookingId(90L);
|
||||
var ocean = new OceanBookingEntity();
|
||||
@@ -209,17 +209,21 @@ class LoadingPickServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void planConfirmationGateRejectsMissingRealContainerNumber() {
|
||||
void planConfirmationGateAllowsMissingRealContainerNumber() {
|
||||
Link link = new Link(1L, 1L, 50L, 2L, "PENDING", 1,
|
||||
10L, 40L, null, "EDITING", 3, 2, null);
|
||||
var booking = new com.baiyue.firstleg.entity.ContainerBookingEntity();
|
||||
booking.setId(40L);
|
||||
var allocation = new OceanBookingContainerAllocationEntity();
|
||||
allocation.setOceanBookingId(90L);
|
||||
var ocean = new OceanBookingEntity();
|
||||
ocean.setId(90L); ocean.setStatus("RELEASED");
|
||||
when(loadingModelBridge.requireAllocatedLinksForConfirmation(10L)).thenReturn(List.of(link));
|
||||
when(smartLoadingRepository.booking(40L)).thenReturn(booking);
|
||||
when(oceanBookingRepository.allocationByContainer(40L)).thenReturn(allocation);
|
||||
when(oceanBookingRepository.find(90L)).thenReturn(ocean);
|
||||
|
||||
assertThatThrownBy(() -> service.requirePreloadConfirmationReady(10L))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("真实集装箱号");
|
||||
verify(oceanBookingRepository, never()).allocationByContainer(anyLong());
|
||||
assertThat(service.requirePreloadConfirmationReady(10L)).containsExactly(link);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -775,6 +779,25 @@ class LoadingPickServiceTest {
|
||||
verify(loadingListService, never()).finishFromPda(anyLong(), anyLong(), anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void completionRejectsMissingRealContainerNumberBeforeCreatingCommand() {
|
||||
LoadingPickTaskEntity loading = task();
|
||||
ContainerBookingEntity booking = new ContainerBookingEntity();
|
||||
booking.setId(99L);
|
||||
booking.setWarehouseId(101L);
|
||||
booking.setRecordStatus("ACTIVE");
|
||||
when(repository.taskForUpdate(20L)).thenReturn(loading);
|
||||
when(repository.activeBookingByTask(20L)).thenReturn(booking);
|
||||
|
||||
assertThatThrownBy(() -> service.complete(20L,
|
||||
new CompleteLoadingRequest(0, "complete-missing-container", "checked"), 9L, "operator"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("确认装柜完成前");
|
||||
|
||||
verify(repository, never()).allTaskItemsResolved(20L);
|
||||
verify(completionCommands, never()).insert(any());
|
||||
verify(repository, never()).acceptCompletion(anyLong(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentOperationIdIsRejectedImmediatelyWithConflict() {
|
||||
// different operationId is a canonical A0409 CONFLICT while the durable command is active.
|
||||
|
||||
Reference in New Issue
Block a user