贴标申请,仓储转运

This commit is contained in:
2026-09-17 17:37:29 +08:00
parent 3b8b6f5aa2
commit 29f05b7b09
106 changed files with 5019 additions and 471 deletions
@@ -11,6 +11,8 @@ class WarehouseTransferSchemaContractTest {
void baselineAndIncrementalContainTransferAndHistoricalOrderBindingTables() throws Exception {
String baseline = Files.readString(Path.of("src", "main", "resources", "db", "lastleg.sql"), StandardCharsets.UTF_8).toLowerCase();
String migration = Files.readString(Path.of("..", "scripts", "db", "incremental.sql"), StandardCharsets.UTF_8).toLowerCase();
String deployment = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
StandardCharsets.UTF_8).toLowerCase();
for (String table : new String[]{"ll_warehouse_transfer_order", "ll_warehouse_transfer_source_order",
"ll_warehouse_transfer_item", "ll_warehouse_transfer_inventory_allocation",
"ll_warehouse_transfer_receipt"}) {
@@ -21,5 +23,25 @@ class WarehouseTransferSchemaContractTest {
assertTrue(migration.contains("uk_ll_wh_transfer_source"));
assertTrue(migration.contains("uk_ll_wh_transfer_active_position"));
assertTrue(migration.contains("uk_ll_wh_transfer_receipt_source"));
assertTrue(baseline.contains("pickup_contact_name varchar(128) null"));
assertTrue(baseline.contains("pickup_contact_phone varchar(64) null"));
assertTrue(migration.contains("column_name='pickup_contact_name'"));
assertTrue(migration.contains("column_name='pickup_contact_phone'"));
assertTrue(baseline.contains("create table if not exists ll_warehouse_transfer_measurement_photo"));
assertTrue(migration.contains("create table if not exists ll_warehouse_transfer_measurement_photo"));
assertTrue(baseline.contains("received_package_count int null comment 'pda实际入库箱数'"));
assertTrue(migration.contains("column_name='received_package_count'"));
assertTrue(migration.contains("o.current_status='inbound_completed'"));
for (String field : new String[]{"pickup_contact_name", "review_decision", "destination_type",
"destination_binding_idempotency_key", "private_destination_address",
"private_destination_postal_code", "draft_idempotency_key", "bind_idempotency_key"}) {
assertTrue(deployment.contains(field), () -> "deployment SQL must include " + field);
}
for (String table : new String[]{"ll_warehouse_transfer_measurement_photo", "ll_inbound_plan_line",
"ll_inbound_plan_pallet", "ll_dispatch_item", "ll_delivery_order"}) {
assertTrue(deployment.contains(table), () -> "deployment SQL must include " + table);
}
assertTrue(deployment.contains("assert_relabel_transfer_latest_schema_ready"));
assertTrue(deployment.contains("贴标申请与仓储转运最新表结构已完整部署"));
}
}
@@ -31,6 +31,25 @@ class MerchantWarehouseTransferControllerTest {
verify(service).detail("100", "TR001");
}
@Test
void merchantSubmitUsesOnlyAuthenticatedTenant() {
controller.submit(user(100L, "MERCHANT"), "TR001");
verify(service).submit("100", "TR001", "1");
}
@Test
void merchantUpdateUsesOnlyAuthenticatedTenant() {
WarehouseTransferRequests.Create request = mock(WarehouseTransferRequests.Create.class);
controller.updateDraft(user(100L, "MERCHANT"), "TR001", request);
verify(service).updateDraft("100", "TR001", "1", request);
}
@Test
void merchantPrintsSubmittedCartonLabelsWithinAuthenticatedTenant() {
controller.cartonLabel(user(100L, "MERCHANT"), "TR001");
verify(service).cartonLabel("100", "TR001");
}
@Test
void merchantEndpointRejectsPlatformIdentity() {
assertThrows(ResponseStatusException.class,
@@ -0,0 +1,62 @@
package com.baiyue.lastleg.transfer.controller;
import com.baiyue.common.security.AuthenticatedUser;
import org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.multipart.MultipartFile;
import static org.assertj.core.api.Assertions.assertThat;
class PdaWarehouseTransferControllerContractTest {
@Test
void detailUsesOnlyAuthenticatedPdaWarehouseScopeAndTransferNumber() throws Exception {
var method = PdaWarehouseTransferController.class
.getMethod("detail", AuthenticatedUser.class, String.class);
assertThat(method.getAnnotation(GetMapping.class).value()).containsExactly("/{transferNo}");
assertThat(method.getParameterCount()).isEqualTo(2);
}
@Test
void measurementPhotoUploadUsesThePublicPdaRouteAndFileMultipartPart() throws Exception {
var method = PdaWarehouseTransferController.class.getMethod("uploadMeasurementPhoto",
AuthenticatedUser.class, String.class, MultipartFile.class);
var mapping = method.getAnnotation(PostMapping.class);
assertThat(mapping.value()).containsExactly("/{transferNo}/measurement-photos/files");
assertThat(mapping.consumes()).containsExactly("multipart/form-data");
assertThat(method.getParameters()[2].getAnnotation(RequestParam.class).value()).isEqualTo("file");
}
@Test
void palletLabelUsesThePdaScopedTransferAndGeneratedWarehousePallet() throws Exception {
var method = PdaWarehouseTransferController.class.getMethod("palletLabel",
AuthenticatedUser.class, String.class, long.class, String.class);
assertThat(method.getAnnotation(GetMapping.class).value())
.containsExactly("/{transferNo}/pallets/{warehousePalletId}/label");
assertThat(method.getParameters()[3].getAnnotation(RequestHeader.class).value()).isEqualTo("X-Request-Id");
}
@Test
void palletLifecycleExposesDraftGenerateBindAndDraftDeleteRoutes() throws Exception {
var draft = PdaWarehouseTransferController.class.getMethod("savePalletDraft",
AuthenticatedUser.class, String.class, WarehouseTransferRequests.PalletDraft.class);
var generate = PdaWarehouseTransferController.class.getMethod("generatePallet",
AuthenticatedUser.class, String.class, long.class, WarehouseTransferRequests.PalletAction.class);
var bind = PdaWarehouseTransferController.class.getMethod("bindPallet",
AuthenticatedUser.class, String.class, long.class, WarehouseTransferRequests.PalletBind.class);
var delete = PdaWarehouseTransferController.class.getMethod("deletePalletDraft",
AuthenticatedUser.class, String.class, long.class);
assertThat(draft.getAnnotation(PostMapping.class).value()).containsExactly("/{transferNo}/pallets/drafts");
assertThat(generate.getAnnotation(PostMapping.class).value()).containsExactly("/{transferNo}/pallets/{palletId}/generate");
assertThat(bind.getAnnotation(PostMapping.class).value()).containsExactly("/{transferNo}/pallets/{palletId}/bind");
assertThat(delete.getAnnotation(DeleteMapping.class).value()).containsExactly("/{transferNo}/pallets/{palletId}");
}
}
@@ -0,0 +1,31 @@
package com.baiyue.lastleg.transfer.dto;
import jakarta.validation.Validation;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
class WarehouseTransferCargoValidationTest {
@Test
void transferCargoAllowsSkuAndProductNameToBeOmitted() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
var violations = factory.getValidator().validate(
new WarehouseTransferRequests.Item(null, null, 1, null));
assertTrue(violations.isEmpty());
}
}
@Test
void cartonRelabelAllowsOriginalSkuToBeOmitted() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
var violations = factory.getValidator().validate(new WarehouseTransferRequests.RelabelItem(
"CARTON_LABEL", List.of("CUSTOMER-CARTON-1"), null, null, 1,
"FBA-CARTON-1", "ONT8", null));
assertTrue(violations.isEmpty());
}
}
}
@@ -11,12 +11,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class WarehouseTransferPalletValidationTest {
@Test
void palletAcceptsDirectTotalVolumeAndWeightWithoutCartonDimensions() {
void palletAcceptsMeasuredDimensionsVolumeAndWeight() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
var validator = factory.getValidator();
var pallet = new WarehouseTransferRequests.Pallet("PALLET-1", 5,
new BigDecimal("1.250000"), new BigDecimal("420.50"),
List.of(new WarehouseTransferRequests.PalletItem(101L, 5)));
var pallet = new WarehouseTransferRequests.Pallet(5,
new BigDecimal("100"), new BigDecimal("100"), new BigDecimal("125"),
new BigDecimal("1.250000"), new BigDecimal("420.50"));
assertTrue(validator.validate(pallet).isEmpty());
assertEquals(new BigDecimal("1.250000"), pallet.volumeCbm());
@@ -28,11 +28,23 @@ class WarehouseTransferPalletValidationTest {
void palletRejectsNonPositiveTotalVolume() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
var validator = factory.getValidator();
var pallet = new WarehouseTransferRequests.Pallet("PALLET-1", 5,
BigDecimal.ZERO, new BigDecimal("420.50"),
List.of(new WarehouseTransferRequests.PalletItem(101L, 5)));
var pallet = new WarehouseTransferRequests.Pallet(5,
new BigDecimal("100"), new BigDecimal("100"), new BigDecimal("125"),
BigDecimal.ZERO, new BigDecimal("420.50"));
assertEquals(1, validator.validate(pallet).size());
}
}
@Test
void palletRejectsMissingOrNonPositiveDimensions() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
var validator = factory.getValidator();
var pallet = new WarehouseTransferRequests.Pallet(5,
BigDecimal.ZERO, null, new BigDecimal("125"),
new BigDecimal("1.250000"), new BigDecimal("420.50"));
assertEquals(2, validator.validate(pallet).size());
}
}
}
@@ -0,0 +1,16 @@
package com.baiyue.lastleg.transfer.gateway;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import static org.assertj.core.api.Assertions.assertThat;
class HttpTransferMeasurementPhotoFileGatewayContractTest {
@Test
void defaultsToTheFileServicesActualLocalPort() throws Exception {
var field = HttpTransferMeasurementPhotoFileGateway.class.getDeclaredField("baseUrl");
assertThat(field.getAnnotation(Value.class).value())
.isEqualTo("${baiyue.clients.file.url:http://127.0.0.1:9206}");
}
}
@@ -0,0 +1,94 @@
package com.baiyue.lastleg.transfer.service;
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferItem;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferPallet;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
class WarehouseTransferPalletAllocationTest {
@Test
void allocatesMultipleDeclaredSkusAcrossPalletsInStableDeclaredOrder() {
WarehouseTransferItem first = item(11L, 3);
WarehouseTransferItem second = item(12L, 4);
var allocations = WarehouseTransferService.derivePalletAllocations(
List.of(first, second), List.of(pallet(2), pallet(5)));
assertEquals(List.of(
new WarehouseTransferService.DerivedPalletAllocation(0, 11L, 2),
new WarehouseTransferService.DerivedPalletAllocation(1, 11L, 1),
new WarehouseTransferService.DerivedPalletAllocation(1, 12L, 4)), allocations);
}
@Test
void underReceiptConsumesDeclaredSkusInStableOrder() {
var allocations = WarehouseTransferService.derivePalletAllocations(
List.of(item(11L, 3), item(12L, 2)), List.of(pallet(4)));
assertEquals(List.of(
new WarehouseTransferService.DerivedPalletAllocation(0, 11L, 3),
new WarehouseTransferService.DerivedPalletAllocation(0, 12L, 1)), allocations);
assertEquals(4, allocations.stream().mapToInt(value -> value.packageCount()).sum());
}
@Test
void overReceiptAssignsExcessToFinalDeclaredSkuAcrossPallets() {
var allocations = WarehouseTransferService.derivePalletAllocations(
List.of(item(11L, 3), item(12L, 2)), List.of(pallet(4), pallet(3)));
assertEquals(List.of(
new WarehouseTransferService.DerivedPalletAllocation(0, 11L, 3),
new WarehouseTransferService.DerivedPalletAllocation(0, 12L, 1),
new WarehouseTransferService.DerivedPalletAllocation(1, 12L, 3)), allocations);
assertEquals(7, allocations.stream().mapToInt(value -> value.packageCount()).sum());
}
@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());
}
@Test
void requestsFreshPalletNumbersAndCarriesOnlyTheKnownFbaDestination() {
var known = WarehouseTransferService.newTransferPalletRequests(81L, "WTR-1", "ONT8", 2);
var unknown = WarehouseTransferService.newTransferPalletRequests(81L, "WTR-2", null, 1);
assertEquals(List.of("WTR-1:1", "WTR-1:2"), known.stream().map(value -> value.businessKey()).toList());
assertEquals(List.of("ONT8", "ONT8"), known.stream().map(value -> value.fbaWarehouseCode()).toList());
assertEquals(true, known.stream().allMatch(value -> value.palletCode() == null));
assertEquals(null, unknown.get(0).fbaWarehouseCode());
assertEquals(null, unknown.get(0).palletCode());
}
private static WarehouseTransferItem item(long id, int packages) {
WarehouseTransferItem item = new WarehouseTransferItem();
item.setId(id); item.setPackageCount(packages);
return item;
}
private static WarehouseTransferRequests.Pallet pallet(int cartons) {
return new WarehouseTransferRequests.Pallet(cartons, BigDecimal.ONE, BigDecimal.ONE,
BigDecimal.ONE, new BigDecimal("0.000001"), BigDecimal.ONE);
}
private static com.baiyue.lastleg.transfer.entity.WarehouseTransferPallet persistedPallet(int cartons) {
var pallet = new com.baiyue.lastleg.transfer.entity.WarehouseTransferPallet();
pallet.setCartonCount(cartons);
return pallet;
}
}
@@ -1,6 +1,7 @@
package com.baiyue.lastleg.transfer.service;
import com.baiyue.lastleg.entity.LastlegOrder;
import com.baiyue.lastleg.entity.LastlegOrderDetail;
import com.baiyue.lastleg.entity.LastlegInboundOrder;
import com.baiyue.lastleg.relabel.entity.RelabelApplication;
import com.baiyue.lastleg.inventory.command.dto.InventoryCommandResponse;
@@ -19,11 +20,27 @@ import com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferCarton;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferInventoryAllocation;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferSourceOrder;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferMeasurementPhoto;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferPallet;
import com.baiyue.lastleg.transfer.entity.WarehouseTransferItem;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferPalletMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferPalletItemMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferRelabelBindingMapper;
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
import com.baiyue.lastleg.inboundplan.pda.mapper.InboundStockReceiptMapper;
import com.baiyue.lastleg.inboundplan.entity.InboundPlan;
import com.baiyue.lastleg.inboundplan.entity.InboundPlanLine;
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanMapper;
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanLineMapper;
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletMapper;
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletAllocationMapper;
import com.baiyue.lastleg.transfer.mapper.InboundSnapshotMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferItemMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferCartonMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferInventoryAllocationMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferOrderMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferMeasurementPhotoMapper;
import com.baiyue.lastleg.transfer.gateway.TransferMeasurementPhotoFileGateway;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferReceiptMapper;
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferSourceOrderMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -62,14 +79,36 @@ import static org.mockito.Mockito.times;
@ExtendWith(MockitoExtension.class)
class WarehouseTransferServiceTest {
@Test
void customerMainStatusFiltersExpandToInternalWorkflowStates() {
assertEquals(List.of(WarehouseTransferService.APPROVED, WarehouseTransferService.WAIT_PDA_RECEIVING),
WarehouseTransferService.customerMainStatuses(WarehouseTransferService.INBOUND_MEASURING));
assertTrue(WarehouseTransferService.customerMainStatuses(WarehouseTransferService.INBOUND_COMPLETED)
.containsAll(List.of(WarehouseTransferService.WAIT_CUSTOMER_CONFIRMATION,
WarehouseTransferService.WAIT_FBA_DESTINATION, WarehouseTransferService.WAIT_RELABEL,
WarehouseTransferService.READY_FOR_DISPATCH, WarehouseTransferService.OUTBOUNDED)));
assertNull(WarehouseTransferService.customerMainStatuses(WarehouseTransferService.DRAFT));
}
@Mock WarehouseTransferOrderMapper transfers;
@Mock WarehouseTransferItemMapper transferItems;
@Mock WarehouseTransferCartonMapper transferCartons;
@Mock WarehouseTransferSourceOrderMapper sourceOrders;
@Mock WarehouseTransferInventoryAllocationMapper inventoryAllocations;
@Mock WarehouseTransferReceiptMapper transferReceipts;
@Mock WarehouseTransferMeasurementPhotoMapper measurementPhotos;
@Mock WarehouseTransferPalletMapper transferPallets;
@Mock WarehouseTransferPalletItemMapper transferPalletItems;
@Mock InboundStockReceiptMapper stockReceipts;
@Mock WarehouseTransferRelabelBindingMapper relabelBindings;
@Mock WarehouseResourceGateway warehouseResources;
@Mock TransferMeasurementPhotoFileGateway measurementPhotoFiles;
@Mock InboundSnapshotMapper inboundSnapshots;
@Mock LastlegInboundOrderMapper inboundOrders;
@Mock InboundPlanMapper inboundPlans;
@Mock InboundPlanLineMapper inboundPlanLines;
@Mock InboundPlanPalletMapper inboundPlanPallets;
@Mock InboundPlanPalletAllocationMapper inboundPlanAllocations;
@Mock LastlegOrderMapper orders;
@Mock LastlegOrderDetailMapper orderDetails;
@Mock LastlegOrderStatusHistoryMapper orderHistories;
@@ -88,8 +127,19 @@ class WarehouseTransferServiceTest {
ReflectionTestUtils.setField(service, "sourceOrders", sourceOrders);
ReflectionTestUtils.setField(service, "inventoryAllocations", inventoryAllocations);
ReflectionTestUtils.setField(service, "transferReceipts", transferReceipts);
ReflectionTestUtils.setField(service, "measurementPhotos", measurementPhotos);
ReflectionTestUtils.setField(service, "transferPallets", transferPallets);
ReflectionTestUtils.setField(service, "transferPalletItems", transferPalletItems);
ReflectionTestUtils.setField(service, "stockReceipts", stockReceipts);
ReflectionTestUtils.setField(service, "relabelBindings", relabelBindings);
ReflectionTestUtils.setField(service, "warehouseResources", warehouseResources);
ReflectionTestUtils.setField(service, "measurementPhotoFiles", measurementPhotoFiles);
ReflectionTestUtils.setField(service, "inboundSnapshots", inboundSnapshots);
ReflectionTestUtils.setField(service, "inboundOrders", inboundOrders);
ReflectionTestUtils.setField(service, "inboundPlans", inboundPlans);
ReflectionTestUtils.setField(service, "inboundPlanLines", inboundPlanLines);
ReflectionTestUtils.setField(service, "inboundPlanPallets", inboundPlanPallets);
ReflectionTestUtils.setField(service, "inboundPlanAllocations", inboundPlanAllocations);
ReflectionTestUtils.setField(service, "orders", orders);
ReflectionTestUtils.setField(service, "orderDetails", orderDetails);
ReflectionTestUtils.setField(service, "orderHistories", orderHistories);
@@ -103,6 +153,116 @@ class WarehouseTransferServiceTest {
lenient().when(inventoryAllocations.selectList(any())).thenReturn(List.of());
lenient().when(transferReceipts.selectList(any())).thenReturn(List.of());
lenient().when(transferCartons.listOrder(anyString(), anyLong())).thenReturn(List.of());
lenient().when(measurementPhotos.listOrder(anyString(), anyLong())).thenReturn(List.of());
lenient().when(measurementPhotos.listSubmitted(anyString(), anyLong())).thenReturn(List.of());
lenient().when(transferPalletItems.listOrder(anyString(), anyLong())).thenReturn(List.of());
lenient().when(relabelBindings.listOrder(anyString(), anyLong())).thenReturn(List.of());
}
@Test
void generatedPalletRetryWithSameKeyDoesNotGenerateAnotherPhysicalPallet() {
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.WAIT_PDA_RECEIVING);
transfer.setOperatingWarehouseId("77");
WarehouseTransferPallet pallet = measuredPallet("GENERATED");
pallet.setGenerateIdempotencyKey("GEN-1");
when(transfers.lockForPda("WTR-1", "77")).thenReturn(transfer);
when(transferPallets.lockOne("TENANT-A", transfer.getId(), pallet.getId())).thenReturn(pallet);
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
when(transferPallets.listOrder("TENANT-A", transfer.getId())).thenReturn(List.of(pallet));
service.generatePallet(77L, "WTR-1", pallet.getId(), new WarehouseTransferRequests.PalletAction("GEN-1"));
verify(warehouseResources, never()).ensurePalletBatch(any());
verify(warehouseResources, never()).confirmPalletBatch(any());
}
@Test
void scanBindingRejectsCodeOtherThanThisGeneratedPallet() {
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.WAIT_PDA_RECEIVING);
WarehouseTransferPallet pallet = measuredPallet("GENERATED");
when(transfers.lockForPda("WTR-1", "77")).thenReturn(transfer);
when(transferPallets.lockOne("TENANT-A", transfer.getId(), pallet.getId())).thenReturn(pallet);
ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> service.bindPallet(
77L, "WTR-1", pallet.getId(), new WarehouseTransferRequests.PalletBind("OTHER-PALLET", "BIND-1")));
assertEquals(409, exception.getStatusCode().value());
verify(warehouseResources, never()).resolvePallet(anyString());
}
@Test
void palletizeRejectsWhenAnyPersistedPalletIsNotBound() {
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.WAIT_PDA_RECEIVING);
transfer.setOperatingWarehouseId("77");
WarehouseTransferPallet pallet = measuredPallet("GENERATED");
when(transfers.lockForPda("WTR-1", "77")).thenReturn(transfer);
when(transferItems.selectList(any())).thenReturn(List.of(transferItem(51L, "SKU-1", 5)));
WarehouseTransferMeasurementPhoto photo = new WarehouseTransferMeasurementPhoto();
photo.setFileId(9001L);
when(measurementPhotos.findFile("TENANT-A", transfer.getId(), 9001L)).thenReturn(photo);
when(transferPallets.listOrder("TENANT-A", transfer.getId())).thenReturn(List.of(pallet));
ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> service.palletize(
"OP-1", 77L, "WTR-1", new WarehouseTransferRequests.Palletize("DONE-1", List.of(9001L))));
assertEquals(409, exception.getStatusCode().value());
verify(warehouseResources, never()).ensurePalletBatch(any());
}
@Test
void palletizeCompletesAfterEveryPalletIsBoundAndDoesNotGenerateAgain() {
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.WAIT_PDA_RECEIVING);
transfer.setOperatingWarehouseId("77");
transfer.setInboundCode("WTR-1");
WarehouseTransferPallet pallet = measuredPallet("BOUND");
WarehouseTransferItem item = transferItem(51L, "SKU-1", 5);
LastlegOrder tail = tailOrder();
LastlegInboundOrder inbound = new LastlegInboundOrder();
inbound.setId(transfer.getInboundOrderId()); inbound.setCustomerId("TENANT-A");
InboundPlan inboundPlan = new InboundPlan(); inboundPlan.setId(201L); inboundPlan.setStatus("PDA_PENDING");
InboundPlanLine inboundLine = new InboundPlanLine(); inboundLine.setId(202L);
when(transfers.lockForPda("WTR-1", "77")).thenReturn(transfer);
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(transferItems.selectList(any())).thenReturn(List.of(item));
when(transferPallets.listOrder("TENANT-A", transfer.getId())).thenReturn(List.of(pallet));
WarehouseTransferMeasurementPhoto photo = new WarehouseTransferMeasurementPhoto();
photo.setFileId(9001L);
when(measurementPhotos.findFile("TENANT-A", transfer.getId(), 9001L)).thenReturn(photo);
when(measurementPhotos.markSubmitted(eq("TENANT-A"), eq(transfer.getId()), any(), any())).thenReturn(1);
when(orders.selectById(transfer.getLastlegOrderId())).thenReturn(tail);
when(inboundOrders.selectById(transfer.getInboundOrderId())).thenReturn(inbound);
when(inboundPlans.findBySourceOrder("TENANT-A", transfer.getLastlegOrderId())).thenReturn(inboundPlan);
when(inboundPlanLines.selectOne(any())).thenReturn(inboundLine);
when(warehouseResources.requireActiveSharedWarehouse(77L)).thenReturn(
new WarehouseResourceGateway.WarehouseReference(77L, "WH-77", "Warehouse 77", "ACTIVE"));
when(inventory.stockIn(eq("TENANT-A"), eq("OP-1"), any())).thenReturn(
new InventoryCommandResponse(1L, "STOCK_IN", 801L, 901L, 5, 0, 0, 0, false, false));
when(sourceOrders.selectList(any())).thenReturn(List.of());
var result = service.palletize("OP-1", 77L, "WTR-1",
new WarehouseTransferRequests.Palletize("DONE-1", List.of(9001L)));
assertEquals(WarehouseTransferService.WAIT_CUSTOMER_CONFIRMATION, result.status());
assertEquals("COMPLETED", pallet.getStatus());
assertEquals(WarehouseTransferService.INBOUND_COMPLETED, tail.getCurrentStatus());
assertEquals(5, tail.getReceivedPackageCount());
assertEquals("RECEIVED", inbound.getStatus());
assertEquals(5, inbound.getPackageCount());
assertEquals("COMPLETED", inboundPlan.getStatus());
verify(transferPalletItems).insert(any(com.baiyue.lastleg.transfer.entity.WarehouseTransferPalletItem.class));
verify(inventory).stockIn(eq("TENANT-A"), eq("OP-1"), any());
verify(stockReceipts).insert(any(com.baiyue.lastleg.inboundplan.pda.entity.InboundStockReceipt.class));
verify(inboundOrders).updateById(inbound);
verify(inboundPlans).updateById(inboundPlan);
verify(inboundPlanPallets).insert(any(com.baiyue.lastleg.inboundplan.entity.InboundPlanPallet.class));
ArgumentCaptor<com.baiyue.lastleg.inboundplan.entity.InboundPlanPalletAllocation> allocation =
ArgumentCaptor.forClass(com.baiyue.lastleg.inboundplan.entity.InboundPlanPalletAllocation.class);
verify(inboundPlanAllocations).insert(allocation.capture());
assertEquals(5, allocation.getValue().getPickedPackageCount());
verify(warehouseResources, never()).ensurePalletBatch(any());
verify(warehouseResources, never()).confirmPalletBatch(any());
}
@Test
@@ -111,7 +271,7 @@ class WarehouseTransferServiceTest {
LastlegOrder historical = historicalOrder();
when(inboundSnapshots.findId("TENANT-A", "IN-1")).thenReturn(101L);
when(orders.selectList(any())).thenReturn(List.of(historical));
when(transfers.findNo(eq("TENANT-A"), org.mockito.ArgumentMatchers.anyString())).thenAnswer(invocation -> persistedTransfer());
when(transfers.findNo(eq("TENANT-A"), org.mockito.ArgumentMatchers.anyString())).thenAnswer(invocation -> transfer(WarehouseTransferService.DRAFT));
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
@@ -120,23 +280,23 @@ class WarehouseTransferServiceTest {
ArgumentCaptor<LastlegOrder> tailOrder = ArgumentCaptor.forClass(LastlegOrder.class);
verify(orders).insert(tailOrder.capture());
assertEquals(WarehouseTransferService.ORDER_TYPE, tailOrder.getValue().getOrderType());
assertEquals(WarehouseTransferService.PENDING_REVIEW, tailOrder.getValue().getCurrentStatus());
assertEquals("WAREHOUSE_TRANSFER:PENDING_REVIEW;RELABEL:PENDING_BINDING", tailOrder.getValue().getSubOrderStatus());
assertEquals(WarehouseTransferService.DRAFT, tailOrder.getValue().getCurrentStatus());
assertEquals("WAREHOUSE_TRANSFER:DRAFT;RELABEL:PENDING_BINDING", tailOrder.getValue().getSubOrderStatus());
assertTrue(tailOrder.getValue().getOrderNo().matches("WT-WH-\\d{8}-\\d{6}"));
assertNull(tailOrder.getValue().getTransferWarehouseId());
verify(sourceOrders).insert(any(WarehouseTransferSourceOrder.class));
verify(relabelApplications, never()).insert(any(RelabelApplication.class));
assertNull(tailOrder.getValue().getRelabelOrderNo());
assertEquals("PENDING_BINDING", tailOrder.getValue().getRelabelStatus());
assertEquals(WarehouseTransferService.PENDING_REVIEW, result.status());
assertEquals(WarehouseTransferService.PENDING_REVIEW, result.orderStatus());
assertEquals(WarehouseTransferService.DRAFT, result.status());
assertEquals(WarehouseTransferService.DRAFT, result.orderStatus());
}
@Test
void transferWithoutRelabelDoesNotCreateRelabelDocument() {
when(inboundSnapshots.findId("TENANT-A", "IN-1")).thenReturn(101L);
when(orders.selectList(any())).thenReturn(List.of(historicalOrder()));
when(transfers.findNo(eq("TENANT-A"), org.mockito.ArgumentMatchers.anyString())).thenAnswer(invocation -> persistedTransfer());
when(transfers.findNo(eq("TENANT-A"), org.mockito.ArgumentMatchers.anyString())).thenAnswer(invocation -> transfer(WarehouseTransferService.DRAFT));
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
@@ -146,6 +306,27 @@ class WarehouseTransferServiceTest {
assertNull(result.relabelNo());
}
@Test
void transferRelabelRejectsMultipleDestinationWarehouses() {
WarehouseTransferRequests.Create request = new WarehouseTransferRequests.Create(
null, null, "WH-1", null, "NONE", null, null, null,
null, null, null, null, "123 Pickup Road", null, null, 2,
new BigDecimal("0.1000"), "CUSTOMER_DELIVERY", LocalDateTime.of(2026, 9, 18, 10, 0),
null, null, null, "BOX-1,BOX-2", null, true,
LocalDateTime.of(2026, 9, 19, 10, 0), "Contact", "13800000000", null, "TRUCK",
"single-destination-check", List.of(new WarehouseTransferRequests.Item("SKU-1", "Product", 2, null)),
List.of(
new WarehouseTransferRequests.RelabelItem("CARTON_LABEL", List.of("BOX-1"), "SKU-1", null, 1, "FBA-1", "ONT8", null),
new WarehouseTransferRequests.RelabelItem("CARTON_LABEL", List.of("BOX-2"), "SKU-1", null, 1, "FBA-2", "ACY2", null)));
ResponseStatusException exception = assertThrows(ResponseStatusException.class,
() -> service.create("TENANT-A", "USER-1", request));
assertEquals(400, exception.getStatusCode().value());
assertEquals("Warehouse transfer relabel only supports one destination warehouse per order", exception.getReason());
verifyNoInteractions(transfers);
}
@Test
void transferCanEnterTheTransitWarehouseBeforeFbaDestinationIsKnown() {
WarehouseTransferRequests.Create request = new WarehouseTransferRequests.Create(
@@ -155,7 +336,7 @@ class WarehouseTransferServiceTest {
List.of(new WarehouseTransferRequests.Item("SKU-1", "Product", 5, "MARK-1")));
when(inboundSnapshots.findId("TENANT-A", "IN-1")).thenReturn(101L);
when(orders.selectList(any())).thenReturn(List.of(historicalOrder()));
when(transfers.findNo(eq("TENANT-A"), org.mockito.ArgumentMatchers.anyString())).thenAnswer(invocation -> persistedTransfer());
when(transfers.findNo(eq("TENANT-A"), org.mockito.ArgumentMatchers.anyString())).thenAnswer(invocation -> transfer(WarehouseTransferService.DRAFT));
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
@@ -179,7 +360,7 @@ class WarehouseTransferServiceTest {
null, "TRACK-MUST-NOT-BE-SAVED", null, "Incoming transit cargo", true, "key-incoming",
List.of(new WarehouseTransferRequests.Item("SKU-1", "Product A", 2, null),
new WarehouseTransferRequests.Item("SKU-2", "Product B", 3, null)));
when(transfers.findNo(eq("TENANT-A"), anyString())).thenAnswer(invocation -> persistedTransfer());
when(transfers.findNo(eq("TENANT-A"), anyString())).thenAnswer(invocation -> transfer(WarehouseTransferService.DRAFT));
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
@@ -199,7 +380,7 @@ class WarehouseTransferServiceTest {
assertEquals(transfer.getValue().getTransferNo(), transfer.getValue().getInboundCode());
assertEquals(transfer.getValue().getTransferNo(), inbound.getValue().getInboundCode());
assertEquals("OVERSEAS", inbound.getValue().getDestinationType());
assertEquals(WarehouseTransferService.PENDING_REVIEW, inbound.getValue().getStatus());
assertEquals(WarehouseTransferService.DRAFT, inbound.getValue().getStatus());
assertNull(transfer.getValue().getTrackingNo());
assertEquals("PENDING_BINDING", tailOrder.getValue().getRelabelStatus());
assertEquals(List.of(1, 2, 3, 4, 5), cartons.getAllValues().stream()
@@ -209,7 +390,7 @@ class WarehouseTransferServiceTest {
}
@Test
void approvedTransferWithoutRelabelEntersPendingAssignment() {
void approvedTransferWithoutRelabelEntersInboundMeasuring() {
WarehouseTransferOrder transfer = persistedTransfer();
transfer.setStatus(WarehouseTransferService.PENDING_REVIEW);
transfer.setNeedRelabel(false);
@@ -225,14 +406,134 @@ class WarehouseTransferServiceTest {
new WarehouseTransferRequests.Review("APPROVE", null));
assertEquals(WarehouseTransferService.APPROVED, transfer.getStatus());
assertEquals(WarehouseTransferService.PENDING_ASSIGNMENT, tailOrder.getCurrentStatus());
assertEquals(WarehouseTransferService.INBOUND_MEASURING, tailOrder.getCurrentStatus());
assertEquals(WarehouseTransferService.APPROVED, result.status());
assertEquals(WarehouseTransferService.PENDING_ASSIGNMENT, result.orderStatus());
assertEquals(WarehouseTransferService.INBOUND_MEASURING, result.orderStatus());
verify(transfers).updateById(transfer);
verify(orders).updateById(tailOrder);
verifyNoInteractions(inventory);
}
@Test
void approvedIncomingTransferCreatesPendingInboundPlan() {
WarehouseTransferOrder transfer = persistedTransfer();
transfer.setInboundCode("WTR-1"); transfer.setOperatingWarehouseId("77");
transfer.setEstimatedArrivalAt(LocalDateTime.of(2026, 9, 17, 10, 0));
LastlegOrder tailOrder = tailOrder(); tailOrder.setCurrentStatus(WarehouseTransferService.PENDING_REVIEW);
LastlegInboundOrder inbound = new LastlegInboundOrder();
inbound.setId(101L); inbound.setCustomerId("TENANT-A"); inbound.setStatus(WarehouseTransferService.PENDING_REVIEW);
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(orders.selectById(31L)).thenReturn(tailOrder);
when(inboundOrders.selectById(101L)).thenReturn(inbound);
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
service.review("TENANT-A", "WTR-1", "USER-1", new WarehouseTransferRequests.Review("APPROVE", null));
ArgumentCaptor<InboundPlan> plan = ArgumentCaptor.forClass(InboundPlan.class);
ArgumentCaptor<InboundPlanLine> line = ArgumentCaptor.forClass(InboundPlanLine.class);
verify(inboundPlans).insert(plan.capture());
verify(inboundPlanLines).insert(line.capture());
assertEquals("PDA_PENDING", plan.getValue().getStatus());
assertEquals("WT-WTR-1", plan.getValue().getPlanNo());
assertEquals("WTR-1", line.getValue().getInboundCode());
assertEquals(5, line.getValue().getRequiredPackageCount());
assertEquals("PENDING_INBOUND", inbound.getStatus());
assertEquals(WarehouseTransferService.WAIT_PDA_RECEIVING, transfer.getStatus());
}
@Test
void merchantSubmitsDraftForReviewBeforePrintingLabels() {
WarehouseTransferOrder transfer = persistedTransfer();
transfer.setStatus(WarehouseTransferService.DRAFT);
transfer.setInboundCode("WTR-1");
LastlegOrder tailOrder = historicalOrder();
tailOrder.setId(31L); tailOrder.setCustomerId("TENANT-A"); tailOrder.setRelabelStatus("NOT_REQUIRED");
LastlegInboundOrder inbound = new LastlegInboundOrder();
inbound.setId(101L); inbound.setCustomerId("TENANT-A"); inbound.setStatus(WarehouseTransferService.DRAFT);
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(orders.selectById(31L)).thenReturn(tailOrder);
when(inboundOrders.selectById(101L)).thenReturn(inbound);
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
var result = service.submit("TENANT-A", "WTR-1", "USER-1");
assertEquals(WarehouseTransferService.PENDING_REVIEW, transfer.getStatus());
assertEquals(WarehouseTransferService.PENDING_REVIEW, tailOrder.getCurrentStatus());
assertEquals(WarehouseTransferService.PENDING_REVIEW, inbound.getStatus());
assertEquals(WarehouseTransferService.PENDING_REVIEW, result.status());
verify(transfers).updateById(transfer);
verify(orders).updateById(tailOrder);
verify(inboundOrders).updateById(inbound);
}
@Test
void merchantUpdatesDraftAndRebuildsEditableSnapshots() {
WarehouseTransferOrder transfer = persistedTransfer();
transfer.setStatus(WarehouseTransferService.DRAFT);
LastlegOrder tailOrder = historicalOrder();
tailOrder.setId(31L); tailOrder.setCustomerId("TENANT-A"); tailOrder.setCurrentStatus(WarehouseTransferService.DRAFT);
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(orders.selectById(31L)).thenReturn(tailOrder);
when(transferItems.selectList(any())).thenReturn(List.of());
when(sourceOrders.selectList(any())).thenReturn(List.of());
var result = service.updateDraft("TENANT-A", "WTR-1", "USER-1", request(false));
assertEquals(WarehouseTransferService.DRAFT, result.status());
assertEquals("WH-1", transfer.getOperatingWarehouseId());
assertEquals(new BigDecimal("0.2500"), tailOrder.getVolumeCbm());
verify(transfers).updateById(transfer);
verify(orders).updateById(tailOrder);
verify(transferCartons).delete(any());
verify(transferItems).delete(any());
verify(relabelBindings).delete(any());
verify(orderDetails).delete(any());
verify(transferItems).insert(any(WarehouseTransferItem.class));
verify(transferCartons, times(5)).insert(any(WarehouseTransferCarton.class));
verify(orderDetails).insert(any(LastlegOrderDetail.class));
}
@Test
void merchantCannotUpdateSubmittedTransfer() {
WarehouseTransferOrder transfer = persistedTransfer();
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
ResponseStatusException error = assertThrows(ResponseStatusException.class,
() -> service.updateDraft("TENANT-A", "WTR-1", "USER-1", request(false)));
assertEquals(409, error.getStatusCode().value());
verify(transfers, never()).updateById(any(WarehouseTransferOrder.class));
}
@Test
void merchantDraftUpdateIsTenantScoped() {
when(transfers.lockNo("TENANT-B", "WTR-1")).thenReturn(null);
ResponseStatusException error = assertThrows(ResponseStatusException.class,
() -> service.updateDraft("TENANT-B", "WTR-1", "USER-2", request(false)));
assertEquals(404, error.getStatusCode().value());
verify(transfers, never()).updateById(any(WarehouseTransferOrder.class));
}
@Test
void draftCannotPrintCartonLabelsBeforeSubmission() {
WarehouseTransferOrder transfer = persistedTransfer();
transfer.setStatus(WarehouseTransferService.DRAFT);
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
ResponseStatusException error = assertThrows(ResponseStatusException.class,
() -> service.cartonLabel("TENANT-A", "WTR-1"));
assertEquals(409, error.getStatusCode().value());
verify(transferCartons, never()).listOrder(anyString(), anyLong());
}
@Test
void rejectionRequiresNonBlankReasonBeforeAnyStateOrInventoryChange() {
for (String decision : List.of("REJECT", "REJECTED")) {
@@ -378,6 +679,67 @@ class WarehouseTransferServiceTest {
assertEquals("RESERVED", allocation.getStatus());
}
@Test
void outboundRejectsTransferWithoutFbaDestinationBeforeInventoryMutation() {
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.ALLOCATED);
transfer.setFbaWarehouseCode(null);
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
ResponseStatusException exception = assertThrows(ResponseStatusException.class, () ->
service.outbound("TENANT-A", "WTR-1", "USER-1",
new WarehouseTransferRequests.Outbound("OUT-NO-FBA", null)));
assertEquals(409, exception.getStatusCode().value());
verifyNoInteractions(inventory);
verify(inventoryAllocations, never()).lockTransfer(anyString(), anyLong());
verify(transfers, never()).updateById(any(WarehouseTransferOrder.class));
}
@Test
void merchantMeasurementPhotosExposeOnlySubmittedSelection() {
WarehouseTransferOrder transfer = persistedTransfer();
WarehouseTransferMeasurementPhoto selected = new WarehouseTransferMeasurementPhoto();
selected.setFileId(101L); selected.setFileName("selected.jpg"); selected.setContentType("image/jpeg");
selected.setSizeBytes(12L); selected.setUploadedAt(LocalDateTime.of(2026, 9, 16, 10, 0));
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(measurementPhotos.listSubmitted("TENANT-A", 21L)).thenReturn(List.of(selected));
var result = service.measurementPhotos("TENANT-A", "WTR-1");
assertEquals(List.of(101L), result.stream().map(value -> value.fileId()).toList());
verify(measurementPhotos, never()).listOrder("TENANT-A", 21L);
}
@Test
void merchantCannotDownloadUploadedButUnsubmittedMeasurementPhoto() {
WarehouseTransferOrder transfer = persistedTransfer();
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
when(measurementPhotos.findSubmittedFile("TENANT-A", 21L, 102L)).thenReturn(null);
ResponseStatusException exception = assertThrows(ResponseStatusException.class,
() -> service.downloadMeasurementPhoto("TENANT-A", "WTR-1", 102L));
assertEquals(404, exception.getStatusCode().value());
verifyNoInteractions(measurementPhotoFiles);
}
@Test
void pdaCanDownloadOwnWarehouseUploadedPhotoBeforeSubmission() {
WarehouseTransferOrder transfer = persistedTransfer();
WarehouseTransferMeasurementPhoto draft = new WarehouseTransferMeasurementPhoto();
draft.setFileId(102L);
var downloaded = new TransferMeasurementPhotoFileGateway.DownloadedFile(
new byte[]{1}, "draft.jpg", "image/jpeg");
when(transfers.findNoByWarehouse("WTR-1", "92")).thenReturn(transfer);
when(measurementPhotos.findFile("TENANT-A", 21L, 102L)).thenReturn(draft);
when(measurementPhotoFiles.download("TENANT-A", 21L, 102L)).thenReturn(downloaded);
var result = service.downloadPdaMeasurementPhoto(92L, "WTR-1", 102L);
assertEquals("draft.jpg", result.fileName());
verify(measurementPhotos, never()).findSubmittedFile(anyString(), anyLong(), anyLong());
}
@Test
void allocationRejectsPositionOutsideSelectedInboundOrder() {
WarehouseTransferOrder transfer = transfer("APPROVED");
@@ -427,6 +789,7 @@ class WarehouseTransferServiceTest {
transfer.setInboundOrderId(101L); transfer.setInboundCode("IN-1"); transfer.setLastlegOrderId(31L);
transfer.setLastlegOrderNo("LMO-TRANSFER-1"); transfer.setNeedRelabel(false);
transfer.setStatus(WarehouseTransferService.PENDING_REVIEW); transfer.setPackageCount(5);
transfer.setFbaWarehouseCode("ONT8");
return transfer;
}
@@ -436,6 +799,24 @@ class WarehouseTransferServiceTest {
return transfer;
}
private static WarehouseTransferPallet measuredPallet(String status) {
WarehouseTransferPallet pallet = new WarehouseTransferPallet();
pallet.setId(61L); pallet.setTransferOrderId(21L); pallet.setCustomerId("TENANT-A");
pallet.setSequenceNo(1); pallet.setWarehousePalletId(701L); pallet.setPalletNo("NEW-PALLET-1");
pallet.setCartonCount(5); pallet.setLengthCm(new BigDecimal("100.00"));
pallet.setWidthCm(new BigDecimal("100.00")); pallet.setHeightCm(new BigDecimal("100.00"));
pallet.setVolumeCbm(new BigDecimal("1.000000")); pallet.setGrossWeightKg(new BigDecimal("50.000"));
pallet.setStatus(status);
return pallet;
}
private static WarehouseTransferItem transferItem(long id, String sku, int packages) {
WarehouseTransferItem item = new WarehouseTransferItem();
item.setId(id); item.setTransferOrderId(21L); item.setCustomerId("TENANT-A");
item.setSkuCode(sku); item.setProductNameZh("Product"); item.setPackageCount(packages);
return item;
}
private static LastlegOrder tailOrder() {
LastlegOrder order = historicalOrder();
order.setId(31L); order.setCurrentStatus("PENDING_ASSIGNMENT");