Merge remote-tracking branch 'origin/test' into dev
# Conflicts: # deploy/sql/海外区域统一增量-MySQL8.sql # lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/HttpWarehouseResourceGateway.java # lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/WarehouseResourceGateway.java # lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/ReceivingContainerService.java # lastleg-service/src/main/resources/db/lastleg.sql # lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/gateway/HttpWarehouseResourceGatewayTest.java
This commit is contained in:
+32
@@ -66,6 +66,22 @@ class HttpWarehouseResourceGatewayTest {
|
||||
server.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveReservedAcceptsOnlyExactOccupiedPlanBinding() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/PAL-RESERVED"))
|
||||
.andRespond(withSuccess("""
|
||||
{"code":"200","data":{"palletId":31,"palletCode":"PAL-RESERVED",
|
||||
"warehouseId":21,"locationId":41,"status":"OCCUPIED","version":3,
|
||||
"reservable":false,"reservationBlockReason":"PALLET_NOT_IDLE"}}
|
||||
""", MediaType.APPLICATION_JSON));
|
||||
|
||||
var result = gateway.resolveReservedPallet("PAL-RESERVED", "11", 21L, 31L, 41L, 51L);
|
||||
|
||||
assertThat(result.palletId()).isEqualTo(31L);
|
||||
assertThat(result.status()).isEqualTo("OCCUPIED");
|
||||
server.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void inspectAllowsOccupiedPalletForReadOnlyInventoryQueries() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/PAL-OCCUPIED"))
|
||||
@@ -84,6 +100,22 @@ class HttpWarehouseResourceGatewayTest {
|
||||
server.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveReservedRejectsDifferentPhysicalBinding() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/PAL-RESERVED"))
|
||||
.andRespond(withSuccess("""
|
||||
{"code":"200","data":{"palletId":31,"palletCode":"PAL-RESERVED",
|
||||
"warehouseId":21,"locationId":99,"status":"OCCUPIED","version":3,
|
||||
"reservable":false,"reservationBlockReason":"PALLET_NOT_IDLE"}}
|
||||
""", MediaType.APPLICATION_JSON));
|
||||
|
||||
assertThatThrownBy(() -> gateway.resolveReservedPallet("PAL-RESERVED", "11", 21L, 31L, 41L, 51L))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("409")
|
||||
.hasMessageContaining("does not match");
|
||||
server.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveFailsClosedWhenWarehouseOmitsReservationFacts() {
|
||||
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/PAL-UNKNOWN"))
|
||||
|
||||
+92
@@ -188,6 +188,98 @@ class InboundPdaWorkflowServiceTest {
|
||||
verify(repository).update(targetPallet);
|
||||
}
|
||||
|
||||
@Test
|
||||
void reservedPalletScanConfirmsOnSiteWithoutReservingAgainAndAdvancesPlan() {
|
||||
plan.setStatus("RESERVED");
|
||||
targetPallet.setPalletNo("IP-ACY2-20260909-P001");
|
||||
targetPallet.setWarehousePalletId(188L);
|
||||
targetPallet.setWarehouseLocationId(288L);
|
||||
targetPallet.setWarehouseResourceLockId(999L);
|
||||
targetPallet.setAssignmentStatus("RESERVED");
|
||||
targetPallet.setLockedAt(null);
|
||||
WarehouseResourceGateway.WarehousePalletReference resource =
|
||||
new WarehouseResourceGateway.WarehousePalletReference(188L, "A002", 88L, 288L,
|
||||
"OCCUPIED", "ACY2", 1);
|
||||
when(repository.pallets(plan.getId())).thenReturn(List.of(targetPallet));
|
||||
|
||||
service.assignResolvedPallet("100", plan, targetPallet, resource);
|
||||
service.assignResolvedPallet("100", plan, targetPallet, resource);
|
||||
|
||||
assertEquals("A002", targetPallet.getPalletNo());
|
||||
assertEquals("ASSIGNED", targetPallet.getAssignmentStatus());
|
||||
org.junit.jupiter.api.Assertions.assertNotNull(targetPallet.getLockedAt());
|
||||
assertEquals("ASSIGNED", plan.getStatus());
|
||||
verify(warehouse, never()).reserve(any(), anyLong(), anyLong(), anyLong(), any(), any(), any());
|
||||
verify(repository, times(1)).update(targetPallet);
|
||||
verify(repository, times(1)).update(plan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicAssignmentAlsoConfirmsReservedPalletWithoutReservingAgain() {
|
||||
plan.setStatus("PENDING_ASSIGNMENT");
|
||||
targetPallet.setDestinationWarehouseId("88");
|
||||
targetPallet.setWarehousePalletId(188L);
|
||||
targetPallet.setWarehouseLocationId(288L);
|
||||
targetPallet.setWarehouseResourceLockId(999L);
|
||||
targetPallet.setAssignmentStatus("RESERVED");
|
||||
targetPallet.setLockedAt(null);
|
||||
when(repository.lockPallet(plan.getId(), targetPallet.getId())).thenReturn(targetPallet);
|
||||
when(repository.pallets(plan.getId())).thenReturn(List.of(targetPallet));
|
||||
|
||||
service.assign("100", "LIP1", targetPallet.getId(),
|
||||
new PdaRequests.Assign(88L, 188L, 288L, "reserved-public"));
|
||||
service.assign("100", "LIP1", targetPallet.getId(),
|
||||
new PdaRequests.Assign(88L, 188L, 288L, "reserved-public-retry"));
|
||||
|
||||
assertEquals("ASSIGNED", targetPallet.getAssignmentStatus());
|
||||
assertEquals("ASSIGNED", plan.getStatus());
|
||||
verify(warehouse, never()).reserve(any(), anyLong(), anyLong(), anyLong(), any(), any(), any());
|
||||
verify(repository, times(1)).update(targetPallet);
|
||||
verify(repository, times(1)).update(plan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void reservedConfirmationDoesNotRegressAdvancedPlanStatus() {
|
||||
plan.setStatus("SIGNED");
|
||||
targetPallet.setWarehousePalletId(188L);
|
||||
targetPallet.setWarehouseLocationId(288L);
|
||||
targetPallet.setWarehouseResourceLockId(999L);
|
||||
targetPallet.setAssignmentStatus("RESERVED");
|
||||
WarehouseResourceGateway.WarehousePalletReference resource =
|
||||
new WarehouseResourceGateway.WarehousePalletReference(188L, "A002", 88L, 288L,
|
||||
"OCCUPIED", "ACY2", 1);
|
||||
when(repository.pallets(plan.getId())).thenReturn(List.of(targetPallet));
|
||||
|
||||
service.assignResolvedPallet("100", plan, targetPallet, resource);
|
||||
|
||||
assertEquals("ASSIGNED", targetPallet.getAssignmentStatus());
|
||||
assertEquals("SIGNED", plan.getStatus());
|
||||
verify(repository, never()).update(plan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void reservedPalletScanRejectsAnotherPhysicalPalletOrLocation() {
|
||||
targetPallet.setWarehousePalletId(188L);
|
||||
targetPallet.setWarehouseLocationId(288L);
|
||||
targetPallet.setWarehouseResourceLockId(999L);
|
||||
targetPallet.setAssignmentStatus("RESERVED");
|
||||
WarehouseResourceGateway.WarehousePalletReference anotherPallet =
|
||||
new WarehouseResourceGateway.WarehousePalletReference(189L, "A003", 88L, 288L,
|
||||
"IDLE", "ACY2", 1);
|
||||
WarehouseResourceGateway.WarehousePalletReference anotherLocation =
|
||||
new WarehouseResourceGateway.WarehousePalletReference(188L, "A002", 88L, 289L,
|
||||
"IDLE", "ACY2", 1);
|
||||
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.assignResolvedPallet("100", plan, targetPallet, anotherPallet));
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.assignResolvedPallet("100", plan, targetPallet, anotherLocation));
|
||||
|
||||
assertEquals("RESERVED", targetPallet.getAssignmentStatus());
|
||||
verify(warehouse, never()).reserve(any(), anyLong(), anyLong(), anyLong(), any(), any(), any());
|
||||
verify(repository, never()).update(targetPallet);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvedAssignmentRejectsPhysicalPalletWithoutBusinessCodeBeforeReservation() {
|
||||
targetPallet.setWarehouseResourceLockId(null);
|
||||
|
||||
+31
@@ -465,6 +465,37 @@ class ReceivingContainerServiceBehaviorTest {
|
||||
verify(workflow).compensateReservation("100", 55L, failure);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bulkReceivingResolvesExactPreReservedPalletWithoutIdleLookup() {
|
||||
stubCurrent("FBA", "CONT-A");
|
||||
stubSku();
|
||||
InboundPlanPallet reserved = planPallet();
|
||||
reserved.setPalletNo("PAL-RESERVED");
|
||||
reserved.setWarehousePalletId(30L);
|
||||
reserved.setWarehouseLocationId(40L);
|
||||
reserved.setWarehouseResourceLockId(50L);
|
||||
reserved.setAssignmentStatus("RESERVED");
|
||||
when(pallets.selectList(any())).thenReturn(List.of(reserved));
|
||||
WarehouseResourceGateway.WarehousePalletReference occupied =
|
||||
new WarehouseResourceGateway.WarehousePalletReference(30L, "PAL-RESERVED", 100L, 40L,
|
||||
"OCCUPIED", "FBA-1", 0);
|
||||
when(warehouse.resolveReservedPallet("PAL-RESERVED", "100", 100L, 30L, 40L, 50L))
|
||||
.thenReturn(occupied);
|
||||
when(workflow.receiveBulkResolved(any(), any(), any(), any(), anyInt(), any(), any()))
|
||||
.thenReturn(1);
|
||||
when(sessions.updateById(any(ReceivingContainerSession.class))).thenReturn(1);
|
||||
when(operations.insert(any(ReceivingContainerOperation.class))).thenReturn(1);
|
||||
|
||||
service.receiveBulk("7", "receiver",
|
||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-RESERVED", 1, "reserved-key"));
|
||||
|
||||
verify(warehouse).resolveReservedPallet("PAL-RESERVED", "100", 100L, 30L, 40L, 50L);
|
||||
verify(warehouse, never()).resolvePallet("PAL-RESERVED");
|
||||
verify(workflow).assignResolvedPallet(org.mockito.ArgumentMatchers.eq("100"),
|
||||
any(InboundPlan.class), org.mockito.ArgumentMatchers.same(reserved),
|
||||
org.mockito.ArgumentMatchers.same(occupied));
|
||||
}
|
||||
|
||||
@Test
|
||||
void signRequiresEachTypedPhotoExactlyOnceAndRestoresRoles() {
|
||||
when(sessions.lockActiveByOperator("OPERATOR:7")).thenReturn(session("CONT-A", "WAIT_SIGN"));
|
||||
|
||||
+142
-1
@@ -1,9 +1,11 @@
|
||||
package com.baiyue.lastleg.inboundplan.service;
|
||||
|
||||
import com.baiyue.lastleg.inboundplan.dto.ConvertContainerInboundPlanRequest;
|
||||
import com.baiyue.lastleg.inboundplan.dto.ContainerInboundPlanPreviewResponse;
|
||||
import com.baiyue.lastleg.inboundplan.entity.ContainerPlanConversionCommand;
|
||||
import com.baiyue.lastleg.inboundplan.mapper.ContainerPlanConversionCommandMapper;
|
||||
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -11,8 +13,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.support.SimpleTransactionStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -20,6 +26,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ContainerInboundPlanConversionCoordinatorTest {
|
||||
@@ -29,6 +37,8 @@ class ContainerInboundPlanConversionCoordinatorTest {
|
||||
@Mock InboundPlanService plans;
|
||||
@Mock WarehouseResourceGateway warehouse;
|
||||
@Mock ContainerPlanConversionCommandMapper commands;
|
||||
@Mock LastlegOrderNoGenerator numbers;
|
||||
@Mock PlatformTransactionManager transactionManager;
|
||||
|
||||
private ContainerInboundPlanConversionCoordinator coordinator;
|
||||
private JsonMapper objectMapper;
|
||||
@@ -40,7 +50,11 @@ class ContainerInboundPlanConversionCoordinatorTest {
|
||||
ReflectionTestUtils.setField(coordinator, "plans", plans);
|
||||
ReflectionTestUtils.setField(coordinator, "warehouse", warehouse);
|
||||
ReflectionTestUtils.setField(coordinator, "commands", commands);
|
||||
ReflectionTestUtils.setField(coordinator, "numbers", numbers);
|
||||
ReflectionTestUtils.setField(coordinator, "objectMapper", objectMapper);
|
||||
ReflectionTestUtils.setField(coordinator, "transactionManager", transactionManager);
|
||||
org.mockito.Mockito.lenient().when(transactionManager.getTransaction(any()))
|
||||
.thenReturn(new SimpleTransactionStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -57,6 +71,19 @@ class ContainerInboundPlanConversionCoordinatorTest {
|
||||
verify(commands, never()).insert(org.mockito.ArgumentMatchers.any(ContainerPlanConversionCommand.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameIdempotencyKeyStillRejectsAlteredCompletedRequest() throws Exception {
|
||||
ContainerPlanConversionCommand completed = command("FIRST-KEY", "COMPLETED", request());
|
||||
completed.setResultJson("[]");
|
||||
when(commands.find(BOOKING_ID, "FIRST-KEY")).thenReturn(completed);
|
||||
|
||||
ConvertContainerInboundPlanRequest changed =
|
||||
new ConvertContainerInboundPlanRequest(BOOKING_ID, 8L, "b".repeat(64));
|
||||
|
||||
assertEquals(409, assertThrows(ResponseStatusException.class,
|
||||
() -> coordinator.confirm(changed, "FIRST-KEY")).getStatusCode().value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void concurrentCabinetClaimRejectsFollowerBeforeWarehouseReservation() throws Exception {
|
||||
ConvertContainerInboundPlanRequest request = request();
|
||||
@@ -78,7 +105,7 @@ class ContainerInboundPlanConversionCoordinatorTest {
|
||||
when(commands.find(BOOKING_ID, "SECOND-KEY")).thenReturn(null);
|
||||
when(commands.findByBooking(BOOKING_ID)).thenReturn(prepared);
|
||||
when(commands.claim(org.mockito.ArgumentMatchers.eq(1L), org.mockito.ArgumentMatchers.eq("PREPARED"),
|
||||
org.mockito.ArgumentMatchers.eq("APPLYING"), org.mockito.ArgumentMatchers.any())).thenReturn(0);
|
||||
org.mockito.ArgumentMatchers.eq("APPLYING"), any(String.class), org.mockito.ArgumentMatchers.any())).thenReturn(0);
|
||||
|
||||
ResponseStatusException error = assertThrows(ResponseStatusException.class,
|
||||
() -> coordinator.confirm(request, "SECOND-KEY"));
|
||||
@@ -102,6 +129,102 @@ class ContainerInboundPlanConversionCoordinatorTest {
|
||||
assertEquals(409, error.getStatusCode().value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void staleApplyingLeaseIsReclaimedWithoutRepeatingPreparedClaim() throws Exception {
|
||||
ConvertContainerInboundPlanRequest request = request();
|
||||
ContainerPlanConversionCommand stale = command("FIRST-KEY", "APPLYING", request);
|
||||
stale.setUpdatedAt(LocalDateTime.now().minusMinutes(3));
|
||||
when(commands.find(BOOKING_ID, "FIRST-KEY")).thenReturn(stale);
|
||||
when(commands.reclaimStale(eq(1L), eq(stale.getUpdatedAt()), any(String.class), any())).thenReturn(1);
|
||||
when(plans.convertContainerReserved(BOOKING_ID, 7L, SNAPSHOT_HASH, List.of())).thenReturn(List.of());
|
||||
when(commands.updateState(eq(1L), eq("APPLYING"), any(String.class), eq("COMPLETED"), eq("[]"),
|
||||
org.mockito.ArgumentMatchers.isNull(), any())).thenReturn(1);
|
||||
|
||||
assertEquals(List.of(), coordinator.confirm(request, "FIRST-KEY"));
|
||||
|
||||
verify(commands, never()).claim(any(Long.class), any(String.class), any(String.class),
|
||||
any(String.class), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void compensatedFailureCanBeReplacedByFreshSnapshotAndComplete() throws Exception {
|
||||
ContainerPlanConversionCommand failed = command("OLD-KEY", "FAILED", request());
|
||||
when(commands.find(BOOKING_ID, "NEW-KEY")).thenReturn(null);
|
||||
when(commands.findByBooking(BOOKING_ID)).thenReturn(failed);
|
||||
when(plans.previewContainer(BOOKING_ID)).thenReturn(preview(8L, "b".repeat(64)));
|
||||
when(commands.replaceFailed(eq(1L), eq("NEW-KEY"), any(), eq(8L), eq("b".repeat(64)),
|
||||
eq(31L), any(), any(), any())).thenReturn(1);
|
||||
when(commands.claim(eq(1L), eq("PREPARED"), eq("APPLYING"), any(String.class), any())).thenReturn(1);
|
||||
when(plans.convertContainerReserved(BOOKING_ID, 8L, "b".repeat(64), List.of())).thenReturn(List.of());
|
||||
when(commands.updateState(eq(1L), eq("APPLYING"), any(String.class), eq("COMPLETED"), eq("[]"),
|
||||
org.mockito.ArgumentMatchers.isNull(), any())).thenReturn(1);
|
||||
|
||||
assertEquals(List.of(), coordinator.confirm(
|
||||
new ConvertContainerInboundPlanRequest(BOOKING_ID, 8L, "b".repeat(64)), "NEW-KEY"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidEnsureResponseIsCompensatedBeforeCommandBecomesFailed() throws Exception {
|
||||
ConvertContainerInboundPlanRequest request = request();
|
||||
ContainerPlanConversionCommand prepared = command("FIRST-KEY", "PREPARED", request);
|
||||
setOnePreparedItem(prepared);
|
||||
when(commands.find(BOOKING_ID, "FIRST-KEY")).thenReturn(prepared);
|
||||
when(commands.claim(eq(1L), eq("PREPARED"), eq("APPLYING"), any(String.class), any())).thenReturn(1);
|
||||
when(warehouse.ensurePalletBatch(any())).thenReturn(new WarehouseResourceGateway.PalletBatchResponse(
|
||||
0L, "BATCH-1", "RESERVED", 1, false, List.of(reserved("RESERVED"))));
|
||||
when(warehouse.compensatePalletBatch(any())).thenReturn(new WarehouseResourceGateway.PalletBatchResponse(
|
||||
41L, "BATCH-1", "COMPENSATED", 1, false, List.of(reserved("RELEASED"))));
|
||||
when(commands.updateState(eq(1L), eq("APPLYING"), any(String.class), eq("FAILED"),
|
||||
org.mockito.ArgumentMatchers.isNull(), any(), any())).thenReturn(1);
|
||||
|
||||
assertEquals(409, assertThrows(ResponseStatusException.class,
|
||||
() -> coordinator.confirm(request, "FIRST-KEY")).getStatusCode().value());
|
||||
|
||||
verify(warehouse).compensatePalletBatch(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void uncertainLocalCommitIsRereadBeforeDecidingWhetherToCompensate() throws Exception {
|
||||
ConvertContainerInboundPlanRequest request = request();
|
||||
ContainerPlanConversionCommand prepared = command("FIRST-KEY", "PREPARED", request);
|
||||
setOnePreparedItem(prepared);
|
||||
ContainerPlanConversionCommand committed = command("FIRST-KEY", "LOCAL_COMMITTED", request);
|
||||
committed.setResultJson("[]");
|
||||
when(commands.find(BOOKING_ID, "FIRST-KEY")).thenReturn(prepared);
|
||||
when(commands.claim(eq(1L), eq("PREPARED"), eq("APPLYING"), any(String.class), any())).thenReturn(1);
|
||||
when(warehouse.ensurePalletBatch(any())).thenReturn(new WarehouseResourceGateway.PalletBatchResponse(
|
||||
41L, "BATCH-1", "RESERVED", 1, false, List.of(reserved("RESERVED"))));
|
||||
when(plans.convertContainerReserved(eq(BOOKING_ID), eq(7L), eq(SNAPSHOT_HASH), any()))
|
||||
.thenThrow(new IllegalStateException("commit outcome unknown"));
|
||||
when(commands.findByBooking(BOOKING_ID)).thenReturn(committed);
|
||||
when(warehouse.confirmPalletBatch(any())).thenReturn(new WarehouseResourceGateway.PalletBatchResponse(
|
||||
41L, "BATCH-1", "CONFIRMED", 1, false, List.of(reserved("CONFIRMED"))));
|
||||
when(commands.updateState(eq(1L), eq("LOCAL_COMMITTED"), any(String.class), eq("COMPLETED"), eq("[]"),
|
||||
org.mockito.ArgumentMatchers.isNull(), any())).thenReturn(1);
|
||||
|
||||
assertEquals(List.of(), coordinator.confirm(request, "FIRST-KEY"));
|
||||
|
||||
verify(warehouse, never()).compensatePalletBatch(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void localCommittedReplayOnlyRetriesRemoteConfirmation() throws Exception {
|
||||
ConvertContainerInboundPlanRequest request = request();
|
||||
ContainerPlanConversionCommand committed = command("FIRST-KEY", "LOCAL_COMMITTED", request);
|
||||
committed.setResultJson("[]");
|
||||
setOnePreparedItem(committed);
|
||||
when(commands.find(BOOKING_ID, "FIRST-KEY")).thenReturn(committed);
|
||||
when(warehouse.confirmPalletBatch(any())).thenReturn(new WarehouseResourceGateway.PalletBatchResponse(
|
||||
41L, "BATCH-1", "CONFIRMED", 1, false, List.of(reserved("CONFIRMED"))));
|
||||
when(commands.updateState(eq(1L), eq("LOCAL_COMMITTED"), any(String.class), eq("COMPLETED"), eq("[]"),
|
||||
org.mockito.ArgumentMatchers.isNull(), any())).thenReturn(1);
|
||||
|
||||
assertEquals(List.of(), coordinator.confirm(request, "FIRST-KEY"));
|
||||
|
||||
verify(warehouse, never()).ensurePalletBatch(any());
|
||||
verify(warehouse).confirmPalletBatch(any());
|
||||
}
|
||||
|
||||
private ConvertContainerInboundPlanRequest request() {
|
||||
return new ConvertContainerInboundPlanRequest(BOOKING_ID, 7L, SNAPSHOT_HASH);
|
||||
}
|
||||
@@ -119,8 +242,26 @@ class ContainerInboundPlanConversionCoordinatorTest {
|
||||
command.setWarehouseId(31L);
|
||||
command.setBatchKey("BATCH-1");
|
||||
command.setStatus(status);
|
||||
if ("APPLYING".equals(status) || "LOCAL_COMMITTED".equals(status)) command.setLeaseToken("LEASE-1");
|
||||
command.setPreparationJson(objectMapper.writeValueAsString(
|
||||
new ContainerInboundPlanConversionCoordinator.Preparation(31L, List.of())));
|
||||
return command;
|
||||
}
|
||||
|
||||
private void setOnePreparedItem(ContainerPlanConversionCommand command) throws Exception {
|
||||
var item = new ContainerInboundPlanConversionCoordinator.PreparedItem(
|
||||
"100", 11L, 21L, "IP-21", 1, 1, "CIP:1:1", "ONT8");
|
||||
command.setPreparationJson(objectMapper.writeValueAsString(
|
||||
new ContainerInboundPlanConversionCoordinator.Preparation(31L, List.of(item))));
|
||||
}
|
||||
|
||||
private WarehouseResourceGateway.PalletBatchItem reserved(String status) {
|
||||
return new WarehouseResourceGateway.PalletBatchItem(
|
||||
100L, "CIP:1:1", "IP-21", 1, 51L, "PLT-51", 61L, 71L, status);
|
||||
}
|
||||
|
||||
private ContainerInboundPlanPreviewResponse preview(long version, String hash) {
|
||||
return new ContainerInboundPlanPreviewResponse(BOOKING_ID, "MSCU6639870", "31", "US-LAX-01",
|
||||
"Los Angeles", version, hash, 1, 1, 0, 0, 0, 1, 1, 1, true, List.of());
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -67,6 +67,21 @@ class ContainerInboundPlanPreviewTest {
|
||||
assertEquals(List.of("DESTINATION_NOT_READY"), result.groups().get(4).orders().get(0).blockers());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashesBlockedPreviewEvenWhenContainerAndWarehouseFactsAreNull() {
|
||||
when(orderMapper.containerPreviewOrders("BOOKING-NULL")).thenReturn(List.of(
|
||||
new InboundPlanOrderMapper.ContainerPreviewOrderRow("100", 1L, "LM-1", "FO-1", "测试客户",
|
||||
"FIRST_LEG", "OVERSEAS", "IN-1", "PENDING_ASSIGNMENT", null, null, 0, 0,
|
||||
BigDecimal.ZERO, null, null, null, null, null, null, null, 0, false, 1,
|
||||
null, null, null)));
|
||||
|
||||
var result = service.previewContainer("BOOKING-NULL");
|
||||
|
||||
assertNotNull(result.snapshotHash());
|
||||
assertEquals(64, result.snapshotHash().length());
|
||||
assertFalse(result.ready());
|
||||
}
|
||||
|
||||
private InboundPlanOrderMapper.ContainerPreviewOrderRow row(
|
||||
long id, String orderNo, String orderType, String destinationType, String destinationCode, String destinationName,
|
||||
int recommendedPallets, String planNo, Integer plannedPallets, int version) {
|
||||
|
||||
Reference in New Issue
Block a user