贴标申请,仓储转运

This commit is contained in:
2026-10-12 18:01:16 +08:00
parent c06e788b0f
commit 46507e41c6
17 changed files with 214 additions and 16 deletions
@@ -92,6 +92,84 @@ class PdaPalletOperationServiceTest {
service.configureTransactions(new NoOpTransactionManager());
}
@Test void returnPalletTotalsFollowCurrentBindingsWithoutCountingRetriesTwice() {
var first = new ReturnInventoryCarton(); first.setWeight(new java.math.BigDecimal("5"));
first.setLength(new java.math.BigDecimal("30")); first.setWidth(new java.math.BigDecimal("20"));
first.setHeight(new java.math.BigDecimal("20")); first.setDestinationWarehouseCode("SCK8");
var second = new ReturnInventoryCarton(); second.setWeight(new java.math.BigDecimal("11"));
second.setLength(new java.math.BigDecimal("40")); second.setWidth(new java.math.BigDecimal("30"));
second.setHeight(new java.math.BigDecimal("30")); second.setDestinationWarehouseCode("SCK8");
var pallet = new PalletPhysicalGateway.PalletReference(10L, "TARGET", 88L, null, "OCCUPIED", "SCK8", 2);
when(returnCartons.palletCartons("88", "TARGET")).thenReturn(List.of(first), List.of(first, second), List.of(first, second), List.of(first));
var before = (com.baiyue.lastleg.palletops.dto.PalletOperationResponses.PalletContent) ReflectionTestUtils.invokeMethod(service, "content", 88L, pallet);
assertEquals(0, before.grossWeightKg().compareTo(new java.math.BigDecimal("5")));
var added = (com.baiyue.lastleg.palletops.dto.PalletOperationResponses.PalletContent) ReflectionTestUtils.invokeMethod(service, "content", 88L, pallet);
assertEquals(2, added.totalPackages());
assertEquals(0, added.grossWeightKg().compareTo(new java.math.BigDecimal("16")));
assertEquals(0, added.volumeCbm().compareTo(new java.math.BigDecimal("0.048")));
assertEquals(added, ReflectionTestUtils.invokeMethod(service, "content", 88L, pallet));
assertEquals(before, ReflectionTestUtils.invokeMethod(service, "content", 88L, pallet));
}
@Test void returnRebindingRequiresCurrentRoundBindingAndAddsToExistingPallet() {
var workTasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
var workHistory = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelHistoryMapper.class);
ReflectionTestUtils.setField(service, "relabelWorkTasks", workTasks);
ReflectionTestUtils.setField(service, "relabelWorkHistory", workHistory);
var app = new RelabelApplication(); app.setId(600L); app.setCustomerId("100");
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask(); task.setId(700L);
when(workTasks.find("100", 600L)).thenReturn(task);
var item = new RelabelItem(); item.setReturnCartonId(801L); item.setCartonMark("BOX-1");
item.setDestinationFbaWarehouseCode("SCK8"); item.setNotifiedPackageCount(1);
var box = new ReturnInventoryCarton(); box.setId(801L); box.setCustomerId("100");
box.setPalletCode("SOURCE"); box.setRelabelApplicationId(600L); box.setStatus("RELABEL_PENDING");
box.setTotalQuantity(10L); box.setWeight(new java.math.BigDecimal("11"));
box.setLength(new java.math.BigDecimal("40")); box.setWidth(new java.math.BigDecimal("30"));
box.setHeight(new java.math.BigDecimal("30")); box.setDestinationWarehouseCode("SCK8");
var existing = new ReturnInventoryCarton(); existing.setWeight(new java.math.BigDecimal("5"));
existing.setLength(new java.math.BigDecimal("30")); existing.setWidth(new java.math.BigDecimal("20"));
existing.setHeight(new java.math.BigDecimal("20")); existing.setDestinationWarehouseCode("SCK8");
var source = new PalletPhysicalGateway.PalletReference(20L, "SOURCE", 88L, 1020L, "OCCUPIED", "SCK8", 1);
var target = new PalletPhysicalGateway.PalletReference(10L, "TARGET", 88L, 1010L, "OCCUPIED", "SCK8", 2);
when(returnCartons.lockId(801L)).thenReturn(box);
when(returnCartons.palletCartons("88", "TARGET")).thenAnswer(call ->
"TARGET".equals(box.getPalletCode()) ? List.of(existing, box) : List.of(existing));
var request = new PalletOperationRequests.RelabelDisassemble("rebind-current", "RL-1",
new PalletOperationRequests.PalletExpectation("SOURCE", 1),
new PalletOperationRequests.PalletExpectation("TARGET", 2), List.of("BOX-1"), "rebind");
assertThrows(ResponseStatusException.class, () -> ReflectionTestUtils.invokeMethod(service,
"bindReturnRelabelPallet", identity(), app, List.of(item), source, target, request));
verifyNoInteractions(physical);
var binding = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory();
binding.setDetailJson("{\"round\":\"INITIAL\",\"cartonMarks\":[\"BOX-1\"]}");
when(workHistory.selectList(any())).thenReturn(List.of(binding));
task.setReviewedAt(LocalDateTime.of(2026, 10, 12, 12, 0));
assertThrows(ResponseStatusException.class, () -> ReflectionTestUtils.invokeMethod(service,
"bindReturnRelabelPallet", identity(), app, List.of(item), source, target, request));
task.setReviewedAt(null);
when(physical.resolve("SOURCE")).thenReturn(source);
when(physical.resolve("TARGET")).thenReturn(target);
var result = (com.baiyue.lastleg.palletops.dto.PalletOperationResponses.Operation)
ReflectionTestUtils.invokeMethod(service, "bindReturnRelabelPallet", identity(), app,
List.of(item), source, target, request);
assertEquals("TARGET", box.getPalletCode());
assertEquals(0, result.pallets().get(0).totalPackages());
assertEquals(2, result.pallets().get(1).totalPackages());
assertEquals(0, result.pallets().get(1).grossWeightKg().compareTo(new java.math.BigDecimal("16")));
assertEquals(0, result.pallets().get(1).volumeCbm().compareTo(new java.math.BigDecimal("0.048")));
verify(returnCartons).updateById(box);
verify(workHistory).insert(any(com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory.class));
}
@Test void missingCartonMeasurementDoesNotBecomeZeroWeight() {
var box = new ReturnInventoryCarton(); box.setWeight(new java.math.BigDecimal("5"));
when(returnCartons.palletCartons("88", "TARGET")).thenReturn(List.of(box));
var pallet = new PalletPhysicalGateway.PalletReference(10L, "TARGET", 88L, null, "OCCUPIED", "SCK8", 2);
var result = (com.baiyue.lastleg.palletops.dto.PalletOperationResponses.PalletContent) ReflectionTestUtils.invokeMethod(service, "content", 88L, pallet);
assertNull(result.volumeCbm());
assertEquals(0, result.grossWeightKg().compareTo(new java.math.BigDecimal("5")));
}
@Test void partialReturnRelabelKeepsUnlabelledRemainderOnOriginalPallet() {
RelabelApplication app = new RelabelApplication(); app.setId(600L); app.setCustomerId("100"); app.setRelabelNo("RL-1");
RelabelItem item = new RelabelItem(); item.setId(701L); item.setSkuCode("SKU-1");
@@ -82,6 +82,31 @@ class PdaRelabelServiceTest {
lenient().when(tasks.updateWithVersion(any(), anyInt())).thenReturn(1);
}
@Test
void detailDistinguishesInventoryReferenceFromRecordedReturnPallet() {
when(applications.findAnyByRelabelNo("FBR-1")).thenReturn(application);
var positions = org.mockito.Mockito.mock(com.baiyue.lastleg.inventory.mapper.InventoryPositionMapper.class);
ReflectionTestUtils.setField(service, "sourcePositions", positions);
item.setSourceInventoryPositionId(30L);
var position = new com.baiyue.lastleg.inventory.entity.InventoryPosition();
position.setPalletNo("PLT-REFERENCE");
when(positions.findTenantPosition("100", 30L)).thenReturn(position);
var ordinary = service.detail("7", 900L, "FBR-1").items().get(0);
assertEquals("PLT-REFERENCE", ordinary.sourcePalletCode());
assertEquals("INVENTORY_REFERENCE", ordinary.sourcePalletBasis());
var cartons = org.mockito.Mockito.mock(com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper.class);
ReflectionTestUtils.setField(service, "returnCartons", cartons);
item.setReturnCartonId(40L);
var carton = new com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCarton();
carton.setCustomerId("100"); carton.setPalletCode("PLT-RETURN"); carton.setTotalQuantity(20L);
when(cartons.selectById(40L)).thenReturn(carton);
var returned = service.detail("7", 900L, "FBR-1").items().get(0);
assertEquals("PLT-RETURN", returned.sourcePalletCode());
assertEquals("RETURN_CARTON", returned.sourcePalletBasis());
carton.setCustomerId("OTHER");
assertEquals(null, service.detail("7", 900L, "FBR-1").items().get(0).sourcePalletCode());
}
@Test
void candidatesUseCustomerNameOnlyFromMatchingCustomerOrder() {
var orders = org.mockito.Mockito.mock(com.baiyue.lastleg.mapper.LastlegOrderMapper.class);
@@ -454,7 +454,7 @@ class ReturnReceiptServiceTest {
stubNewReceipt(order, List.of(line), "SP-SOURCE");
var request = new PdaReturnReceiptRequests.Confirm("RT-1", null, "SKU", null,
List.of(new PdaReturnReceiptRequests.Item("SKU-A", 1)), "parcel-key",
"PARCEL", null, null, null, null, null, null);
"PARCEL", null, java.math.BigDecimal.ONE, java.math.BigDecimal.ONE, java.math.BigDecimal.ONE, java.math.BigDecimal.ONE, null, true);
var result = service.confirm(identity, request);
var capture = ArgumentCaptor.forClass(ReturnReceipt.class);
verify(receipts).insert(capture.capture());
@@ -611,6 +611,6 @@ class ReturnReceiptServiceTest {
// These focused tests exercise receipt/idempotency behavior at the
// carton level. Pallet receipts have a separate multi-carton contract.
return new PdaReturnReceiptRequests.Confirm("RT-1", trackingNo, startedBy, palletCode, boxed, key,
"BOX", palletCode, null, null, null, null, 1L);
"BOX", palletCode, java.math.BigDecimal.ONE, java.math.BigDecimal.ONE, java.math.BigDecimal.ONE, java.math.BigDecimal.ONE, 1L, true);
}
}