This commit is contained in:
2026-10-15 15:42:10 +08:00
parent 095a95e64a
commit c6bd6af5ce
43 changed files with 1153 additions and 92 deletions
@@ -672,6 +672,16 @@ class DeliveryTransferServiceTest {
assertEquals(4, detail.pallets().get(0).packageCount());
}
@org.junit.jupiter.params.ParameterizedTest
@org.junit.jupiter.params.provider.ValueSource(strings = {"DISCARD_OUTBOUND", "ONE_CLICK_DROPSHIP"})
void discardDoesNotExposeHistoricInboundCodeAsLxButDropshipKeepsRealLx(String type) {
OutboundOrder outbound = outbound(301L, null, null, "OUT-301", "outbound-301");
outbound.setOutboundType(type); outbound.setLxCodes("LX-REAL-001");
when(outboundOrders.findGlobalByNo("OUT-301")).thenReturn(outbound);
var detail = service.outboundDetail("OUT-301");
assertEquals("DISCARD_OUTBOUND".equals(type) ? null : "LX-REAL-001", detail.outbound().lxCodes());
}
@Test
void dispatchOutboundStillRequiresItsDeliveryDocument() {
OutboundOrder outbound = outbound(301L, 101L, "DSP-101", "OUT-301", "dispatch-301");
@@ -3,10 +3,51 @@ package com.baiyue.lastleg.discard;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.sql.DriverManager;
import java.sql.SQLException;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonItemMapper;
import org.apache.ibatis.annotations.Update;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class CargoDiscardSchemaContractTest {
@Test
void returnCartonDeductionAllowsZeroButRejectsNegativeStock() throws Exception {
String baseline;
try (var input = getClass().getResourceAsStream("/db/lastleg.sql")) {
baseline = new String(input.readAllBytes(), StandardCharsets.UTF_8);
}
var constraint = java.util.regex.Pattern.compile(
"CONSTRAINT chk_ll_return_inventory_carton_item_quantity CHECK\\(([^)]+)\\)")
.matcher(baseline);
assertTrue(constraint.find());
String deduction = ReturnInventoryCartonItemMapper.class.getMethod("deduct", long.class, long.class)
.getAnnotation(Update.class).value()[0]
.replace("#{quantity}", "?").replace("#{id}", "?");
try (var connection = DriverManager.getConnection("jdbc:h2:mem:discard_zero_quantity;MODE=MySQL")) {
try (var statement = connection.createStatement()) {
statement.execute("CREATE TABLE ll_return_inventory_carton_item (id BIGINT PRIMARY KEY, "
+ "quantity BIGINT NOT NULL, CONSTRAINT chk_ll_return_inventory_carton_item_quantity CHECK("
+ constraint.group(1) + "))");
statement.execute("INSERT INTO ll_return_inventory_carton_item VALUES (1, 3)");
try (var update = connection.prepareStatement(deduction)) {
update.setLong(1, 3); update.setLong(2, 1); update.setLong(3, 3);
assertEquals(1, update.executeUpdate());
update.setLong(1, 1); update.setLong(3, 1);
assertEquals(0, update.executeUpdate());
}
try (var result = statement.executeQuery("SELECT quantity FROM ll_return_inventory_carton_item WHERE id=1")) {
assertTrue(result.next());
assertEquals(0, result.getLong(1));
}
assertThrows(SQLException.class, () -> statement.executeUpdate(
"UPDATE ll_return_inventory_carton_item SET quantity=-1 WHERE id=1"));
}
}
}
@Test
void baselineContainsDiscardApplicationReservationAndHistoryTables() throws Exception {
String sql;
@@ -15,6 +15,22 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class MerchantCargoDiscardControllerTest {
@Test
void completionUsesAuthenticatedCustomerAndIndependentPermission() throws Exception {
controller.confirmCompletion(user(100L, "MERCHANT"), "CD001");
verify(service).confirmCompletion("100", "CD001", "1");
assertThrows(ResponseStatusException.class,
() -> controller.confirmCompletion(user(0L, "PLATFORM"), "CD001"));
var guard = MerchantCargoDiscardController.class.getMethod("confirmCompletion", AuthenticatedUser.class, String.class)
.getAnnotation(org.springframework.security.access.prepost.PreAuthorize.class);
org.junit.jupiter.api.Assertions.assertEquals(
"hasAuthority('merchant:overseas-warehouse:discard:confirm')", guard.value());
org.junit.jupiter.api.Assertions.assertFalse(java.util.Arrays.stream(CargoDiscardController.class.getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(org.springframework.web.bind.annotation.PostMapping.class))
.flatMap(method -> java.util.Arrays.stream(method.getAnnotation(org.springframework.web.bind.annotation.PostMapping.class).value()))
.anyMatch(path -> path.endsWith("/complete") || path.endsWith("/confirm-completion")));
}
private final CargoDiscardService service = mock(CargoDiscardService.class);
private final MerchantCargoDiscardController controller = controller();
private final CargoDiscardRequests.Query query = new CargoDiscardRequests.Query(
@@ -43,6 +43,7 @@ class CargoDiscardOutboundServiceTest {
application = new CargoDiscardApplication(); application.setId(1L); application.setCustomerId("C1");
application.setDiscardNo("CD-TEST"); application.setOverseasWarehouseId("99");
application.setTotalPackages(5); application.setStatus("APPROVED");
application.setInboundCodes("RT-123,RK-456");
first = line(11L, 21L, 3); second = line(12L, 22L, 2);
when(items.listApplication("C1", 1L)).thenReturn(List.of(first, second));
when(cartons.listApplication("C1", 1L)).thenReturn(List.of());
@@ -63,6 +64,7 @@ class CargoDiscardOutboundServiceTest {
@Test void approvalCreatesExactlyOneDocumentAndImmutablePlannedLines() {
service.create(application, "OP"); service.create(application, "OP");
assertEquals("DISCARD_OUTBOUND", document.getOutboundType()); assertEquals("WAIT_PICK", document.getStatus());
assertNull(document.getLxCodes());
assertEquals(5, document.getPackageCount()); assertEquals(2, document.getPalletCount());
assertTrue(service.outboundNo(application).startsWith("OB-"));
assertEquals(List.of(3, 2), snapshots.stream().map(OutboundPalletItem::getPackageCount).toList());
@@ -82,6 +84,13 @@ class CargoDiscardOutboundServiceTest {
service.create(application, "OP"); application.setStatus("CANCELLED"); service.sync(application);
assertEquals("CANCELLED", document.getStatus()); assertTrue(snapshots.stream().allMatch(s -> "CANCELLED".equals(s.getStatus())));
}
@Test void syncClearsHistoricallyMislabelledInboundCodesWithoutChangingSourceSnapshots() {
first.setInboundCode("RK-456");
service.create(application, "OP"); document.setLxCodes("RT-123,RK-456");
service.sync(application);
assertNull(document.getLxCodes()); assertEquals("RK-456", snapshots.get(0).getInboundCode());
assertEquals("RT-123,RK-456", application.getInboundCodes());
}
@Test void returnSourceKeepsRealCartonMarkWithoutInventingPalletNumber() {
first.setReturnCartonId(31L); first.setSourceType("RETURN_CARTON");
var carton = new ReturnInventoryCarton(); carton.setId(31L); carton.setCustomerId("C1");
@@ -47,6 +47,36 @@ import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class CargoDiscardServiceTest {
@Test
void customerConfirmationClosesPdaCompletedApplicationOnceWithoutAnotherDeduction() {
CargoDiscardApplication application = new CargoDiscardApplication();
application.setId(1001L); application.setCustomerId("100"); application.setDiscardNo("CD001");
application.setTotalPackages(1); application.setOverseasWarehouseName("测试仓"); application.setStatus(CargoDiscardService.PDA_COMPLETED);
storedApplication.set(application);
when(applications.lockNo("100", "CD001")).thenReturn(application);
service.confirmCompletion("100", "CD001", "CUSTOMER");
var confirmedAt = application.getCustomerConfirmedAt();
org.junit.jupiter.api.Assertions.assertNotNull(confirmedAt);
assertEquals(CargoDiscardService.COMPLETED, application.getStatus());
assertEquals("客户确认废弃完成", storedHistories.get(0).getRemark());
service.confirmCompletion("100", "CD001", "CUSTOMER");
assertEquals(confirmedAt, application.getCustomerConfirmedAt());
assertEquals(1, storedHistories.size());
verify(applications, times(1)).updateById(application);
org.mockito.Mockito.verifyNoInteractions(adjustments, inventory, returnCartonItems);
}
@org.junit.jupiter.params.ParameterizedTest
@org.junit.jupiter.params.provider.ValueSource(strings = {"PENDING_REVIEW", "APPROVED", "REJECTED", "CANCELLED"})
void customerCannotConfirmBeforePdaCompletion(String status) {
CargoDiscardApplication application = new CargoDiscardApplication(); application.setStatus(status);
when(applications.lockNo("100", "CD001")).thenReturn(application);
org.junit.jupiter.api.Assertions.assertThrows(org.springframework.web.server.ResponseStatusException.class,
() -> service.confirmCompletion("100", "CD001", "CUSTOMER"));
verify(applications, never()).updateById(any(CargoDiscardApplication.class));
}
@Mock CargoDiscardApplicationMapper applications;
@Mock CargoDiscardItemMapper items;
@Mock CargoDiscardCartonMapper discardCartons;
@@ -57,6 +87,7 @@ class CargoDiscardServiceTest {
@Mock LastlegOrderStatusHistoryMapper orderHistories;
@Mock ReturnInventoryCartonMapper returnCartons;
@Mock ReturnInventoryCartonItemMapper returnCartonItems;
@Mock com.baiyue.lastleg.client.DomesticWarehouseDirectoryClient warehouseDirectory;
private CargoDiscardService service;
private final CargoDiscardOutboundService outboundService = org.mockito.Mockito.mock(CargoDiscardOutboundService.class);
@@ -68,6 +99,9 @@ class CargoDiscardServiceTest {
@BeforeEach
void setUp() {
service = new CargoDiscardService();
ReflectionTestUtils.setField(service, "warehouseDirectory", warehouseDirectory);
lenient().when(warehouseDirectory.receivingWarehouses(any())).thenReturn(com.baiyue.common.core.api.ApiResponse.success(List.of(
new com.baiyue.lastleg.client.DomesticWarehouseDirectoryClient.ReceivingWarehouse(99L, "LAX", "洛杉矶仓", "US", "ACTIVE"))));
ReflectionTestUtils.setField(service, "outboundService", outboundService);
ReflectionTestUtils.setField(service, "stockService", org.mockito.Mockito.mock(CargoDiscardStockService.class));
ReflectionTestUtils.setField(service, "photoService", org.mockito.Mockito.mock(CargoDiscardPhotoService.class));
@@ -97,6 +131,7 @@ class CargoDiscardServiceTest {
@Test
void createReservesExactSkuCartonsWithoutDeductingInventory() {
LastlegOrder order = order();
order.setOverseasWarehouseId("99"); order.setOverseasWarehouseName(null);
DropshipSkuInventory sku = skuInventory();
when(orders.selectById(101L)).thenReturn(order);
when(inventory.countAvailable("100", 101L, "SKU-1")).thenReturn(2L);
@@ -109,6 +144,7 @@ class CargoDiscardServiceTest {
List.of(new CargoDiscardRequests.Item(101L, null, "SKU-1", 2)), "discard-create-1", "damaged"));
assertEquals(CargoDiscardService.PENDING_REVIEW, detail.summary().status());
assertEquals("洛杉矶仓", storedApplication.get().getOverseasWarehouseName());
assertEquals(2, detail.summary().totalPackages());
assertEquals(new BigDecimal("10.00"), detail.summary().totalFee());
assertEquals(2, storedLinks.size());
@@ -116,6 +152,14 @@ class CargoDiscardServiceTest {
verify(inventory, never()).deductSkuInventory(any(), anyLong(), anyInt());
}
@Test void historicalDiscardDetailResolvesMissingWarehouseNameByOperatingWarehouseId() {
CargoDiscardApplication application = pendingApplication();
application.setOverseasWarehouseId("99"); application.setOverseasWarehouseName(null);
storedApplication.set(application);
assertEquals("洛杉矶仓", service.detail("100", application.getDiscardNo()).summary().overseasWarehouseName());
verify(applications, never()).updateById(any(CargoDiscardApplication.class));
}
@Test void selectedBoxesCreatePartialApplicationWithoutReservingUnselectedStock() {
when(orders.selectById(101L)).thenReturn(order());
@@ -159,7 +203,7 @@ class CargoDiscardServiceTest {
ReturnInventoryCarton carton = new ReturnInventoryCarton();
carton.setId(901L);
carton.setCustomerId("100");
carton.setOverseasWarehouseId("WH-1");
carton.setOverseasWarehouseId("99");
carton.setSourceReturnNo("RT-20260928-001");
carton.setCartonMark("RC-LAX-001");
carton.setStatus("AVAILABLE");
@@ -176,6 +220,7 @@ class CargoDiscardServiceTest {
assertEquals(1, result.size());
assertEquals("RETURN_CARTON", result.get(0).sourceType());
assertEquals("洛杉矶仓", result.get(0).overseasWarehouseName());
assertEquals(901L, result.get(0).returnCartonId());
assertEquals("RC-LAX-001", result.get(0).cartonMark());
assertEquals(4, result.get(0).availablePackages());
@@ -18,6 +18,16 @@ class WarehouseTransferCargoValidationTest {
}
}
@Test
void skuUnitsAndExpectedCartonsAreIndependent() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
var validator = factory.getValidator();
assertTrue(validator.validate(new WarehouseTransferRequests.Item("SKU-A", "货物", 3, null, 120L)).isEmpty());
assertTrue(!validator.validate(new WarehouseTransferRequests.Item("SKU-A", "货物", 3, null, 0L)).isEmpty());
assertTrue(!validator.validate(new WarehouseTransferRequests.Item("SKU-A", "货物", 0, null, 120L)).isEmpty());
}
}
@Test
void cartonRelabelAllowsOriginalSkuToBeOmitted() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
@@ -0,0 +1,108 @@
package com.baiyue.lastleg.transfer.service;
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
import com.baiyue.lastleg.transfer.entity.*;
import com.baiyue.lastleg.transfer.mapper.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.server.ResponseStatusException;
import java.math.BigDecimal;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.*;
class WarehouseTransferCartonCountTest {
WarehouseTransferService service;
WarehouseTransferOrderMapper orders = mock(WarehouseTransferOrderMapper.class);
WarehouseTransferCartonMapper cartons = mock(WarehouseTransferCartonMapper.class);
WarehouseTransferItemMapper items = mock(WarehouseTransferItemMapper.class);
WarehouseTransferPalletMapper palletMapper = mock(WarehouseTransferPalletMapper.class);
WarehouseTransferPallet pallet;
WarehouseTransferOrder order;
WarehouseTransferCarton a, b;
@BeforeEach void setup() {
service = spy(new WarehouseTransferService());
ReflectionTestUtils.setField(service, "transfers", orders);
ReflectionTestUtils.setField(service, "transferCartons", cartons);
ReflectionTestUtils.setField(service, "transferItems", items);
ReflectionTestUtils.setField(service, "transferPallets", palletMapper);
pallet = new WarehouseTransferPallet(); pallet.setId(200L); pallet.setStatus("GENERATED"); pallet.setWarehousePalletId(900L);
when(palletMapper.listOrder("C1", 1L)).thenReturn(List.of(pallet));
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper());
doReturn(null).when(service).detail(anyString(), anyString());
order = new WarehouseTransferOrder(); order.setId(1L); order.setCustomerId("C1"); order.setTransferNo("WT1"); order.setStatus("WAIT_PDA_RECEIVING"); order.setPackageCount(2);
a = box("BOX1", 10L); b = box("BOX2", 11L);
when(orders.lockForPda("WT1", "77")).thenReturn(order);
when(cartons.listOrder("C1", 1L)).thenReturn(List.of(a,b));
var ia = new WarehouseTransferItem(); ia.setId(10L); ia.setSkuCode("A");
var ib = new WarehouseTransferItem(); ib.setId(11L); ib.setSkuCode("B");
when(items.selectList(any())).thenReturn(List.of(ia,ib));
}
WarehouseTransferCarton box(String mark, long item) { var box = new WarehouseTransferCarton(); box.setCartonMark(mark); box.setCartonIndex((int)item); box.setTransferItemId(item); return box; }
WarehouseTransferRequests.CountCarton input(String mark, String sku, long quantity) { return new WarehouseTransferRequests.CountCarton(mark, null, 200L, new BigDecimal("20"),new BigDecimal("30"),new BigDecimal("40"),new BigDecimal("2.5"),sku,quantity); }
WarehouseTransferRequests.CountCartons request(String key, WarehouseTransferRequests.CountCarton... rows) { return new WarehouseTransferRequests.CountCartons(key,List.of(rows),null); }
@Test void multiSkuBoxesPersistDimensionsPiecesAndReplayWithoutWriting() {
var request = request("K1",input("BOX1","A",12),input("BOX2","B",7));
service.countCartons("OP1",77L,"WT1",request);
assertEquals(12L,a.getCountedQuantity()); assertEquals(7L,b.getCountedQuantity()); assertNotNull(a.getCountedAt()); assertEquals("OP1",a.getCountedBy()); assertEquals(new BigDecimal("2.5"),b.getGrossWeightKg());
assertEquals(200L,a.getTransferPalletId()); assertEquals(2,pallet.getCartonCount());
assertEquals(new BigDecimal("0.048000"),pallet.getVolumeCbm()); assertEquals(new BigDecimal("5.0"),pallet.getGrossWeightKg());
clearInvocations(cartons); order.setStatus("WAIT_CUSTOMER_CONFIRMATION");
service.countCartons("OP1",77L,"WT1",request);
verify(cartons,never()).updateById(any(WarehouseTransferCarton.class));
assertThrows(ResponseStatusException.class,()->service.countCartons("OP1",77L,"WT1",request("K1",input("BOX1","A",13),input("BOX2","B",7))));
}
@Test void missingDuplicateForeignSkuAndInvalidQuantityRejectBeforeWrites() {
var invalid = List.of(request("K",input("BOX1","A",1)),request("K",input("BOX1","A",1),input("BOX1","A",2)),request("K",input("OTHER","A",1),input("BOX2","B",2)),request("K",input("BOX1","B",1),input("BOX2","B",2)),request("K",input("BOX1","A",0),input("BOX2","B",2)));
for(var request:invalid) assertThrows(ResponseStatusException.class,()->service.countCartons("OP1",77L,"WT1",request));
verify(cartons,never()).updateById(any(WarehouseTransferCarton.class));
}
@Test void shortReceiptNeedsReasonAndPreservesMissingBoxFact() {
var request = new WarehouseTransferRequests.CountCartons("SHORT",List.of(input("BOX1","A",3)),"少到一箱");
service.countCartons("OP1",77L,"WT1",request);
assertEquals("COUNTED",a.getStatus()); assertEquals("NOT_RECEIVED",b.getStatus());
assertEquals("少到一箱",b.getDiscrepancyReason()); assertNull(b.getCountedQuantity());
}
@Test void extraReceiptGeneratesOwnedBoxAndReconcilesToDeclaredSku() {
var extra = new WarehouseTransferRequests.CountCarton(null,11L,200L,new BigDecimal("10"),new BigDecimal("20"),new BigDecimal("30"),BigDecimal.ONE,"B",4);
service.countCartons("OP1",77L,"WT1",new WarehouseTransferRequests.CountCartons("EXTRA",List.of(input("BOX1","A",1),input("BOX2","B",2),extra),"多到一箱"));
var captured = org.mockito.ArgumentCaptor.forClass(WarehouseTransferCarton.class);
verify(cartons).insert(captured.capture());
assertEquals("WT1#EX-12",captured.getValue().getCartonMark()); assertEquals("C1",captured.getValue().getCustomerId()); assertEquals(4L,captured.getValue().getCountedQuantity());
}
@Test void cartonsRequireGeneratedPalletOwnedByThisOrder() {
when(palletMapper.listOrder("C1",1L)).thenReturn(List.of());
assertThrows(ResponseStatusException.class,()->service.countCartons("OP1",77L,"WT1",request("K",input("BOX1","A",1),input("BOX2","B",2))));
verify(cartons,never()).updateById(any(WarehouseTransferCarton.class));
when(palletMapper.listOrder("C1",1L)).thenReturn(List.of(pallet)); pallet.setStatus("DRAFT");
assertThrows(ResponseStatusException.class,()->service.countCartons("OP1",77L,"WT1",request("K",input("BOX1","A",1),input("BOX2","B",2))));
}
@Test void multiSkuPalletCreatesOneInboundLineAllocationWithSummedBoxes() {
var plans = mock(com.baiyue.lastleg.inboundplan.mapper.InboundPlanMapper.class);
var lines = mock(com.baiyue.lastleg.inboundplan.mapper.InboundPlanLineMapper.class);
var pallets = mock(com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletMapper.class);
var allocations = mock(com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletAllocationMapper.class);
ReflectionTestUtils.setField(service,"inboundPlans",plans); ReflectionTestUtils.setField(service,"inboundPlanLines",lines);
ReflectionTestUtils.setField(service,"inboundPlanPallets",pallets); ReflectionTestUtils.setField(service,"inboundPlanAllocations",allocations);
order.setLastlegOrderId(9L); order.setInboundCode("WT1");
var plan = new com.baiyue.lastleg.inboundplan.entity.InboundPlan(); plan.setId(100L);
var line = new com.baiyue.lastleg.inboundplan.entity.InboundPlanLine(); line.setId(101L);
when(plans.findBySourceOrder("C1",9L)).thenReturn(plan); when(lines.selectOne(any())).thenReturn(line);
var pallet = new WarehouseTransferPallet(); pallet.setId(200L); pallet.setCartonCount(3); pallet.setVolumeCbm(BigDecimal.ONE); pallet.setSequenceNo(1);
var first = new WarehouseTransferPalletItem(); first.setTransferPalletId(200L); first.setTransferItemId(10L); first.setPackageCount(1);
var second = new WarehouseTransferPalletItem(); second.setTransferPalletId(200L); second.setTransferItemId(11L); second.setPackageCount(2);
ReflectionTestUtils.invokeMethod(service,"completeTransferInboundPlan","C1",order,List.of(pallet),List.of(first,second),java.time.LocalDateTime.now());
var result=org.mockito.ArgumentCaptor.forClass(com.baiyue.lastleg.inboundplan.entity.InboundPlanPalletAllocation.class);
verify(allocations,times(1)).insert(result.capture()); assertEquals(3,result.getValue().getPickedPackageCount()); assertEquals(3,result.getValue().getCountedPackageCount());
}
@Test void otherWarehouseCannotReadOrWriteAndCompletedCountsCannotBeOverwritten() {
assertThrows(ResponseStatusException.class,()->service.countCartons("OP1",88L,"WT1",request("K",input("BOX1","A",1))));
service.countCartons("OP1",77L,"WT1",request("K",input("BOX1","A",1),input("BOX2","B",2)));
clearInvocations(cartons);
assertThrows(ResponseStatusException.class,()->service.countCartons("OP2",77L,"WT1",request("NEW",input("BOX1","A",9),input("BOX2","B",2))));
verify(cartons,never()).updateById(any(WarehouseTransferCarton.class));
}
}
@@ -48,19 +48,17 @@ class WarehouseTransferPalletAllocationTest {
}
@Test
void persistedOverReceiptUsesTheSameStableAllocationRule() {
WarehouseTransferPallet first = persistedPallet(4);
WarehouseTransferPallet second = persistedPallet(3);
var allocations = WarehouseTransferService.derivePersistedPalletAllocations(
List.of(item(11L, 3), item(12L, 2)), List.of(first, second));
assertEquals(7, allocations.stream().mapToInt(value -> value.packageCount()).sum());
assertEquals(3, allocations.stream().filter(value -> value.transferItemId() == 11L)
.mapToInt(value -> value.packageCount()).sum());
assertEquals(4, allocations.stream().filter(value -> value.transferItemId() == 12L)
.mapToInt(value -> value.packageCount()).sum());
assertEquals(List.of(0, 0, 1), allocations.stream().map(value -> value.palletIndex()).toList());
void countedBoxesDetermineSkuPlacementRatherThanDeclarationOrder() {
WarehouseTransferPallet first = persistedPallet(2); first.setId(100L);
WarehouseTransferPallet second = persistedPallet(1); second.setId(200L);
var a = new com.baiyue.lastleg.transfer.entity.WarehouseTransferCarton(); a.setTransferItemId(12L); a.setTransferPalletId(100L);
var b = new com.baiyue.lastleg.transfer.entity.WarehouseTransferCarton(); b.setTransferItemId(12L); b.setTransferPalletId(100L);
var c = new com.baiyue.lastleg.transfer.entity.WarehouseTransferCarton(); c.setTransferItemId(11L); c.setTransferPalletId(200L);
var allocations = WarehouseTransferService.deriveCountedPalletAllocations(List.of(a,b,c),List.of(first,second));
assertEquals(List.of(new WarehouseTransferService.DerivedPalletAllocation(0,12L,2),new WarehouseTransferService.DerivedPalletAllocation(1,11L,1)),allocations);
c.setTransferPalletId(999L);
org.junit.jupiter.api.Assertions.assertThrows(org.springframework.web.server.ResponseStatusException.class,
() -> WarehouseTransferService.deriveCountedPalletAllocations(List.of(a,b,c),List.of(first,second)));
}
@Test
@@ -322,6 +322,10 @@ class WarehouseTransferServiceTest {
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.WAIT_PDA_RECEIVING);
transfer.setOperatingWarehouseId("77");
WarehouseTransferPallet pallet = measuredPallet("GENERATED");
var counted = java.util.stream.IntStream.rangeClosed(1, 5).mapToObj(index -> {
var box = new WarehouseTransferCarton(); box.setStatus("COUNTED"); box.setCountedAt(LocalDateTime.now()); return box;
}).toList();
when(transferCartons.listOrder("TENANT-A", transfer.getId())).thenReturn(counted);
when(transfers.lockForPda("WTR-1", "77")).thenReturn(transfer);
when(transferItems.selectList(any())).thenReturn(List.of(transferItem(51L, "SKU-1", 5)));
WarehouseTransferMeasurementPhoto photo = new WarehouseTransferMeasurementPhoto();
@@ -366,6 +370,10 @@ class WarehouseTransferServiceTest {
new InventoryCommandResponse(1L, "STOCK_IN", 801L, 901L, 5, 0, 0, 0, false, false));
when(sourceOrders.selectList(any())).thenReturn(List.of());
var counted = java.util.stream.IntStream.rangeClosed(1, 5).mapToObj(index -> {
var box = new WarehouseTransferCarton(); box.setTransferPalletId(pallet.getId()); box.setTransferItemId(item.getId()); box.setCartonIndex(index); box.setTotalCartons(5); box.setCartonMark("BOX-" + index); box.setStatus("COUNTED"); box.setCountedAt(LocalDateTime.now()); return box;
}).toList();
when(transferCartons.listOrder("TENANT-A", transfer.getId())).thenReturn(counted);
var result = service.palletize("OP-1", 77L, "WTR-1",
new WarehouseTransferRequests.Palletize("DONE-1", List.of(9001L)));