This commit is contained in:
2026-09-15 18:17:06 +08:00
parent 45018987ef
commit 4b671bb0ab
13 changed files with 174 additions and 15 deletions
@@ -20,6 +20,21 @@ import java.time.LocalDateTime;
import static org.assertj.core.api.Assertions.assertThat;
class SmartLoadingCandidateMapperContractTest {
@Test
void sharedPalletPaginationGroupsByPalletRatherThanInbound() throws Exception {
String sql = String.join(" ", SmartLoadingCandidateMapper.class
.getDeclaredMethod("globalCandidateUnits", Page.class, InboundCandidateQuery.class, Set.class)
.getAnnotation(Select.class).value());
assertThat(sql).contains("MIN(CASE WHEN current_group.id IS NULL THEN eligible.inboundId END) inboundId")
.contains("CASE WHEN current_group.id IS NULL AND eligible.palletId IS NULL THEN eligible.inboundId END")
.contains("sortInboundId,palletId");
String members = String.join(" ", com.baiyue.firstleg.mapper.DropshipPalletizationMapper.class
.getDeclaredMethod("palletInboundMembers", long.class).getAnnotation(Select.class).value());
assertThat(members).contains("COUNT(DISTINCT c.id) availablePackageCount")
.contains("WHERE c.pallet_id=#{palletId}")
.contains("GROUP BY o.tenant_id,o.id")
.doesNotContain("#{inboundId}");
}
@Test
void candidateHasOnlyTheCanonicalMybatisConstructor() {
assertThat(Candidate.class.getDeclaredConstructors()).singleElement()
@@ -165,6 +180,10 @@ class SmartLoadingCandidateMapperContractTest {
.contains("eligible.candidateStatus='WAIT_SPLIT'")
.contains("MAX(CASE WHEN LOWER(eligible.inboundCode)")
.contains("MAX(CASE WHEN eligible.accountId=");
assertThat(renderedUnits.indexOf("MAX(CASE WHEN LOWER(eligible.inboundCode)"))
.as("inbound search must match any member after grouping, without cutting pallet composition")
.isGreaterThan(renderedUnits.indexOf("HAVING"));
assertThat(renderedUnits).contains("LIKE CONCAT('%',LOWER(");
Method details = SmartLoadingCandidateMapper.class.getDeclaredMethod(
"globalCandidatesByUnits", List.class);
@@ -261,6 +261,30 @@ class SmartLoadingServiceTest {
});
}
@Test
void sharedPalletIsOneUnitWithExactInboundComposition() {
Candidate dropship = withStatus(withChannel(candidate(9L, 10L, 20L, 100L, 20), "EXX_TRUCK", "EXX海卡"), "WAIT_SPLIT", false);
// Searching a non-representative member must still return the whole pallet.
InboundCandidateQuery query = new InboundCandidateQuery(List.of("EXX"), null, null, "I11",
null, null, null, null, List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 1);
var unit = new CandidateUnit(null, 9L, 10L, 801L, null, 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(dropship));
when(dropshipPallets.palletCandidates(10L)).thenReturn(List.of(
new PalletCandidate(801L, "DP-0025", "SEALED_PALLET", true, 13, 1, new BigDecimal("130"), new BigDecimal("1.3"))));
var members = List.of(
new com.baiyue.firstleg.dto.SmartLoadingDtos.GroupMemberCandidate(9L, 10L, 100L, "O10", "I10", "客户", 3, "WAIT_SPLIT", null),
new com.baiyue.firstleg.dto.SmartLoadingDtos.GroupMemberCandidate(9L, 11L, 101L, "O11", "I11", "客户", 10, "WAIT_SPLIT", null));
when(dropshipPallets.palletInboundMembers(801L)).thenReturn(members);
var result = service.inboundCandidates(query);
assertThat(result.total()).isEqualTo(1);
assertThat(result.records()).singleElement().satisfies(row -> {
assertThat(row.availablePackageCount()).isEqualTo(13);
assertThat(row.groupMembers()).containsExactlyElementsOf(members);
assertThat(row.unitGrossWeightKg()).isEqualByComparingTo("10");
});
}
@Test
void combinesAllUnfinishedStatusesBeforeReturningTheRequestedPage() {
InboundCandidateQuery query = new InboundCandidateQuery(