提交
This commit is contained in:
+48
@@ -0,0 +1,48 @@
|
||||
package com.baiyue.lastleg.transfer.service;
|
||||
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
|
||||
import com.baiyue.lastleg.transfer.mapper.InboundSnapshotMapper;
|
||||
import org.apache.ibatis.mapping.Environment;
|
||||
import org.apache.ibatis.session.*;
|
||||
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TransferInventorySourceTest {
|
||||
WarehouseTransferRequests.Create request(String inbound, String destination, String method, LocalDateTime arrival) {
|
||||
return new WarehouseTransferRequests.Create(inbound,List.of(),"WH",destination,"ADDRESS",1,BigDecimal.ZERO,
|
||||
method,arrival,null,null,null,null,false,"KEY",List.of(new WarehouseTransferRequests.Item("SKU","Product",1,null)));
|
||||
}
|
||||
@Test void inventoryDoesNotRequireRepeatedArrivalButExternalCargoStillDoes() {
|
||||
assertTrue(request("IN","ONT8",null,null).isInboundModeValid());
|
||||
assertFalse(request("IN",null,null,null).isInboundModeValid());
|
||||
assertFalse(request(null,null,null,null).isInboundModeValid());
|
||||
assertTrue(request(null,null,"CUSTOMER_DELIVERY",LocalDateTime.now()).isInboundModeValid());
|
||||
}
|
||||
@Test void originalBoxesIncludeBothSourcesButNeverAnotherCustomerWarehouseOrInbound() {
|
||||
var ds = new DriverManagerDataSource("jdbc:h2:mem:"+UUID.randomUUID()+";MODE=MySQL;DB_CLOSE_DELAY=-1","sa","");
|
||||
var db=new JdbcTemplate(ds);
|
||||
db.execute("CREATE TABLE ll_order(id BIGINT,customer_id VARCHAR,inbound_code VARCHAR,overseas_warehouse_id VARCHAR)");
|
||||
db.execute("CREATE TABLE ll_inbound_plan_carton(customer_id VARCHAR,order_id BIGINT,carton_mark VARCHAR,sku_code VARCHAR,destination_warehouse_code VARCHAR,destination_warehouse_name VARCHAR)");
|
||||
db.execute("CREATE TABLE ll_warehouse_transfer_order(id BIGINT,customer_id VARCHAR,lastleg_order_id BIGINT,operating_warehouse_id VARCHAR,destination_warehouse_code VARCHAR,destination_warehouse_name VARCHAR)");
|
||||
db.execute("CREATE TABLE ll_warehouse_transfer_item(id BIGINT,customer_id VARCHAR,transfer_order_id BIGINT,sku_code VARCHAR,product_name_zh VARCHAR)");
|
||||
db.execute("CREATE TABLE ll_warehouse_transfer_carton(customer_id VARCHAR,transfer_order_id BIGINT,transfer_item_id BIGINT,carton_mark VARCHAR,counted_quantity BIGINT,sku_items_json VARCHAR,status VARCHAR)");
|
||||
db.update("INSERT INTO ll_order VALUES(1,'A','IN','WH'),(2,'B','IN','WH'),(3,'A','IN','OTHER'),(4,'A','OTHER','WH')");
|
||||
db.update("INSERT INTO ll_inbound_plan_carton VALUES('A',1,'FIRST','S','ONT8','Amazon'),('B',2,'FOREIGN','S','ONT8','Amazon'),('A',3,'WRONG-WH','S','ONT8','Amazon'),('A',4,'WRONG-IN','S','ONT8','Amazon'),('B',1,'FORGED','S','ONT8','Amazon')");
|
||||
db.update("INSERT INTO ll_warehouse_transfer_order VALUES(10,'A',1,'WH','ONT8','Amazon')");
|
||||
db.update("INSERT INTO ll_warehouse_transfer_item VALUES(11,'A',10,'SKU','Product')");
|
||||
db.update("INSERT INTO ll_warehouse_transfer_carton VALUES('A',10,11,'MEASURED',20,NULL,'COUNTED'),('A',10,11,'EXPECTED',NULL,NULL,'EXPECTED'),('B',10,11,'FOREIGN2',20,NULL,'COUNTED')");
|
||||
var config=new Configuration(new Environment("test",new JdbcTransactionFactory(),ds)); config.addMapper(InboundSnapshotMapper.class);
|
||||
try(var session=new SqlSessionFactoryBuilder().build(config).openSession()) {
|
||||
var result=session.getMapper(InboundSnapshotMapper.class).sourceCartons("A","WH","IN");
|
||||
assertEquals(List.of("FIRST","MEASURED"),result.stream().map(InboundSnapshotMapper.SourceCarton::cartonMark).toList());
|
||||
assertEquals("ONT8",result.get(0).destinationWarehouseCode());
|
||||
assertNull(result.get(0).quantity()); assertEquals(20L,result.get(1).quantity());
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
-42
@@ -203,9 +203,13 @@ class WarehouseTransferServiceTest {
|
||||
@Mock WarehouseTransferReceiptCoordinator receiptCoordinator;
|
||||
@Mock com.baiyue.lastleg.fleet.customer.FleetCustomerDirectory customerDirectory;
|
||||
|
||||
private com.baiyue.lastleg.service.CompactBusinessNumberService compactNumbers;
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
compactNumbers = org.mockito.Mockito.mock(com.baiyue.lastleg.service.CompactBusinessNumberService.class);
|
||||
service = new WarehouseTransferService();
|
||||
ReflectionTestUtils.setField(service, "compactNumbers", compactNumbers);
|
||||
org.mockito.Mockito.lenient().when(compactNumbers.next(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.anyString())).thenAnswer(call -> call.getArgument(0) + "-CS-261016102030");
|
||||
ReflectionTestUtils.setField(service, "customerDirectory", customerDirectory);
|
||||
lenient().when(customerDirectory.find("TENANT-A")).thenReturn(
|
||||
new com.baiyue.lastleg.fleet.customer.FleetCustomerDirectory.Customer("TENANT-A", "C-A", "Customer A", null, null));
|
||||
@@ -416,7 +420,7 @@ class WarehouseTransferServiceTest {
|
||||
assertEquals("Customer A", tailOrder.getValue().getCustomerName());
|
||||
assertEquals(WarehouseTransferService.DRAFT, tailOrder.getValue().getCurrentStatus());
|
||||
assertEquals("WAREHOUSE_TRANSFER:DRAFT;RELABEL:PENDING_BINDING", tailOrder.getValue().getSubOrderStatus());
|
||||
assertTrue(tailOrder.getValue().getOrderNo().matches("WT-[0-9A-Z]{25}"));
|
||||
assertTrue(tailOrder.getValue().getOrderNo().matches("ZY-CS-[0-9]{12}"));
|
||||
assertNull(tailOrder.getValue().getTransferWarehouseId());
|
||||
verify(sourceOrders).insert(any(WarehouseTransferSourceOrder.class));
|
||||
verify(relabelApplications, never()).insert(any(RelabelApplication.class));
|
||||
@@ -461,10 +465,45 @@ class WarehouseTransferServiceTest {
|
||||
verifyNoInteractions(transfers);
|
||||
}
|
||||
|
||||
@Test
|
||||
void transferRelabelRejectsUnknownAndForeignOrderCartonsBeforePersistence() {
|
||||
var request = new WarehouseTransferRequests.Create(
|
||||
"IN-1", List.of(11L), "WH-1", null, "FBA", null, "ONT8", null,
|
||||
null, null, null, null, null, null, null, 1,
|
||||
BigDecimal.ZERO, null, null, null, null, null, null, null, true,
|
||||
LocalDateTime.of(2026, 10, 16, 10, 0), "Contact", "123", null, "TRUCK",
|
||||
"carton-ownership", List.of(new WarehouseTransferRequests.Item("SKU-1", "Product", 1, null)),
|
||||
List.of(new WarehouseTransferRequests.RelabelItem("CARTON_LABEL", List.of("FOREIGN-BOX"), "SKU-1", null, 1, "FBA-1", "ONT8", null)));
|
||||
for (var cartons : List.of(List.<InboundSnapshotMapper.SourceCarton>of(),
|
||||
List.of(new InboundSnapshotMapper.SourceCarton("CURRENT-BOX", "SKU-1", null, null, null, null, null)))) {
|
||||
when(inboundSnapshots.sourceCartons("TENANT-A", "WH-1", "IN-1")).thenReturn(cartons);
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.create("TENANT-A", "USER-1", request));
|
||||
assertEquals("当前箱子不存在或不属于当前订单", error.getReason());
|
||||
}
|
||||
when(inboundSnapshots.sourceCartons("TENANT-A", "WH-1", "IN-1"))
|
||||
.thenReturn(List.of(new InboundSnapshotMapper.SourceCarton("FOREIGN-BOX", "SKU-1", null, null, null, null, null)));
|
||||
org.junit.jupiter.api.Assertions.assertDoesNotThrow(() ->
|
||||
ReflectionTestUtils.invokeMethod(service, "validateRelabelRequest", "TENANT-A", request));
|
||||
verifyNoInteractions(transfers);
|
||||
}
|
||||
|
||||
@Test
|
||||
void submittingOldDraftRechecksRelabelCartonOwnership() {
|
||||
var transfer = transfer(WarehouseTransferService.DRAFT);
|
||||
transfer.setNeedRelabel(true);
|
||||
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
|
||||
var binding = new com.baiyue.lastleg.transfer.entity.WarehouseTransferRelabelBinding();
|
||||
binding.setCustomerCartonMark("FOREIGN-BOX");
|
||||
when(relabelBindings.listOrder("TENANT-A", transfer.getId())).thenReturn(List.of(binding));
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.submit("TENANT-A", "WTR-1", "USER-1"));
|
||||
assertEquals("当前箱子不存在或不属于当前订单", error.getReason());
|
||||
verify(transfers, never()).updateById(any(WarehouseTransferOrder.class));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@NullSource
|
||||
@ValueSource(strings = {"NONE"})
|
||||
void transferWithoutDestinationCanBeCreatedAndSubmitted(String destinationType) {
|
||||
void inventoryTransferRequiresKnownDestination(String destinationType) {
|
||||
WarehouseTransferRequests.Create request = new WarehouseTransferRequests.Create(
|
||||
"IN-1", List.of(11L), "WH-1", null, destinationType, null, null, null,
|
||||
null, null, null, null, "123 Pickup Road", null, null, 5,
|
||||
@@ -473,53 +512,23 @@ class WarehouseTransferServiceTest {
|
||||
null, null, null, null, null, "key-no-fba",
|
||||
List.of(new WarehouseTransferRequests.Item("SKU-1", "Product", 5, "MARK-1")), null);
|
||||
|
||||
when(inboundSnapshots.findId("TENANT-A", "IN-1")).thenReturn(101L);
|
||||
when(orders.selectList(any())).thenReturn(List.of(historicalOrder()));
|
||||
WarehouseTransferOrder draft = transfer(WarehouseTransferService.DRAFT);
|
||||
draft.setFbaWarehouseCode(null);
|
||||
when(transfers.findNo(eq("TENANT-A"), anyString())).thenReturn(draft);
|
||||
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(draft);
|
||||
when(orders.selectById(draft.getLastlegOrderId())).thenReturn(tailOrder());
|
||||
when(transferItems.selectList(any())).thenReturn(List.of());
|
||||
when(sourceOrders.selectList(any())).thenReturn(List.of());
|
||||
|
||||
service.create("TENANT-A", "USER-1", request);
|
||||
var result = service.submit("TENANT-A", "WTR-1", "USER-1");
|
||||
|
||||
ArgumentCaptor<WarehouseTransferOrder> created = ArgumentCaptor.forClass(WarehouseTransferOrder.class);
|
||||
verify(transfers).insert(created.capture());
|
||||
assertNull(created.getValue().getDestinationType());
|
||||
assertNull(created.getValue().getFbaWarehouseCode());
|
||||
assertEquals(WarehouseTransferService.PENDING_REVIEW, result.status());
|
||||
verify(relabelApplications, never()).insert(any(RelabelApplication.class));
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.create("TENANT-A","USER-1",request));
|
||||
assertEquals(400,error.getStatusCode().value());
|
||||
verifyNoInteractions(transfers,orders);
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantCanClearDestinationWhenEditingDraft() {
|
||||
WarehouseTransferOrder transfer = transfer(WarehouseTransferService.DRAFT);
|
||||
transfer.setDestinationType("FBA");
|
||||
transfer.setDestinationWarehouseCode("ONT8");
|
||||
LastlegOrder order = tailOrder();
|
||||
when(transfers.lockNo("TENANT-A", "WTR-1")).thenReturn(transfer);
|
||||
when(transfers.findNo("TENANT-A", "WTR-1")).thenReturn(transfer);
|
||||
when(orders.selectById(transfer.getLastlegOrderId())).thenReturn(order);
|
||||
when(transferItems.selectList(any())).thenReturn(List.of());
|
||||
when(sourceOrders.selectList(any())).thenReturn(List.of());
|
||||
void inventoryDraftCannotClearDestination() {
|
||||
var transfer = transfer(WarehouseTransferService.DRAFT);
|
||||
when(transfers.lockNo("TENANT-A","WTR-1")).thenReturn(transfer);
|
||||
WarehouseTransferRequests.Create request = new WarehouseTransferRequests.Create(
|
||||
"IN-1", List.of(11L), "WH-1", null, "NONE", null, null, null,
|
||||
null, null, null, null, "123 Pickup Road", null, null, 5,
|
||||
new BigDecimal("0.2500"), "WAREHOUSE_PICKUP", LocalDateTime.of(2026, 9, 12, 10, 0),
|
||||
null, null, null, null, null, false, null, null, null, null, null, "edit-no-fba",
|
||||
List.of(new WarehouseTransferRequests.Item("SKU-1", "Product", 5, "MARK-1")), null);
|
||||
|
||||
var result = service.updateDraft("TENANT-A", "WTR-1", "USER-1", request);
|
||||
|
||||
assertEquals(WarehouseTransferService.DRAFT, result.status());
|
||||
assertNull(transfer.getDestinationType());
|
||||
assertNull(transfer.getDestinationWarehouseCode());
|
||||
assertNull(transfer.getFbaWarehouseCode());
|
||||
assertNull(order.getFbaWarehouseCode());
|
||||
verify(transfers).updateById(transfer);
|
||||
assertThrows(ResponseStatusException.class, () -> service.updateDraft("TENANT-A","WTR-1","USER-1",request));
|
||||
verify(transfers, never()).updateById(any(WarehouseTransferOrder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -544,7 +553,8 @@ class WarehouseTransferServiceTest {
|
||||
assertEquals("ONT8", transfer.getValue().getFbaWarehouseCode());
|
||||
assertNull(transfer.getValue().getFbaShipmentNo());
|
||||
assertEquals("ONT8", tailOrder.getValue().getFbaWarehouseCode());
|
||||
assertEquals("WAREHOUSE_PICKUP", transfer.getValue().getDeliveryMethod());
|
||||
assertEquals("INVENTORY_TRANSFER", transfer.getValue().getDeliveryMethod());
|
||||
assertNull(transfer.getValue().getEstimatedArrivalAt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -620,7 +630,7 @@ class WarehouseTransferServiceTest {
|
||||
assertEquals(List.of(1, 2, 3, 4, 5), cartons.getAllValues().stream()
|
||||
.map(WarehouseTransferCarton::getCartonIndex).toList());
|
||||
assertTrue(cartons.getAllValues().stream().allMatch(value -> value.getCartonMark()
|
||||
.matches("WT-[0-9A-Z]{25}#5-[1-5]")));
|
||||
.matches("BX-[0-9A-Z]+")));
|
||||
when(transfers.findKey("TENANT-A", request.idempotencyKey())).thenReturn(transfer.getValue());
|
||||
clearInvocations(customerDirectory, orders, inboundOrders);
|
||||
service.create("TENANT-A", "USER-1", request);
|
||||
|
||||
Reference in New Issue
Block a user