fix(lastleg): confirm pre-reserved pallets on PDA scan
This commit is contained in:
+32
@@ -66,6 +66,38 @@ 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 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"));
|
||||
|
||||
Reference in New Issue
Block a user