贴标申请,仓储转运
This commit is contained in:
+1
-1
@@ -25,7 +25,7 @@ class PdaPalletOperationControllerContractTest {
|
||||
.filter(PostMapping.class::isInstance).map(PostMapping.class::cast)
|
||||
.flatMap(annotation -> Arrays.stream(annotation.value())).collect(Collectors.toSet());
|
||||
assertEquals(Set.of("/pallets/resolve", "/relabel-pallet-label", "/assemble", "/disassemble",
|
||||
"/relabel-disassemble", "/swap", "/unbind"), paths);
|
||||
"/relabel-disassemble", "/relabel-sources", "/swap", "/unbind"), paths);
|
||||
}
|
||||
|
||||
@Test void palletContentAnnotationUsesNativeGreaterThanOperator() throws Exception {
|
||||
|
||||
+107
-1
@@ -42,6 +42,17 @@ import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PdaPalletOperationServiceTest {
|
||||
@Test void relabelRebindingRejectsDispatchAndOutboundOccupation() {
|
||||
RelabelApplication app = new RelabelApplication();
|
||||
for (String status : List.of("PRE_DISPATCH_CREATED", "OUTBOUND_CREATED", "OUTBOUNDED")) {
|
||||
app.setFulfillmentStatus(status);
|
||||
assertThrows(ResponseStatusException.class, () -> ReflectionTestUtils.invokeMethod(service, "requireUnallocatedRelabel", app));
|
||||
}
|
||||
app.setFulfillmentStatus("WAIT_PRE_DISPATCH");
|
||||
assertDoesNotThrow(() -> ReflectionTestUtils.invokeMethod(service, "requireUnallocatedRelabel", app));
|
||||
app.setOutboundOrderNo("OUT-1");
|
||||
assertThrows(ResponseStatusException.class, () -> ReflectionTestUtils.invokeMethod(service, "requireUnallocatedRelabel", app));
|
||||
}
|
||||
@Mock private PdaPalletOperationMapper mapper;
|
||||
@Mock private InventoryPositionMapper positions;
|
||||
@Mock private InventoryBalanceMapper balances;
|
||||
@@ -185,6 +196,13 @@ class PdaPalletOperationServiceTest {
|
||||
}
|
||||
|
||||
@Test void relabelDisassembleMovesOnlySelectedHeldCartonWithoutRequiringLocations() {
|
||||
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
|
||||
var histories = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelHistoryMapper.class);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkTasks", tasks);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkHistory", histories);
|
||||
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask();
|
||||
task.setId(900L); task.setStatus("COMPLETED");
|
||||
when(tasks.find("100", 600L)).thenReturn(task);
|
||||
var sourcePallet = new PalletPhysicalGateway.PalletReference(20L, "SOURCE", 88L, null,
|
||||
"OCCUPIED", null, 1);
|
||||
var targetPallet = new PalletPhysicalGateway.PalletReference(10L, "TARGET", 88L, null,
|
||||
@@ -196,7 +214,7 @@ class PdaPalletOperationServiceTest {
|
||||
|
||||
RelabelApplication application = new RelabelApplication(); application.setId(600L);
|
||||
application.setCustomerId("100"); application.setRelabelNo("RL-1"); application.setStatus("READY_FOR_OUTBOUND");
|
||||
application.setOverseasWarehouseId("88"); application.setOutboundOrderNo("OUT-1");
|
||||
application.setOverseasWarehouseId("88"); application.setFulfillmentStatus("WAIT_PRE_DISPATCH");
|
||||
when(relabelApplications.findAnyByRelabelNo("RL-1")).thenReturn(application);
|
||||
when(relabelApplications.lockAnyByRelabelNo("RL-1")).thenReturn(application);
|
||||
RelabelItem selected = relabelItem(701L, "CARTON-A", 100L);
|
||||
@@ -266,6 +284,94 @@ class PdaPalletOperationServiceTest {
|
||||
relabelPalletMutations);
|
||||
}
|
||||
|
||||
@Test void actualSourceReconcilesOnlySelectedHoldAndKeepsOriginalInboundBalance() {
|
||||
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
|
||||
var histories = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelHistoryMapper.class);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkTasks", tasks);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkHistory", histories);
|
||||
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask(); task.setId(900L); task.setStatus("COMPLETED");
|
||||
when(tasks.find("100", 600L)).thenReturn(task);
|
||||
RelabelApplication app = new RelabelApplication(); app.setId(600L); app.setRelabelNo("RL-1");
|
||||
app.setCustomerId("100"); app.setOverseasWarehouseId("88"); app.setStatus("READY_FOR_OUTBOUND");
|
||||
when(relabelApplications.findAnyByRelabelNo("RL-1")).thenReturn(app);
|
||||
when(relabelApplications.lockAnyByRelabelNo("RL-1")).thenReturn(app);
|
||||
RelabelItem item = relabelItem(701L, "CARTON-A", 101L);
|
||||
when(relabelItems.selectList(any())).thenReturn(List.of(item));
|
||||
when(relabelItems.selectById(701L)).thenReturn(item);
|
||||
InventoryPosition anchor = position(101L, 30L, "ACCOUNTING", 2L, 3L);
|
||||
InventoryPosition actual = position(100L, 20L, "SOURCE", 0L, 4L); actual.setAvailablePackages(5L);
|
||||
AtomicReference<InventoryPosition> target = new AtomicReference<>();
|
||||
when(positions.selectById(anyLong())).thenAnswer(invocation -> {
|
||||
long id = invocation.getArgument(0); return id == 101L ? anchor : id == 100L ? actual : target.get();
|
||||
});
|
||||
doAnswer(invocation -> { target.set(invocation.getArgument(0)); return 1; }).when(positions).insert(any(InventoryPosition.class));
|
||||
when(mapper.lockPosition(eq("88"), anyLong())).thenAnswer(invocation -> {
|
||||
InventoryPosition p = ((Long) invocation.getArgument(1)) == 101L ? anchor : actual;
|
||||
PalletInventoryRow row = row(p.getId(), p.getPalletId(), p.getVersion(), p.getAvailablePackages());
|
||||
row.setHoldPackages(p.getHoldPackages()); return row;
|
||||
});
|
||||
var src = new PalletPhysicalGateway.PalletReference(20L, "SOURCE", 88L, null, "OCCUPIED", null, 1);
|
||||
var dst = new PalletPhysicalGateway.PalletReference(10L, "TARGET", 88L, null, "IDLE", null, 2);
|
||||
when(physical.resolve("SOURCE")).thenReturn(src); when(physical.resolve("TARGET")).thenReturn(dst);
|
||||
when(physical.apply(eq(88L), any(), anyString(), isNull(), anyString(), any()))
|
||||
.thenAnswer(invocation -> transition(invocation.getArgument(1), invocation.getArgument(2)));
|
||||
when(mapper.content("88", 10L)).thenReturn(List.of());
|
||||
when(mapper.palletPackages("88", 20L)).thenAnswer(invocation -> actual.getAvailablePackages() + actual.getHoldPackages());
|
||||
when(mapper.palletPackages("88", 10L)).thenAnswer(invocation -> target.get() == null ? 0L : target.get().getHoldPackages());
|
||||
InventoryBalance balance = new InventoryBalance(); balance.setId(200L); balance.setCustomerId("100");
|
||||
balance.setOverseasWarehouseId("88"); balance.setInboundCode("ORIGINAL-INBOUND");
|
||||
when(balances.selectById(200L)).thenReturn(balance);
|
||||
AtomicReference<PdaPalletOperation> op = new AtomicReference<>();
|
||||
doAnswer(invocation -> { op.set(invocation.getArgument(0)); return 1; }).when(mapper).insert(any(PdaPalletOperation.class));
|
||||
when(mapper.selectById(anyLong())).thenAnswer(invocation -> op.get());
|
||||
var result = service.relabelDisassemble(identity(), new PalletOperationRequests.RelabelDisassemble(
|
||||
"qty-1", "RL-1", new PalletOperationRequests.PalletExpectation("SOURCE", 1),
|
||||
new PalletOperationRequests.PalletExpectation("TARGET", 2), List.of("CARTON-A"), "quantity",
|
||||
new PalletOperationRequests.MoveLine(100L, 1L, 4L)));
|
||||
assertEquals("COMPLETED", result.status());
|
||||
assertEquals(1L, anchor.getHoldPackages()); // Other order's hold is not moved.
|
||||
assertEquals(1L, anchor.getAvailablePackages());
|
||||
assertEquals(4L, actual.getAvailablePackages()); assertEquals(0L, actual.getHoldPackages());
|
||||
assertEquals(1L, target.get().getHoldPackages()); assertEquals(200L, target.get().getBalanceId());
|
||||
assertEquals(7L, anchor.getAvailablePackages() + anchor.getHoldPackages() + actual.getAvailablePackages()
|
||||
+ actual.getHoldPackages() + target.get().getHoldPackages());
|
||||
verify(relabelPalletMutations).moveSelectedItems(eq(app), argThat(values -> values.get(100L).equals(List.of(item))), anyMap());
|
||||
ArgumentCaptor<InventoryLedger> entries = ArgumentCaptor.forClass(InventoryLedger.class);
|
||||
verify(ledgers, times(4)).insert(entries.capture());
|
||||
assertTrue(entries.getAllValues().stream().allMatch(entry -> "ORIGINAL-INBOUND".equals(entry.getInboundCode())));
|
||||
verify(balances, never()).updateById(any(InventoryBalance.class));
|
||||
}
|
||||
|
||||
@Test void boundMarksSurviveReloadButDoNotBlockANewReworkRound() {
|
||||
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
|
||||
var histories = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelHistoryMapper.class);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkTasks", tasks);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkHistory", histories);
|
||||
RelabelApplication app = new RelabelApplication(); app.setId(600L); app.setCustomerId("100");
|
||||
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask(); task.setId(900L);
|
||||
when(tasks.find("100", 600L)).thenReturn(task);
|
||||
var history = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory();
|
||||
history.setDetailJson("{\"round\":\"INITIAL\",\"cartonMarks\":[\"CARTON-A\"]}");
|
||||
when(histories.selectList(any())).thenReturn(List.of(history));
|
||||
assertEquals(java.util.Set.of("CARTON-A"), ReflectionTestUtils.invokeMethod(service, "boundRelabelMarks", app));
|
||||
task.setReviewedAt(LocalDateTime.of(2026, 9, 15, 12, 0));
|
||||
assertEquals(java.util.Set.of(), ReflectionTestUtils.invokeMethod(service, "boundRelabelMarks", app));
|
||||
}
|
||||
|
||||
@Test void createsPalletBeforeCustomerConfirmationOnlyForClaimingOperator() {
|
||||
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
|
||||
ReflectionTestUtils.setField(service, "relabelWorkTasks", tasks);
|
||||
RelabelApplication app = new RelabelApplication(); app.setId(600L); app.setRelabelNo("RL-1");
|
||||
app.setCustomerId("100"); app.setOverseasWarehouseId("88"); app.setStatus("PROCESSING");
|
||||
when(relabelApplications.findAnyByRelabelNo("RL-1")).thenReturn(app);
|
||||
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask(); task.setStatus("PROCESSING"); task.setOperatorKey("7");
|
||||
when(tasks.find("100", 600L)).thenReturn(task);
|
||||
when(physical.ensureRelabelPallet(88L, "RL-1:before-confirm")).thenReturn(pallet(30L, "NEW", 88L, 0));
|
||||
assertEquals("NEW", service.createRelabelPallet(identity(), new PalletOperationRequests.NewRelabelPallet("RL-1", "before-confirm")).palletCode());
|
||||
task.setOperatorKey("other");
|
||||
assertThrows(ResponseStatusException.class, () -> service.createRelabelPallet(identity(), new PalletOperationRequests.NewRelabelPallet("RL-1", "different")));
|
||||
}
|
||||
|
||||
private static PdaWarehouseIdentity identity() { return new PdaWarehouseIdentity("7", "picker", 88L); }
|
||||
private static PalletPhysicalGateway.PalletReference pallet(long id, String code, long warehouse, int version) {
|
||||
return new PalletPhysicalGateway.PalletReference(id, code, warehouse, 1000L + id,
|
||||
|
||||
Reference in New Issue
Block a user