优化
This commit is contained in:
+2
-2
@@ -49,12 +49,12 @@ class OceanBookingMapperContractTest {
|
||||
@Test
|
||||
void linkCandidatesUsesOneBoundedSetQueryAndExactRemainingSemantics() throws Exception {
|
||||
String sql = String.join("\n", OceanBookingMapper.class.getDeclaredMethod("selectLinkCandidates",
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page.class, LinkCandidateQuery.class, java.util.Set.class)
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page.class, LinkCandidateQuery.class)
|
||||
.getAnnotation(Select.class).value());
|
||||
assertThat(sql)
|
||||
.contains("booking.status='RELEASED'")
|
||||
.contains("booking.warehouse_id=#{query.warehouseId}")
|
||||
.contains("<foreach collection=\"channelCodes\"", "#{channelCode}")
|
||||
.contains("booking.channel_code=#{query.channelGroupCode}")
|
||||
.contains("requirement.container_type=#{query.containerType}")
|
||||
.contains("FROM fl_ocean_booking_container_allocation")
|
||||
.contains("container.record_status='ACTIVE'")
|
||||
|
||||
+9
-11
@@ -150,7 +150,7 @@ class OceanBookingServiceTest {
|
||||
Detail result = service.create(9L, "admin", "draft-complete", new CreateRequest(0, completeDraft()));
|
||||
|
||||
assertThat(result.oceanBooking().getStatus()).isEqualTo("DRAFT");
|
||||
assertThat(inserted.get().getChannelName()).isEqualTo("美西海运");
|
||||
assertThat(inserted.get().getChannelName()).isEqualTo("美森正班");
|
||||
assertThat(inserted.get().getWarehouseName()).isEqualTo("深圳中转仓");
|
||||
assertThat(inserted.get().getBookingAgentName()).isEqualTo("订舱代理");
|
||||
assertThat(inserted.get().getCustomerId()).isEqualTo(100L);
|
||||
@@ -328,8 +328,8 @@ class OceanBookingServiceTest {
|
||||
void linkCandidatesDefaultsPaginationAndDelegatesOneNormalizedSetQuery() {
|
||||
LinkCandidate candidate = new LinkCandidate(101L, "OB-260818-0001", 201L, "40HQ",
|
||||
new BigDecimal("68"), new BigDecimal("19500"), 3, 1, 2,
|
||||
"客户A", "深圳中转仓", "美西海运");
|
||||
when(repository.linkCandidates(any(), anySet())).thenReturn(new PageResult<>(List.of(candidate), 1, 20, 1, 1));
|
||||
"客户A", "深圳中转仓", "美森正班");
|
||||
when(repository.linkCandidates(any())).thenReturn(new PageResult<>(List.of(candidate), 1, 20, 1, 1));
|
||||
|
||||
PageResult<LinkCandidate> result = service.linkCandidates(new LinkCandidateQuery(701L,
|
||||
" MATSON_CLX ", " 40HQ ", null, null));
|
||||
@@ -337,13 +337,11 @@ class OceanBookingServiceTest {
|
||||
assertThat(result.records()).containsExactly(candidate);
|
||||
assertThat(result.records().get(0).remainingQuantity()).isEqualTo(2);
|
||||
ArgumentCaptor<LinkCandidateQuery> query = ArgumentCaptor.forClass(LinkCandidateQuery.class);
|
||||
@SuppressWarnings("unchecked") ArgumentCaptor<java.util.Set<String>> channels = ArgumentCaptor.forClass(java.util.Set.class);
|
||||
verify(repository).linkCandidates(query.capture(), channels.capture());
|
||||
verify(repository).linkCandidates(query.capture());
|
||||
assertThat(query.getValue().channelGroupCode()).isEqualTo("MATSON_CLX");
|
||||
assertThat(query.getValue().containerType()).isEqualTo("40HQ");
|
||||
assertThat(query.getValue().page()).isEqualTo(1L);
|
||||
assertThat(query.getValue().size()).isEqualTo(20L);
|
||||
assertThat(channels.getValue()).contains("MATSON_CLX_TRUCK", "MATSON_CLX_PARCEL", "ZBYHK");
|
||||
verify(repository, never()).find(anyLong());
|
||||
verify(repository, never()).requirements(anyLong());
|
||||
verify(repository, never()).containers(anyLong());
|
||||
@@ -351,7 +349,7 @@ class OceanBookingServiceTest {
|
||||
|
||||
@Test
|
||||
void linkCandidatesReturnsNormalEmptyPageWithOneSetQueryAndNoDiagnosticFields() {
|
||||
when(repository.linkCandidates(any(), anySet())).thenReturn(new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
when(repository.linkCandidates(any())).thenReturn(new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
|
||||
PageResult<LinkCandidate> result = service.linkCandidates(
|
||||
new LinkCandidateQuery(701L, "MATSON_CLX", "45HQ", null, null));
|
||||
@@ -359,7 +357,7 @@ class OceanBookingServiceTest {
|
||||
assertThat(result.records()).isEmpty();
|
||||
assertThat(result.total()).isZero();
|
||||
assertThat(result.pages()).isZero();
|
||||
verify(repository, times(1)).linkCandidates(any(), anySet());
|
||||
verify(repository, times(1)).linkCandidates(any());
|
||||
assertThat(LinkCandidate.class.getRecordComponents()).extracting(java.lang.reflect.RecordComponent::getName)
|
||||
.doesNotContain("mismatchReasons", "disabledReason", "warehouseId", "channelCode");
|
||||
}
|
||||
@@ -386,7 +384,7 @@ class OceanBookingServiceTest {
|
||||
|
||||
private void stubMasterData() {
|
||||
ChannelRow row = new ChannelRow();
|
||||
row.setPriceBookVersionId(51L); row.setChannelCode("SEA-US"); row.setChannelName("美西海运");
|
||||
row.setPriceBookVersionId(51L); row.setChannelCode("MATSON_CLX_TRUCK"); row.setChannelName("美森正班海卡");
|
||||
row.setPriceModel("FBA_WAREHOUSE_RATE");
|
||||
when(priceBooks.activeVersionId()).thenReturn(51L);
|
||||
when(priceBooks.channels(51L, 701L)).thenReturn(List.of(row));
|
||||
@@ -406,7 +404,7 @@ class OceanBookingServiceTest {
|
||||
}
|
||||
|
||||
private static DraftData completeDraft() {
|
||||
return new DraftData(100L, "客户", "SEA-US", 701L, "BL-001", 71L, "船公司", "MATSON",
|
||||
return new DraftData(100L, "客户", "MATSON_CLX", 701L, "BL-001", 71L, "船公司", "MATSON",
|
||||
81L, null, "VESSEL", "V001", "CNSZX", "深圳", "USLAX", "洛杉矶",
|
||||
"LAX", LocalDateTime.of(2026, 9, 1, 0, 0),
|
||||
LocalDateTime.of(2026, 9, 20, 0, 0), null,
|
||||
@@ -419,7 +417,7 @@ class OceanBookingServiceTest {
|
||||
|
||||
private static OceanBookingEntity completeBooking(String status, int version) {
|
||||
OceanBookingEntity value = booking(status, version);
|
||||
value.setCustomerId(100L); value.setCustomerName("客户"); value.setChannelCode("SEA-US");
|
||||
value.setCustomerId(100L); value.setCustomerName("客户"); value.setChannelCode("MATSON_CLX");
|
||||
value.setWarehouseId(701L); value.setBillOfLadingNo("BL-001"); value.setShippingCompanyId(71L);
|
||||
value.setCarrierCode("MATSON");
|
||||
value.setBookingAgentId(81L); value.setVesselName("VESSEL"); value.setVoyageNo("V001");
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ class ContainerBookingMapperContractTest {
|
||||
.filter(candidate -> candidate.getName().equals("linkReleasedBooking"))
|
||||
.findFirst().orElseThrow();
|
||||
String sql = String.join("\n", method.getAnnotation(Update.class).value());
|
||||
assertThat(sql).doesNotContain("channel_code=#{channelCode}", "channel_name=#{channelName}");
|
||||
var parameterNames = Arrays.stream(method.getParameters())
|
||||
.map(parameter -> parameter.getAnnotation(Param.class).value())
|
||||
.toList();
|
||||
|
||||
@@ -207,7 +207,7 @@ class ContainerServiceTest {
|
||||
container.setWarehouseId(101L); container.setChannelGroupCode("EXX"); container.setChannelCode(null); container.setContainerType("40HQ");
|
||||
container.setCapacityCbm(new BigDecimal("85.5000")); container.setMaxWeightKg(new BigDecimal("27500.000"));
|
||||
OceanBookingEntity booking = new OceanBookingEntity();
|
||||
booking.setId(21L); booking.setStatus("RELEASED"); booking.setWarehouseId(101L); booking.setChannelCode("EXX_RAIL_NY");
|
||||
booking.setId(21L); booking.setStatus("RELEASED"); booking.setWarehouseId(101L); booking.setChannelCode("EXX");
|
||||
OceanBookingContainerRequirementEntity requirement = new OceanBookingContainerRequirementEntity();
|
||||
requirement.setId(31L); requirement.setQuantity(1); requirement.setContainerType("40HQ"); requirement.setCapacityCbm(new BigDecimal("68.0000")); requirement.setMaxWeightKg(new BigDecimal("19500.000"));
|
||||
when(repository.find(11L)).thenReturn(container, container);
|
||||
@@ -319,7 +319,7 @@ class ContainerServiceTest {
|
||||
second.setChannelGroupCode("MATSON_CLX"); second.setChannelCode(null); second.setContainerType("40HQ");
|
||||
OceanBookingEntity oceanBooking = new OceanBookingEntity();
|
||||
oceanBooking.setId(21L); oceanBooking.setStatus("RELEASED");
|
||||
oceanBooking.setWarehouseId(101L); oceanBooking.setChannelCode("MATSON_CLX_TRUCK");
|
||||
oceanBooking.setWarehouseId(101L); oceanBooking.setChannelCode("MATSON_CLX");
|
||||
OceanBookingContainerRequirementEntity requirement = new OceanBookingContainerRequirementEntity();
|
||||
requirement.setId(31L); requirement.setQuantity(2); requirement.setContainerType("40HQ");
|
||||
when(repository.find(11L)).thenReturn(first);
|
||||
@@ -362,19 +362,19 @@ class ContainerServiceTest {
|
||||
@Test
|
||||
@DisplayName("首次关联拒绝装柜仓库不一致")
|
||||
void rejectsLinkWhenWarehouseDiffers() {
|
||||
assertThreeFieldMismatch(102L, "MATSON_CLX_TRUCK", "40HQ");
|
||||
assertThreeFieldMismatch(102L, "MATSON_CLX", "40HQ");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("首次关联拒绝物流渠道不一致")
|
||||
void rejectsLinkWhenChannelDiffers() {
|
||||
assertThreeFieldMismatch(101L, "HEDE_TRUCK", "40HQ");
|
||||
assertThreeFieldMismatch(101L, "HEDE", "40HQ");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("首次关联拒绝柜型不一致")
|
||||
void rejectsLinkWhenContainerTypeDiffers() {
|
||||
assertThreeFieldMismatch(101L, "MATSON_CLX_TRUCK", "45HQ");
|
||||
assertThreeFieldMismatch(101L, "MATSON_CLX", "45HQ");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -443,7 +443,7 @@ class ContainerServiceTest {
|
||||
container.setContainerType("40HQ");
|
||||
OceanBookingEntity oceanBooking = new OceanBookingEntity();
|
||||
oceanBooking.setId(21L); oceanBooking.setStatus("RELEASED");
|
||||
oceanBooking.setWarehouseId(101L); oceanBooking.setChannelCode("MATSON_CLX_TRUCK");
|
||||
oceanBooking.setWarehouseId(101L); oceanBooking.setChannelCode("MATSON_CLX");
|
||||
OceanBookingContainerRequirementEntity requirement = new OceanBookingContainerRequirementEntity();
|
||||
requirement.setId(31L); requirement.setQuantity(2); requirement.setContainerType("40HQ");
|
||||
when(repository.find(11L)).thenReturn(container);
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.event.*;
|
||||
import com.baiyue.firstleg.client.OrderFulfillmentCompletionClient;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.mapper.ContainerEventInboxMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class OverseasDeliveryCompletedConsumerTest {
|
||||
@Test
|
||||
void completesOnlyEventSourceInboundAndOrder() {
|
||||
InboundOrderMapper inbounds = mock(InboundOrderMapper.class);
|
||||
InboundStatusHistoryMapper histories = mock(InboundStatusHistoryMapper.class);
|
||||
ContainerEventInboxMapper inbox = mock(ContainerEventInboxMapper.class);
|
||||
OrderFulfillmentCompletionClient orders = mock(OrderFulfillmentCompletionClient.class);
|
||||
ObjectMapper json = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||
OverseasDeliveryCompletedConsumer consumer = new OverseasDeliveryCompletedConsumer(
|
||||
inbounds, histories, inbox, orders, json);
|
||||
ReflectionTestUtils.setField(consumer, "internalToken", "token");
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
inbound.setId(101L); inbound.setTenantId(88L); inbound.setOrderId(201L);
|
||||
inbound.setOrderNo("FL-201"); inbound.setInboundCode("IN-1"); inbound.setDestinationCode("ONT8");
|
||||
inbound.setProcessStatus("LOADED");
|
||||
when(inbounds.selectActiveByIdForUpdate(101L)).thenReturn(inbound);
|
||||
when(inbounds.completeOverseasDelivery(eq(88L), eq(101L), any())).thenReturn(1);
|
||||
when(inbounds.countNotDeliveredByOrder(88L, 201L)).thenReturn(0);
|
||||
when(orders.complete(eq("token"), any())).thenReturn(ApiResponse.success(
|
||||
new OrderFulfillmentCompletionClient.Result(201L, "COMPLETED", false)));
|
||||
|
||||
consumer.consume(event(json));
|
||||
|
||||
verify(inbounds).completeOverseasDelivery(eq(88L), eq(101L), any());
|
||||
verify(orders).complete(eq("token"), argThat(request ->
|
||||
"201".equals(request.orderId()) && "IN-1".equals(request.inboundCode())
|
||||
&& "DL-ONT8".equals(request.deliveryNo())));
|
||||
verify(inbounds).markOrderSnapshotCompleted(eq(88L), eq(201L), any());
|
||||
verify(inbounds, never()).completeOverseasDelivery(eq(88L), eq(102L), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void leavesOrderOpenWhileAnotherSourceInboundIsNotDelivered() {
|
||||
InboundOrderMapper inbounds = mock(InboundOrderMapper.class);
|
||||
InboundStatusHistoryMapper histories = mock(InboundStatusHistoryMapper.class);
|
||||
ContainerEventInboxMapper inbox = mock(ContainerEventInboxMapper.class);
|
||||
OrderFulfillmentCompletionClient orders = mock(OrderFulfillmentCompletionClient.class);
|
||||
ObjectMapper json = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||
OverseasDeliveryCompletedConsumer consumer = new OverseasDeliveryCompletedConsumer(
|
||||
inbounds, histories, inbox, orders, json);
|
||||
ReflectionTestUtils.setField(consumer, "internalToken", "token");
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
inbound.setId(101L); inbound.setTenantId(88L); inbound.setOrderId(201L);
|
||||
inbound.setOrderNo("FL-201"); inbound.setInboundCode("IN-1"); inbound.setDestinationCode("ONT8");
|
||||
inbound.setProcessStatus("LOADED");
|
||||
when(inbounds.selectActiveByIdForUpdate(101L)).thenReturn(inbound);
|
||||
when(inbounds.completeOverseasDelivery(eq(88L), eq(101L), any())).thenReturn(1);
|
||||
when(inbounds.countNotDeliveredByOrder(88L, 201L)).thenReturn(1);
|
||||
|
||||
consumer.consume(event(json));
|
||||
|
||||
verifyNoInteractions(orders);
|
||||
verify(inbounds, never()).markOrderSnapshotCompleted(anyLong(), anyLong(), any());
|
||||
}
|
||||
|
||||
private EventEnvelope event(ObjectMapper json) {
|
||||
Instant time = Instant.parse("2026-09-15T08:00:00Z");
|
||||
var payload = new OverseasDeliveryCompletedV1("1", "DL-ONT8", "11", "LM-11",
|
||||
"101", "IN-1", "201", "FL-201", "201", "ONT8", time);
|
||||
var node = json.valueToTree(payload);
|
||||
return new EventEnvelope("00000000-0000-4000-8000-000000000001",
|
||||
EventTypes.OVERSEAS_DELIVERY_COMPLETED, 1, time, RegionCode.OVERSEAS, RegionCode.CN,
|
||||
"88", "INBOUND_ORDER", "101", 2L, 1L,
|
||||
"00000000-0000-4000-8000-000000000099", "delivery-101", null, node,
|
||||
EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(node)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user