贴标申请,仓储转运

This commit is contained in:
2026-09-20 15:06:17 +08:00
parent a7d458cddd
commit 02844da360
56 changed files with 2121 additions and 111 deletions
@@ -117,4 +117,20 @@ class RelabelContractTest {
assertTrue(service.contains("requiresOutbound && (!StringUtils.hasText(deliveryMethod)"
+ " || !DELIVERY_METHODS.contains(deliveryMethod))"));
}
@Test
void returnRelabelReviewStatusIsProjectedWithoutLosingPendingOrRejectedState() throws Exception {
String service = Files.readString(Path.of("src/main/java/com/baiyue/lastleg/relabel/service/RelabelApplicationService.java"),
StandardCharsets.UTF_8);
assertTrue(service.contains("Set.of(PENDING_REVIEW, PENDING_PROCESSING, \"PROCESSING\", \"REJECTED\", \"CANCELLED\")"));
assertTrue(service.contains("return workflowStatus;"));
}
@Test
void returnCartonConstraintsAllowRelabelReservationWithPositiveInventory() throws Exception {
String baseline = Files.readString(Path.of("src/main/resources/db/lastleg.sql"), StandardCharsets.UTF_8)
.replaceAll("\\s+", "").toUpperCase();
assertTrue(baseline.contains("STATUSIN('AVAILABLE','RELABEL_PENDING','OUTBOUNDED')ANDSKU_TYPES>0ANDTOTAL_QUANTITY>0"));
assertTrue(baseline.contains("STATUSIN('AVAILABLE','RELABEL_PENDING','MERGED','OUTBOUNDED')"));
}
}
@@ -264,6 +264,73 @@ class PdaRelabelServiceTest {
verify(unitFacts, never()).insert(any(PdaRelabelUnitFact.class));
}
@Test
void returnSkuTotalCompletesOneSkuOnceAndAllocatesAcrossSourcePalletItems() {
application.setStatus("PROCESSING"); application.setNotifiedPackageCount(100);
item.setOperationType("RETURN_BULK_SKU_LABEL"); item.setSkuCode("sku-fba100");
item.setNotifiedPackageCount(50); item.setCartonMark("PALLET-A");
RelabelItem second = item(); second.setId(11L); second.setOperationType("RETURN_BULK_SKU_LABEL");
second.setSkuCode("sku-fba100"); second.setNotifiedPackageCount(50); second.setCartonMark("PALLET-B");
PdaRelabelTask task = task("PROCESSING", 0); task.setExpectedPackages(100);
when(applications.lockAnyByRelabelNo("FBR-1")).thenReturn(application);
when(tasks.lock("100", 1L)).thenReturn(task);
when(items.selectList(any())).thenReturn(List.of(item, second));
var result = service.completeReturnSkuTotal("7", "picker", 900L, "FBR-1",
new PdaRelabelRequests.BulkSkuTotal("sku-fba100", 100, 0, "sku-total-1"));
assertEquals(100, result.relabelledPackages());
assertEquals(2, persistedFacts.size());
assertEquals(List.of(50, 50), persistedFacts.stream().map(PdaRelabelUnitFact::getQuantity).toList());
assertEquals(List.of(10L, 11L), persistedFacts.stream().map(PdaRelabelUnitFact::getItemId).toList());
assertTrue(persistedFacts.stream().allMatch(fact -> fact.getOldLabel() == null));
assertEquals(1, result.version());
}
@Test
void multiSkuPartialReturnRelabelRequiresBothSkuTotalsBeforeCompletion() {
verifyMultiSkuReturnCompletion(30, 15);
}
@Test
void multiSkuFullReturnRelabelRequiresBothSkuTotalsBeforeCompletion() {
verifyMultiSkuReturnCompletion(50, 40);
}
private void verifyMultiSkuReturnCompletion(int firstQuantity, int secondQuantity) {
application.setStatus("PROCESSING");
application.setNotifiedPackageCount(firstQuantity + secondQuantity);
item.setOperationType("RETURN_BULK_SKU_LABEL"); item.setSkuCode("SKU-A");
item.setNotifiedPackageCount(firstQuantity); item.setCartonMark("RC-A");
RelabelItem second = item(); second.setId(11L);
second.setOperationType("RETURN_BULK_SKU_LABEL"); second.setSkuCode("SKU-B");
second.setNotifiedPackageCount(secondQuantity); second.setCartonMark("RC-B");
PdaRelabelTask task = task("PROCESSING", 0);
task.setExpectedPackages(firstQuantity + secondQuantity);
when(applications.lockAnyByRelabelNo("FBR-1")).thenReturn(application);
when(tasks.lock("100", 1L)).thenReturn(task);
when(items.selectList(any())).thenReturn(List.of(item, second));
var first = service.completeReturnSkuTotal("7", "picker", 900L, "FBR-1",
new PdaRelabelRequests.BulkSkuTotal("SKU-A", firstQuantity, 0, "multi-a"));
assertEquals(firstQuantity, first.relabelledPackages());
assertThrows(ResponseStatusException.class, () -> service.complete("7", "picker", 900L, "FBR-1",
new PdaRelabelRequests.Complete(List.of(501L), 1, "multi-early", null)));
assertThrows(ResponseStatusException.class, () -> service.completeReturnSkuTotal("7", "picker", 900L, "FBR-1",
new PdaRelabelRequests.BulkSkuTotal("SKU-A", 1, 1, "multi-over")));
var both = service.completeReturnSkuTotal("7", "picker", 900L, "FBR-1",
new PdaRelabelRequests.BulkSkuTotal("SKU-B", secondQuantity, 1, "multi-b"));
assertEquals(firstQuantity + secondQuantity, both.relabelledPackages());
assertEquals(List.of("SKU-A", "SKU-B"), persistedFacts.stream()
.map(fact -> fact.getItemId().equals(item.getId()) ? "SKU-A" : "SKU-B").toList());
assertEquals(List.of(firstQuantity, secondQuantity), persistedFacts.stream()
.map(PdaRelabelUnitFact::getQuantity).toList());
var completed = service.complete("7", "picker", 900L, "FBR-1",
new PdaRelabelRequests.Complete(List.of(501L), 2, "multi-complete", "multi SKU complete"));
assertEquals(PdaRelabelService.WAIT_REVIEW, completed.taskStatus());
}
@Test
void completeRequiresEveryUnitAndMovesOnlyPdaTaskToWaitReview() {
application.setStatus("PROCESSING");
@@ -30,6 +30,8 @@ import com.baiyue.lastleg.delivery.mapper.OutboundPalletItemMapper;
import com.baiyue.lastleg.delivery.mapper.OutboundPdaTaskMapper;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferOrderMapper;
import com.baiyue.lastleg.returnreceipt.entity.ReturnOrder;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnOrderMapper;
import com.baiyue.lastleg.financefee.entity.OverseasFeeSource;
import com.baiyue.lastleg.financefee.service.OverseasFeeSourceService;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -75,6 +77,7 @@ class RelabelApplicationServiceTest {
@Mock OutboundPdaTaskMapper outboundTasks;
@Mock WarehouseTransferOrderMapper warehouseTransfers;
@Mock OverseasFeeSourceService feeSources;
@Mock ReturnOrderMapper returnOrders;
@Mock com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper pdaTasks;
@Spy LastlegOrderNoGenerator orderNoGenerator = new LastlegOrderNoGenerator();
@@ -103,6 +106,7 @@ class RelabelApplicationServiceTest {
ReflectionTestUtils.setField(service, "outboundItems", outboundItems);
ReflectionTestUtils.setField(service, "outboundTasks", outboundTasks);
ReflectionTestUtils.setField(service, "warehouseTransfers", warehouseTransfers);
ReflectionTestUtils.setField(service, "returnOrders", returnOrders);
ReflectionTestUtils.setField(service, "objectMapper", mapper());
lenient().when(walletCommands.publish(any(), any(Long.class), any(), any(), any(), any(), any(Long.class))).thenReturn("wallet-event-1");
lenient().when(inventoryPositions.findTenantPosition(any(), any())).thenAnswer(invocation -> {
@@ -411,6 +415,10 @@ class RelabelApplicationServiceTest {
when(items.selectList(any())).thenReturn(List.of(item(31L, application.getId(), "SKU-A", 1, 1)));
when(histories.selectList(any())).thenReturn(List.of());
when(orders.selectById(21L)).thenReturn(order);
ReturnOrder returnOrder = new ReturnOrder();
returnOrder.setId(41L); returnOrder.setCustomerId("10001");
returnOrder.setRelabelApplicationId(application.getId()); returnOrder.setRelabelStatus("PROCESSING");
when(returnOrders.selectOne(any())).thenReturn(returnOrder);
service.changeStatus("10001", "FBR-REVIEW", "operator-2",
new RelabelRequests.ChangeStatus(RelabelApplicationService.CUSTOMER_CONFIRM_PENDING, "submitted"));
@@ -419,6 +427,8 @@ class RelabelApplicationServiceTest {
assertEquals("WAIT_CUSTOMER_CONFIRMATION", application.getFulfillmentStatus());
assertEquals("COMPLETED", order.getRelabelStatus());
assertEquals("RELABEL:CUSTOMER_CONFIRM_PENDING", order.getSubOrderStatus());
assertEquals(RelabelApplicationService.CUSTOMER_CONFIRM_PENDING, returnOrder.getRelabelStatus());
verify(returnOrders).updateById(returnOrder);
}
@Test
@@ -558,6 +568,7 @@ class RelabelApplicationServiceTest {
new RelabelRequests.CustomerConfirm("confirm-transfer", "accepted"));
assertEquals("READY_FOR_DISPATCH", transfer.getStatus());
assertEquals("WAIT_PRE_DISPATCH", application.getFulfillmentStatus());
assertNotNull(transfer.getRelabelCompletedAt());
assertEquals("READY_FOR_DISPATCH", transferOrder.getCurrentStatus());
assertEquals("COMPLETED", transferOrder.getRelabelStatus());
@@ -610,6 +621,7 @@ class RelabelApplicationServiceTest {
assertEquals("ONT8", transfer.getFbaWarehouseCode());
assertEquals("READY_FOR_DISPATCH", transfer.getStatus());
assertEquals("WAIT_PRE_DISPATCH", application.getFulfillmentStatus());
assertEquals("ONT8", transferOrder.getFbaWarehouseCode());
assertEquals("READY_FOR_DISPATCH", transferOrder.getCurrentStatus());
}
@@ -45,6 +45,7 @@ class RelabelReturnCartonCandidateTest {
assertEquals("RETURN_CARTON", result.get(0).sourceType());
assertEquals(9001L, result.get(0).returnCartonId());
assertEquals("RC-WH-0001", result.get(0).cartonMark());
assertEquals(12, result.get(0).availablePackages());
assertEquals("SKU-RETURN", result.get(0).skuItems().get(0).skuCode());
assertEquals(12, result.get(0).skuItems().get(0).quantity());
}