修改提交
This commit is contained in:
+1
-1
@@ -89,7 +89,7 @@ class InboundPlanServiceTest {
|
||||
assertEquals(1, allocations.getAllValues().stream()
|
||||
.filter(item -> "PENDING_COUNT".equals(item.getStatus())).count());
|
||||
verify(orderMapper).markPlanned(any(), org.mockito.ArgumentMatchers.eq(2L), any(), org.mockito.ArgumentMatchers.anyInt(), any());
|
||||
verify(orderMapper).insertHistory(org.mockito.ArgumentMatchers.eq(2L), any(), any(), any());
|
||||
verify(orderMapper).insertHistory(any(), org.mockito.ArgumentMatchers.eq(2L), any(), any(), any());
|
||||
verify(orderMapper).lockOrder("100", 2L);
|
||||
assertEquals(2L, result.sourceOrderId());
|
||||
assertEquals("CONT-1", result.containerNo());
|
||||
|
||||
+2
@@ -17,5 +17,7 @@ class LocalLooseboardSchemaContractTest {
|
||||
assertTrue(sql.contains("CREATE TABLE IF NOT EXISTS ll_local_looseboard_history"));
|
||||
assertTrue(sql.contains("operation_type VARCHAR(32) NOT NULL"));
|
||||
assertTrue(sql.contains("uk_ll_local_looseboard_no(customer_id,order_no)"));
|
||||
assertTrue(sql.contains("lastleg_order_id BIGINT NULL"));
|
||||
assertTrue(sql.contains("uk_ll_local_looseboard_lastleg(lastleg_order_id)"));
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -5,6 +5,10 @@ import com.baiyue.lastleg.looseboard.entity.LocalLooseboardHistory;
|
||||
import com.baiyue.lastleg.looseboard.entity.LocalLooseboardOrder;
|
||||
import com.baiyue.lastleg.looseboard.mapper.LocalLooseboardHistoryMapper;
|
||||
import com.baiyue.lastleg.looseboard.mapper.LocalLooseboardOrderMapper;
|
||||
import com.baiyue.lastleg.entity.LastlegOrder;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -31,6 +35,9 @@ import static org.mockito.Mockito.when;
|
||||
class LocalLooseboardServiceTest {
|
||||
@Mock LocalLooseboardOrderMapper orders;
|
||||
@Mock LocalLooseboardHistoryMapper histories;
|
||||
@Mock LastlegOrderMapper lastlegOrders;
|
||||
@Mock LastlegOrderStatusHistoryMapper lastlegHistories;
|
||||
@Mock LastlegOrderNoGenerator lastlegOrderNoGenerator;
|
||||
private LocalLooseboardService service;
|
||||
|
||||
@BeforeEach
|
||||
@@ -38,7 +45,11 @@ class LocalLooseboardServiceTest {
|
||||
service = new LocalLooseboardService();
|
||||
ReflectionTestUtils.setField(service, "orders", orders);
|
||||
ReflectionTestUtils.setField(service, "histories", histories);
|
||||
ReflectionTestUtils.setField(service, "lastlegOrders", lastlegOrders);
|
||||
ReflectionTestUtils.setField(service, "lastlegHistories", lastlegHistories);
|
||||
ReflectionTestUtils.setField(service, "lastlegOrderNoGenerator", lastlegOrderNoGenerator);
|
||||
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper().findAndRegisterModules());
|
||||
org.mockito.Mockito.lenient().when(lastlegOrderNoGenerator.next()).thenReturn("LMO-LOOSE-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,6 +67,9 @@ class LocalLooseboardServiceTest {
|
||||
assertEquals("100", detail.summary().customerId());
|
||||
assertEquals(LocalLooseboardService.PENDING_ACCEPTANCE, detail.summary().status());
|
||||
assertEquals("SHARED_TRUCK", detail.summary().transportMode());
|
||||
verify(lastlegOrders).insert(org.mockito.ArgumentMatchers.<LastlegOrder>argThat(value ->
|
||||
"LOCAL_LOOSEBOARD".equals(value.getOrderType())
|
||||
&& "LOCAL_LOOSEBOARD:PENDING_ACCEPTANCE".equals(value.getSubOrderStatus())));
|
||||
verify(histories).insert(org.mockito.ArgumentMatchers.<LocalLooseboardHistory>argThat(value ->
|
||||
"CREATE".equals(value.getOperationType())));
|
||||
}
|
||||
|
||||
@@ -15,5 +15,7 @@ class LastlegOrderTypeTest {
|
||||
Arrays.stream(LastlegOrderType.values()).map(Enum::name).toList());
|
||||
assertEquals("换标下单", LastlegOrderType.RELABEL_APPLICATION.label());
|
||||
assertEquals("本土散板", LastlegOrderType.LOCAL_LOOSEBOARD.label());
|
||||
assertEquals("一件代发", LastlegOrderType.labelOf("ONE_CLICK_DROPSHIP"));
|
||||
assertEquals("LEGACY_TYPE", LastlegOrderType.labelOf("LEGACY_TYPE"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ class LastlegOrderServiceTest {
|
||||
|
||||
assertEquals(11L, response.order().id());
|
||||
assertEquals("100", response.order().customerId());
|
||||
assertEquals("ONE_CLICK_DROPSHIP", response.order().orderType());
|
||||
assertEquals("一件代发", response.order().orderTypeName());
|
||||
assertTrue(java.util.Arrays.stream(response.getClass().getRecordComponents())
|
||||
.noneMatch(component -> "dropshipPallets".equals(component.getName())));
|
||||
assertTrue(java.util.Arrays.stream(com.baiyue.lastleg.dto.LastlegOrderDetailResponse.History.class.getRecordComponents())
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ package com.baiyue.lastleg.service;
|
||||
import com.baiyue.common.event.*; import com.baiyue.lastleg.entity.*; import com.baiyue.lastleg.mapper.*; import com.baiyue.lastleg.dropship.dto.DropshipRequests; import com.baiyue.lastleg.dropship.service.DropshipOrderService; import com.baiyue.lastleg.inboundplan.dto.InboundPlanResponse; import com.baiyue.lastleg.inboundplan.mapper.InboundPlanCartonMapper; import com.baiyue.lastleg.inboundplan.service.InboundPlanService; import com.baiyue.lastleg.inventory.command.dto.InventoryCommandRequests; import com.baiyue.lastleg.inventory.command.service.InventoryCommandService; import com.fasterxml.jackson.databind.*; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.*; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.time.Instant; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*;
|
||||
@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class)
|
||||
class LoadingCompletedConsumerTest {
|
||||
@Mock LastlegEventInboxMapper inbox; @Mock LastlegOrderMapper orders; @Mock LastlegOrderDetailMapper details; @Mock LastlegOrderStatusHistoryMapper histories; @Mock InboundPlanCartonMapper cartons; @Mock DropshipOrderService dropshipOrders; @Mock InboundPlanService inboundPlans; @Mock InventoryCommandService inventory; ObjectMapper json=new ObjectMapper().findAndRegisterModules(); LoadingCompletedConsumer service;
|
||||
@BeforeEach void setup(){ service=new LoadingCompletedConsumer(); ReflectionTestUtils.setField(service,"inboxMapper",inbox); ReflectionTestUtils.setField(service,"orderMapper",orders); ReflectionTestUtils.setField(service,"detailMapper",details); ReflectionTestUtils.setField(service,"historyMapper",histories); ReflectionTestUtils.setField(service,"cartonMapper",cartons); ReflectionTestUtils.setField(service,"dropshipOrders",dropshipOrders); ReflectionTestUtils.setField(service,"inboundPlans",inboundPlans); ReflectionTestUtils.setField(service,"inventory",inventory); ReflectionTestUtils.setField(service,"objectMapper",json); ReflectionTestUtils.setField(service,"orderNoGenerator",new LastlegOrderNoGenerator()); lenient().doAnswer(i->{ LastlegOrder o=i.getArgument(0); o.setId(Math.abs(o.getSourceInboundId().hashCode())+1L); return 1; }).when(orders).insert(any(LastlegOrder.class)); lenient().when(inboundPlans.convert(anyString(),anyLong())).thenReturn(new InboundPlanResponse(1L,"LIP-1","100",1L,"MSCU1","PENDING_ASSIGNMENT",1,1,BigDecimal.ONE,List.of(),List.of(),List.of())); }
|
||||
@Mock LastlegEventInboxMapper inbox; @Mock LastlegOrderMapper orders; @Mock LastlegInboundOrderMapper inboundOrders; @Mock LastlegOrderDetailMapper details; @Mock LastlegOrderStatusHistoryMapper histories; @Mock InboundPlanCartonMapper cartons; @Mock DropshipOrderService dropshipOrders; @Mock InboundPlanService inboundPlans; @Mock InventoryCommandService inventory; ObjectMapper json=new ObjectMapper().findAndRegisterModules(); LoadingCompletedConsumer service;
|
||||
@BeforeEach void setup(){ service=new LoadingCompletedConsumer(); ReflectionTestUtils.setField(service,"inboxMapper",inbox); ReflectionTestUtils.setField(service,"orderMapper",orders); ReflectionTestUtils.setField(service,"inboundOrderMapper",inboundOrders); ReflectionTestUtils.setField(service,"detailMapper",details); ReflectionTestUtils.setField(service,"historyMapper",histories); ReflectionTestUtils.setField(service,"cartonMapper",cartons); ReflectionTestUtils.setField(service,"dropshipOrders",dropshipOrders); ReflectionTestUtils.setField(service,"inboundPlans",inboundPlans); ReflectionTestUtils.setField(service,"inventory",inventory); ReflectionTestUtils.setField(service,"objectMapper",json); ReflectionTestUtils.setField(service,"orderNoGenerator",new LastlegOrderNoGenerator()); lenient().doAnswer(i->{ LastlegOrder o=i.getArgument(0); o.setId(Math.abs(o.getSourceInboundId().hashCode())+1L); return 1; }).when(orders).insert(any(LastlegOrder.class)); lenient().when(inboundPlans.convert(anyString(),anyLong())).thenReturn(new InboundPlanResponse(1L,"LIP-1","100",1L,"MSCU1","PENDING_ASSIGNMENT",1,1,BigDecimal.ONE,List.of(),List.of(),List.of())); }
|
||||
@Test void createsOneOrderAndOneInboundPlanPerInbound(){ EventEnvelope event=event(); assertEquals(2,service.consume(event)); verify(orders,times(2)).insert(any(LastlegOrder.class)); verify(inboundPlans,times(2)).convert(eq("100"),anyLong()); verify(inventory,times(2)).registerInTransit(eq("100"),eq("SYSTEM"),any(InventoryCommandRequests.InTransit.class)); verify(details,times(2)).insert(any(LastlegOrderDetail.class)); verify(histories,times(2)).insert(any(LastlegOrderStatusHistory.class)); ArgumentCaptor<LastlegOrder> c=ArgumentCaptor.forClass(LastlegOrder.class); verify(orders,times(2)).insert(c.capture()); assertEquals(Set.of("in-1","in-2"),c.getAllValues().stream().map(LastlegOrder::getSourceInboundId).collect(java.util.stream.Collectors.toSet())); assertTrue(c.getAllValues().stream().allMatch(o->"PENDING_ASSIGNMENT".equals(o.getCurrentStatus()))); assertTrue(c.getAllValues().stream().allMatch(o->o.getId()!=null)); assertTrue(c.getAllValues().stream().allMatch(o->"MSCU1".equals(o.getContainerNo()))); assertEquals(1,c.getAllValues().stream().map(LastlegOrder::getOrderNo).distinct().count()); assertEquals(new LastlegOrderNoGenerator().forContainerNo("MSCU1"),c.getAllValues().get(0).getOrderNo()); }
|
||||
@Test void repeatedEventReturnsExistingEffect(){ EventEnvelope event=event(); LastlegEventInbox row=new LastlegEventInbox(); row.setPayloadHash(event.payloadHash()); when(inbox.selectById(event.eventId())).thenReturn(row); when(orders.countContainer("100","MSCU1")).thenReturn(2L); assertEquals(2,service.consume(event)); verify(orders).countContainer("100","MSCU1"); verify(orders,never()).insert(any(LastlegOrder.class)); verify(details,never()).insert(any(LastlegOrderDetail.class)); }
|
||||
@Test void sameEventWithDifferentHashIsRejected(){ EventEnvelope event=event(); LastlegEventInbox row=new LastlegEventInbox(); row.setPayloadHash("sha256:"+"0".repeat(64)); when(inbox.selectById(event.eventId())).thenReturn(row); assertThrows(IllegalArgumentException.class,()->service.consume(event)); }
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package com.baiyue.lastleg.service;
|
||||
|
||||
import com.baiyue.common.event.EventEnvelope;
|
||||
import com.baiyue.lastleg.dropship.service.DropshipOrderService;
|
||||
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
|
||||
import com.baiyue.lastleg.inboundplan.service.InboundPlanService;
|
||||
import com.baiyue.lastleg.inventory.command.service.InventoryCommandService;
|
||||
import com.baiyue.lastleg.looseboard.dto.LocalLooseboardRequests;
|
||||
import com.baiyue.lastleg.looseboard.service.LocalLooseboardService;
|
||||
import com.baiyue.lastleg.relabel.dto.RelabelRequests;
|
||||
import com.baiyue.lastleg.relabel.service.RelabelApplicationService;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
|
||||
import com.baiyue.lastleg.transfer.service.WarehouseTransferService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
@SpringBootTest(classes = TaillegRealConsumerAcceptanceTest.AcceptanceApplication.class,
|
||||
webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = {
|
||||
"spring.sql.init.mode=never", "spring.cloud.nacos.discovery.enabled=false",
|
||||
"spring.cloud.nacos.discovery.register-enabled=false", "spring.cloud.nacos.config.enabled=false",
|
||||
"spring.cloud.nacos.config.import-check.enabled=false", "spring.task.scheduling.enabled=false"
|
||||
})
|
||||
@EnabledIfSystemProperty(named = "tailleg.real.consumer", matches = "true")
|
||||
class TaillegRealConsumerAcceptanceTest {
|
||||
static final String CUSTOMER = "990022";
|
||||
static final String MARKER = "REAL-TAIL-20260822-R3";
|
||||
static final String EVENT_KEY = "FIRSTLEG_LOADING_COMPLETED:990022022:990022:2";
|
||||
static final LocalDateTime RELABEL_DEADLINE = LocalDateTime.of(2026, 8, 29, 11, 1, 21, 628_000_000);
|
||||
static final LocalDateTime TRANSFER_ETA = LocalDateTime.of(2026, 9, 1, 11, 1, 21, 674_000_000);
|
||||
static final LocalDateTime RETURN_RELABEL_ETA = LocalDateTime.of(2026, 9, 1, 11, 1, 21, 756_000_000);
|
||||
static final LocalDate REQUESTED_DATE = LocalDate.of(2026, 8, 25);
|
||||
|
||||
@Autowired JdbcTemplate jdbc;
|
||||
@Autowired ObjectMapper json;
|
||||
@Autowired LoadingCompletedConsumer consumer;
|
||||
@Autowired RelabelApplicationService relabel;
|
||||
@Autowired WarehouseTransferService transfer;
|
||||
@Autowired LocalLooseboardService looseboard;
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration(excludeName = "com.baiyue.common.security.BaiyueSecurityAutoConfiguration")
|
||||
@Import({LoadingCompletedConsumer.class, LastlegOrderNoGenerator.class, DropshipOrderService.class,
|
||||
InboundPlanService.class, InventoryCommandService.class, RelabelApplicationService.class,
|
||||
WarehouseTransferService.class, LocalLooseboardService.class})
|
||||
@MapperScan({"com.baiyue.lastleg.mapper", "com.baiyue.lastleg.dropship.mapper",
|
||||
"com.baiyue.lastleg.inboundplan.mapper", "com.baiyue.lastleg.inventory.mapper",
|
||||
"com.baiyue.lastleg.inventory.command.mapper", "com.baiyue.lastleg.relabel.mapper",
|
||||
"com.baiyue.lastleg.transfer.mapper", "com.baiyue.lastleg.looseboard.mapper"})
|
||||
static class AcceptanceApplication {
|
||||
@Bean WarehouseResourceGateway warehouseResourceGateway() {
|
||||
return new WarehouseResourceGateway() {
|
||||
public WarehousePalletReference ensureDropshipPallet(String customerId, long warehouseId, String businessId) {
|
||||
return new WarehousePalletReference(1L, "UNUSED", 1L);
|
||||
}
|
||||
public long reserve(String customerId, long warehouseId, long palletId, long locationId,
|
||||
String businessType, String businessId, String reservationKey) { return 1L; }
|
||||
public void scrap(String customerId, long resourceLockId) { }
|
||||
public void scrapPallet(String customerId, long palletId) { }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void consumesRealOutboxAndCreatesEveryTaillegOrderType() throws Exception {
|
||||
String envelopeJson = jdbc.queryForObject(
|
||||
"SELECT payload_json FROM baiyue_firstleg.fl_inbound_outbox WHERE event_key=?", String.class, EVENT_KEY);
|
||||
EventEnvelope envelope = json.readValue(envelopeJson, EventEnvelope.class);
|
||||
assertEquals(2, consumer.consume(envelope));
|
||||
|
||||
Long sourceOrderId = jdbc.queryForObject("SELECT id FROM ll_order WHERE customer_id=? AND " +
|
||||
"source_loading_plan_id='990022022' AND order_type='FIRST_LEG'", Long.class, CUSTOMER);
|
||||
String inboundCode = jdbc.queryForObject("SELECT inbound_code FROM ll_order WHERE id=?", String.class, sourceOrderId);
|
||||
assertNotNull(jdbc.queryForObject("SELECT id FROM ll_inbound_order WHERE customer_id=? AND inbound_code=?",
|
||||
Long.class, CUSTOMER, inboundCode));
|
||||
|
||||
if (!exists("ll_relabel_application", MARKER + "-RELABEL-KEY")) {
|
||||
relabel.create(CUSTOMER, "real-acceptance", new RelabelRequests.Create(
|
||||
MARKER + "-RELABEL", "92", RELABEL_DEADLINE, "验收联系人", "13800000000",
|
||||
MARKER, MARKER + "-RELABEL-KEY", List.of(new RelabelRequests.Item("SKU-REAL-A", null, null,
|
||||
null, "真实验收商品", 3, 3, MARKER + "-SHIP", MARKER + "-TRACK", "SKU-REAL-A-NEW",
|
||||
"换标验收", null, null, null))));
|
||||
}
|
||||
|
||||
createTransfer(sourceOrderId, inboundCode, false, "TRANSFER");
|
||||
createTransfer(sourceOrderId, inboundCode, true, "RETURN-RELABEL");
|
||||
|
||||
if (!exists("ll_local_looseboard_order", MARKER + "-LOOSEBOARD-KEY")) {
|
||||
looseboard.create(CUSTOMER, "real-acceptance", new LocalLooseboardRequests.Create(
|
||||
"SHARED_TRUCK", "YES", "WAREHOUSE_TO_WAREHOUSE", "洛杉矶海外仓", "Los Angeles",
|
||||
"ONT8", "FBA ONT8", "40HQ", 3, new BigDecimal("30.00"), new BigDecimal("0.40"),
|
||||
new BigDecimal("120.00"), "USD", "验收联系人", "13800000000", REQUESTED_DATE,
|
||||
MARKER, MARKER + "-LOOSEBOARD-KEY"));
|
||||
}
|
||||
|
||||
assertEquals(6, jdbc.queryForObject("SELECT COUNT(DISTINCT order_type) FROM ll_order WHERE customer_id=? " +
|
||||
"AND (source_loading_plan_id='990022022' OR source_event_id LIKE ? OR customer_remark=?)",
|
||||
Integer.class, CUSTOMER, "%" + MARKER + "%", MARKER));
|
||||
}
|
||||
|
||||
private void createTransfer(Long sourceOrderId, String inboundCode, boolean needRelabel, String suffix) {
|
||||
String idempotencyKey = MARKER + "-" + suffix + "-KEY";
|
||||
if (exists("ll_warehouse_transfer_order", idempotencyKey)) return;
|
||||
transfer.create(CUSTOMER, "real-acceptance", new WarehouseTransferRequests.Create(
|
||||
inboundCode, List.of(sourceOrderId), "92", needRelabel ? "LAX9" : "ONT8", "真实验收目的地址",
|
||||
3, new BigDecimal("0.40"), "TRUCK", needRelabel ? RETURN_RELABEL_ETA : TRANSFER_ETA,
|
||||
MARKER + "-SHIP-" + suffix,
|
||||
MARKER + "-TRACK", MARKER + "-BOXES", MARKER, needRelabel, idempotencyKey,
|
||||
List.of(new WarehouseTransferRequests.Item("SKU-REAL-A", "真实验收商品", 3, MARKER + "-MARK"))));
|
||||
}
|
||||
|
||||
private boolean exists(String table, String idempotencyKey) {
|
||||
return jdbc.queryForObject("SELECT COUNT(*) FROM " + table + " WHERE customer_id=? AND idempotency_key=?",
|
||||
Integer.class, CUSTOMER, idempotencyKey) == 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user