优化
This commit is contained in:
+49
-5
@@ -3,12 +3,17 @@ package com.baiyue.firstleg.repository;
|
||||
import com.baiyue.firstleg.mapper.SmartLoadingCandidateMapper;
|
||||
import com.baiyue.firstleg.dto.SmartLoadingDtos.Candidate;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.firstleg.dto.SmartLoadingDtos.WorkbenchContainerQuery;
|
||||
import com.baiyue.firstleg.dto.SmartLoadingDtos.InboundCandidateQuery;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -53,15 +58,54 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalCandidateQueryHasOptionalWarehouseAndNoContainerJoin() throws Exception {
|
||||
Method list = SmartLoadingCandidateMapper.class.getDeclaredMethod("globalCandidates", Long.class);
|
||||
String sql = String.join(" ", list.getAnnotation(Select.class).value());
|
||||
void globalCandidateQueryPagesUnitsBeforeLoadingDetailsAndHasNoContainerJoin() throws Exception {
|
||||
Method units = SmartLoadingCandidateMapper.class.getDeclaredMethod("globalCandidateUnits",
|
||||
Page.class, InboundCandidateQuery.class, Set.class);
|
||||
String unitSql = String.join(" ", units.getAnnotation(Select.class).value());
|
||||
Method details = SmartLoadingCandidateMapper.class.getDeclaredMethod(
|
||||
"globalCandidatesByUnits", List.class);
|
||||
String detailSql = String.join(" ", details.getAnnotation(Select.class).value());
|
||||
|
||||
assertThat(sql)
|
||||
.contains("#{warehouseId} IS NULL OR o.warehouse_id=#{warehouseId}")
|
||||
assertThat(unitSql)
|
||||
.contains("#{query.warehouseId} IS NULL OR o.warehouse_id=#{query.warehouseId}")
|
||||
.contains("o.channel_code IN")
|
||||
.contains("o.process_status='WAIT_SPLIT'")
|
||||
.contains("current_group.id groupId")
|
||||
.contains("group_member_count.group_id=current_group.id")
|
||||
.contains("availablePackageCount=current_member.full_package_count")
|
||||
.doesNotContain("fl_container_booking")
|
||||
.doesNotContain("bookingId");
|
||||
assertThat(detailSql)
|
||||
.contains("collection=\"units\"")
|
||||
.contains("current_group.id=#{unit.groupId}")
|
||||
.contains("o.tenant_id=#{unit.accountId}")
|
||||
.contains("o.id=#{unit.inboundId}")
|
||||
.doesNotContain("fl_container_booking");
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalCandidateDynamicSqlRendersForStandaloneAndGroupedUnits() throws Exception {
|
||||
Configuration configuration = new Configuration();
|
||||
XMLLanguageDriver driver = new XMLLanguageDriver();
|
||||
Method units = SmartLoadingCandidateMapper.class.getDeclaredMethod("globalCandidateUnits",
|
||||
Page.class, InboundCandidateQuery.class, Set.class);
|
||||
String unitScript = String.join(" ", units.getAnnotation(Select.class).value());
|
||||
var query = new InboundCandidateQuery(List.of("MATSON_CLX"), 100L, 9L, "IN-",
|
||||
java.time.LocalDate.parse("2026-09-01"), java.time.LocalDate.parse("2026-09-30"),
|
||||
null, 1, 20);
|
||||
String renderedUnits = driver.createSqlSource(configuration, unitScript, Map.class)
|
||||
.getBoundSql(Map.of("query", query, "actualChannels", Set.of("MATSON_CLX_TRUCK"))).getSql();
|
||||
assertThat(renderedUnits).contains("o.channel_code IN", "DATE(eligible.expectedArrivalAt)");
|
||||
|
||||
Method details = SmartLoadingCandidateMapper.class.getDeclaredMethod(
|
||||
"globalCandidatesByUnits", List.class);
|
||||
String detailScript = String.join(" ", details.getAnnotation(Select.class).value());
|
||||
List<SmartLoadingCandidateMapper.CandidateUnit> page = List.of(
|
||||
new SmartLoadingCandidateMapper.CandidateUnit(null, 9L, 10L, null, 10L),
|
||||
new SmartLoadingCandidateMapper.CandidateUnit(700L, null, null, null, 11L));
|
||||
String renderedDetails = driver.createSqlSource(configuration, detailScript, Map.class)
|
||||
.getBoundSql(Map.of("units", page)).getSql();
|
||||
assertThat(renderedDetails).contains("current_group.id=?", "o.tenant_id=?", "o.id=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+20
@@ -100,6 +100,26 @@ class SmartLoadingSqlContractTest {
|
||||
.doesNotContain("split_item.source_measurement_item_id=i.id");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("全局候选分页具备平台维度和关联明细索引")
|
||||
void shouldProvideGlobalCandidatePagingIndexes() throws Exception {
|
||||
assertThat(new ClassPathResource("db/phase2-inbound-schema.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8))
|
||||
.contains("idx_inbound_smart_loading (warehouse_id, process_status, channel_code, expected_arrival_at, id)")
|
||||
.contains("idx_measure_inbound_status_id (tenant_id, inbound_id, status, id)")
|
||||
.contains("idx_measure_item_candidate (tenant_id, measurement_id, inbound_detail_id)");
|
||||
assertThat(migration())
|
||||
.contains("idx_loading_item_candidate (account_id, inbound_id, inbound_detail_id, deleted)");
|
||||
String unified = unifiedMigration();
|
||||
assertThat(unified)
|
||||
.contains("CREATE PROCEDURE baiyue_firstleg.ensure_smart_loading_candidate_indexes()")
|
||||
.contains("ADD KEY idx_inbound_smart_loading")
|
||||
.contains("ADD KEY idx_measure_inbound_status_id")
|
||||
.contains("ADD KEY idx_measure_item_candidate")
|
||||
.contains("ADD KEY idx_loading_item_candidate")
|
||||
.contains("ADD KEY idx_inbound_split_candidate");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("仓库备注使用计划先行与明细单表CAS并允许已拣明细仅改备注")
|
||||
void shouldUpdateWarehouseRemarkWithoutMultiTableTriggerConflict() throws Exception {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.client.OrderCargoClient;
|
||||
@@ -29,6 +30,7 @@ import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.Member;
|
||||
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelRow;
|
||||
import com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase;
|
||||
import com.baiyue.firstleg.mapper.SmartLoadingCandidateMapper.ChannelContainerCountRow;
|
||||
import com.baiyue.firstleg.mapper.SmartLoadingCandidateMapper.CandidateUnit;
|
||||
import com.baiyue.firstleg.split.service.SplitPreloadService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import feign.FeignException;
|
||||
@@ -62,6 +64,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anySet;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
@@ -156,10 +159,14 @@ class SmartLoadingServiceTest {
|
||||
"MATSON_CLX_TRUCK", "美森正班海卡");
|
||||
Candidate max = withChannel(candidate(19L, 11L, 21L, 31L, 6),
|
||||
"MATSON_MAX_TRUCK", "美森加班海卡");
|
||||
when(repository.globalCandidates(null)).thenReturn(List.of(clx, max));
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), null, null, null, null, null, null, 1, 20);
|
||||
CandidateUnit unit = new CandidateUnit(null, 9L, 10L, null, 10L);
|
||||
when(repository.globalCandidateUnits(eq(query), anySet()))
|
||||
.thenReturn(new PageResult<>(List.of(unit), 1, 20, 1, 1));
|
||||
when(repository.globalCandidatesByUnits(List.of(unit))).thenReturn(List.of(clx));
|
||||
|
||||
var result = service.inboundCandidates(new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), null, null, null, null, null, null, 1, 20));
|
||||
var result = service.inboundCandidates(query);
|
||||
|
||||
assertThat(result.total()).isEqualTo(1);
|
||||
assertThat(result.pages()).isEqualTo(1);
|
||||
@@ -167,7 +174,9 @@ class SmartLoadingServiceTest {
|
||||
assertThat(candidate.inboundId()).isEqualTo(10L);
|
||||
assertThat(candidate.channelCode()).isEqualTo("MATSON_CLX_TRUCK");
|
||||
});
|
||||
verify(repository).globalCandidates(null);
|
||||
verify(repository).globalCandidateUnits(eq(query), anySet());
|
||||
verify(repository).globalCandidatesByUnits(List.of(unit));
|
||||
verify(coloadGroups, never()).findByInbound(anyLong(), anyLong());
|
||||
verify(repository, never()).booking(anyLong());
|
||||
}
|
||||
|
||||
@@ -194,19 +203,20 @@ class SmartLoadingServiceTest {
|
||||
|
||||
@Test
|
||||
void treatsWholeColoadGroupAsOneStablePagingUnit() {
|
||||
Candidate first = withArrival(withChannel(candidate(9L, 10L, 20L, 30L, 4),
|
||||
"MATSON_CLX_TRUCK", "美森正班海卡"), "2026-09-01T09:00:00");
|
||||
Candidate second = withArrival(withChannel(candidate(19L, 11L, 21L, 31L, 6),
|
||||
"MATSON_CLX_TRUCK", "美森正班海卡"), "2026-09-10T09:00:00");
|
||||
GroupSnapshot group = group("ACTIVE", null,
|
||||
new Member(9L, 30L, 10L, "I10", 4), new Member(19L, 31L, 11L, "I11", 6));
|
||||
when(repository.globalCandidates(100L)).thenReturn(List.of(first, second));
|
||||
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
|
||||
when(coloadGroups.findByInbound(19L, 11L)).thenReturn(group);
|
||||
|
||||
var result = service.inboundCandidates(new InboundCandidateQuery(
|
||||
Candidate first = withGroup(withArrival(withChannel(candidate(9L, 10L, 20L, 30L, 4),
|
||||
"MATSON_CLX_TRUCK", "美森正班海卡"), "2026-09-01T09:00:00"), 2, 10);
|
||||
Candidate second = withGroup(withArrival(withChannel(candidate(19L, 11L, 21L, 31L, 6),
|
||||
"MATSON_CLX_TRUCK", "美森正班海卡"), "2026-09-10T09:00:00"), 2, 10);
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), 100L, null, null, LocalDate.parse("2026-09-10"),
|
||||
LocalDate.parse("2026-09-10"), null, 1, 1));
|
||||
LocalDate.parse("2026-09-10"), null, 1, 1);
|
||||
CandidateUnit unit = new CandidateUnit(700L, null, null,
|
||||
LocalDateTime.parse("2026-09-01T09:00:00"), 10L);
|
||||
when(repository.globalCandidateUnits(eq(query), anySet()))
|
||||
.thenReturn(new PageResult<>(List.of(unit), 1, 1, 1, 1));
|
||||
when(repository.globalCandidatesByUnits(List.of(unit))).thenReturn(List.of(first, second));
|
||||
|
||||
var result = service.inboundCandidates(query);
|
||||
|
||||
assertThat(result.total()).isEqualTo(1);
|
||||
assertThat(result.records()).singleElement().satisfies(candidate -> {
|
||||
@@ -219,18 +229,16 @@ class SmartLoadingServiceTest {
|
||||
|
||||
@Test
|
||||
void excludesIncompleteColoadGroupInsteadOfPublishingPartialMember() {
|
||||
Candidate first = withChannel(candidate(9L, 10L, 20L, 30L, 4),
|
||||
"MATSON_CLX_TRUCK", "美森正班海卡");
|
||||
GroupSnapshot group = group("ACTIVE", null,
|
||||
new Member(9L, 30L, 10L, "I10", 4), new Member(19L, 31L, 11L, "I11", 6));
|
||||
when(repository.globalCandidates(100L)).thenReturn(List.of(first));
|
||||
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), 100L, null, null, null, null, null, 1, 20);
|
||||
when(repository.globalCandidateUnits(eq(query), anySet()))
|
||||
.thenReturn(new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
|
||||
var result = service.inboundCandidates(new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), 100L, null, null, null, null, null, 1, 20));
|
||||
var result = service.inboundCandidates(query);
|
||||
|
||||
assertThat(result.records()).isEmpty();
|
||||
assertThat(result.total()).isZero();
|
||||
verify(repository, never()).globalCandidatesByUnits(anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1223,6 +1231,15 @@ class SmartLoadingServiceTest {
|
||||
value.orderStatusSnapshot(), LocalDateTime.parse(expectedArrivalAt));
|
||||
}
|
||||
|
||||
private static Candidate withGroup(Candidate value, int memberCount, int groupTotalBoxes) {
|
||||
return new Candidate(value.accountId(), value.inboundId(), value.inboundDetailId(), value.orderId(),
|
||||
value.orderNo(), value.inboundCode(), value.warehouseId(), value.channelCode(), value.channelName(),
|
||||
value.destinationWarehouseId(), value.destinationWarehouseCode(), value.destinationWarehouseName(),
|
||||
value.customerName(), value.goodsName(), value.availablePackageCount(), value.unitGrossWeightKg(),
|
||||
value.unitNetWeightKg(), value.unitVolumeCbm(), 700L, "CLG-700", memberCount, groupTotalBoxes,
|
||||
false, null, value.orderStatusSnapshot(), value.expectedArrivalAt());
|
||||
}
|
||||
|
||||
private static ChannelRow channel(String channelCode, String channelName) {
|
||||
ChannelRow value = new ChannelRow();
|
||||
value.setChannelCode(channelCode); value.setChannelName(channelName);
|
||||
|
||||
Reference in New Issue
Block a user