This commit is contained in:
2026-09-14 11:12:29 +08:00
parent 481ab348ff
commit 035537e5cc
5 changed files with 74 additions and 15 deletions
@@ -143,9 +143,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba
SELECT current_group.id groupId,
CASE WHEN current_group.id IS NULL THEN eligible.accountId END accountId,
CASE WHEN current_group.id IS NULL THEN eligible.inboundId END inboundId,
CASE WHEN current_group.id IS NULL THEN eligible.palletId END palletId,
MIN(eligible.expectedArrivalAt) sortArrivalAt,MIN(eligible.inboundId) sortInboundId
FROM (
SELECT o.tenant_id accountId,o.id inboundId,o.inbound_code inboundCode,
available_pallet.palletId palletId,
o.expected_arrival_at expectedArrivalAt,o.created_at createdAt,
CASE WHEN o.process_status='WAIT_SPLIT' THEN 'WAIT_SPLIT'
WHEN o.process_status='LOADING' THEN 'LOADING' ELSE 'WAIT_MEASURE' END candidateStatus,
@@ -165,6 +167,18 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba
WHERE o.inbound_role='MASTER' AND split_item.tenant_id=o.tenant_id
AND split_item.parent_inbound_id=o.id),0) availablePackageCount
FROM fl_inbound_order o
LEFT JOIN (
SELECT DISTINCT carton.tenant_id accountId,carton.inbound_id inboundId,pallet.id palletId
FROM fl_dropship_pallet pallet
JOIN fl_dropship_pallet_carton carton ON carton.pallet_id=pallet.id
WHERE pallet.pallet_status='SEALED'
AND NOT EXISTS (
SELECT 1 FROM fl_loading_plan_item pallet_item
WHERE pallet_item.pallet_id=pallet.id AND pallet_item.deleted=0
)
) available_pallet
ON available_pallet.accountId=o.tenant_id AND available_pallet.inboundId=o.id
AND o.fulfillment_type='ONE_CLICK_DROPSHIP'
WHERE (#{query.warehouseId} IS NULL OR o.warehouse_id=#{query.warehouseId})
AND COALESCE(o.hold_flag,0)=0
AND o.channel_code IN
@@ -174,11 +188,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba
o.process_status IN ('WAIT_MEASURE','MEASURING','MEASURE_PENDING','MEASURE_REJECTED',
'WAIT_PRICING','FEE_CONFIRMING','INBOUNDING','WAIT_SPLIT','LOADING')
)
AND NOT EXISTS (
SELECT 1 FROM fl_loading_plan_item active_item
WHERE active_item.account_id=o.tenant_id AND active_item.inbound_id=o.id
AND active_item.deleted=0
)
AND ((COALESCE(o.fulfillment_type,'STANDARD')<>'ONE_CLICK_DROPSHIP' AND NOT EXISTS (
SELECT 1 FROM fl_loading_plan_item active_item
WHERE active_item.account_id=o.tenant_id AND active_item.inbound_id=o.id
AND active_item.deleted=0
)) OR (o.fulfillment_type='ONE_CLICK_DROPSHIP' AND available_pallet.palletId IS NOT NULL))
) eligible
LEFT JOIN fl_coload_group_member current_member
ON current_member.tenant_id=eligible.accountId AND current_member.inbound_id=eligible.inboundId
@@ -188,9 +202,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba
WHERE eligible.candidateStatus<>'WAIT_SPLIT' OR eligible.availablePackageCount>0
GROUP BY current_group.id,
CASE WHEN current_group.id IS NULL THEN eligible.accountId END,
CASE WHEN current_group.id IS NULL THEN eligible.inboundId END
CASE WHEN current_group.id IS NULL THEN eligible.inboundId END,
CASE WHEN current_group.id IS NULL THEN eligible.palletId END
HAVING (current_group.id IS NULL OR (
COUNT(*)=(SELECT COUNT(*) FROM fl_coload_group_member group_member_count
COUNT(DISTINCT eligible.accountId,eligible.inboundId)=(SELECT COUNT(*) FROM fl_coload_group_member group_member_count
WHERE group_member_count.group_id=current_group.id AND group_member_count.active_flag=1)
))
<if test="query.orderStatuses != null and !query.orderStatuses.isEmpty()">
@@ -444,8 +459,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba
private String channelCode;
private Long availableContainerCount;
}
record CandidateUnit(Long groupId,Long accountId,Long inboundId,
LocalDateTime sortArrivalAt,Long sortInboundId) {}
record CandidateUnit(Long groupId,Long accountId,Long inboundId,Long palletId,
LocalDateTime sortArrivalAt,Long sortInboundId) {
public CandidateUnit(Long groupId,Long accountId,Long inboundId,
LocalDateTime sortArrivalAt,Long sortInboundId) {
this(groupId,accountId,inboundId,null,sortArrivalAt,sortInboundId);
}
}
record PlanColoadMemberRow(Long groupId,String groupNo,Long lockedPlanId,
Long orderId,Long inboundId,Integer fullPackageCount) {}
}
@@ -175,15 +175,15 @@ public class SmartLoadingService {
LinkedHashMap::new, java.util.stream.Collectors.toList()));
for (InboundCandidate candidate : all) {
if (candidate.coLoadGroupId() == null) {
units.put(unitKey(null, candidate.accountId(), candidate.inboundId()), candidate);
units.put(unitKey(null, candidate.accountId(), candidate.inboundId(), candidate.palletId()), candidate);
}
}
for (var entry : grouped.entrySet()) {
InboundCandidate aggregate = globalGroupCandidate(entry.getValue());
if (aggregate != null) units.put(unitKey(entry.getKey(), null, null), aggregate);
if (aggregate != null) units.put(unitKey(entry.getKey(), null, null, null), aggregate);
}
List<InboundCandidate> records = unitPage.records().stream()
.map(unit -> units.get(unitKey(unit.groupId(), unit.accountId(), unit.inboundId())))
.map(unit -> units.get(unitKey(unit.groupId(), unit.accountId(), unit.inboundId(), unit.palletId())))
.filter(Objects::nonNull).toList();
return new PageResult<>(records, unitPage.page(), unitPage.size(), unitPage.total(), unitPage.pages());
}
@@ -357,8 +357,8 @@ public class SmartLoadingService {
};
}
private static String unitKey(Long groupId, Long accountId, Long inboundId) {
return groupId == null ? "I|" + accountId + '|' + inboundId : "G|" + groupId;
private static String unitKey(Long groupId, Long accountId, Long inboundId, Long palletId) {
return groupId == null ? "I|" + accountId + '|' + inboundId + '|' + palletId : "G|" + groupId;
}
private static BigDecimal weightedAverage(List<InboundCandidate> members,
@@ -91,6 +91,11 @@ class SmartLoadingCandidateMapperContractTest {
.contains("status.name() == 'WAIT_SPLIT'")
.contains("status.name() == 'LOADING'")
.contains("NOT EXISTS (", "active_item.inbound_id=o.id", "active_item.deleted=0")
.contains("available_pallet.palletId palletId")
.contains("pallet.pallet_status='SEALED'")
.contains("pallet_item.pallet_id=pallet.id", "pallet_item.deleted=0")
.contains("o.fulfillment_type='ONE_CLICK_DROPSHIP' AND available_pallet.palletId IS NOT NULL")
.contains("CASE WHEN current_group.id IS NULL THEN eligible.palletId END palletId")
.contains("current_group.id groupId")
.contains("group_member_count.group_id=current_group.id")
.doesNotContain("fl_container_booking")
@@ -16,6 +16,7 @@ import com.baiyue.firstleg.dto.SmartLoadingDtos.DeleteRequest;
import com.baiyue.firstleg.dto.SmartLoadingDtos.GroupMemberCandidate;
import com.baiyue.firstleg.dto.SmartLoadingDtos.InboundCandidateQuery;
import com.baiyue.firstleg.dto.SmartLoadingDtos.InboundCandidate;
import com.baiyue.firstleg.dto.SmartLoadingDtos.PalletCandidate;
import com.baiyue.firstleg.dto.SmartLoadingDtos.WorkbenchContainer;
import com.baiyue.firstleg.dto.SmartLoadingDtos.WorkbenchContainerQuery;
import com.baiyue.firstleg.dto.SmartLoadingDtos.Plan;
@@ -224,6 +225,39 @@ class SmartLoadingServiceTest {
verify(repository, never()).booking(anyLong());
}
@Test
void pagesEachAvailableDropshipPalletAsAnIndependentCandidate() {
Candidate dropship = withChannel(candidate(9L, 10L, 20L, 30L, 12),
"EXX_TRUCK", "EXX海卡");
InboundCandidateQuery query = new InboundCandidateQuery(
List.of("EXX"), null, null, "EXXHWK2609140003", null, null,
null, null, List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 20);
List<CandidateUnit> units = List.of(
new CandidateUnit(null, 9L, 10L, 801L, null, 10L),
new CandidateUnit(null, 9L, 10L, 802L, null, 10L));
when(repository.globalCandidateUnits(eq(query), anySet()))
.thenReturn(new PageResult<>(units, 1, 20, 2, 1));
when(repository.globalCandidatesByUnits(units)).thenReturn(List.of(dropship));
when(dropshipPallets.palletCandidates(10L)).thenReturn(List.of(
new PalletCandidate(801L, "DP-260914-0004", "SEALED_PALLET", true,
8, 1, new BigDecimal("79.2"), new BigDecimal("4.4")),
new PalletCandidate(802L, "DP-260914-0005", "SEALED_PALLET", true,
4, 1, new BigDecimal("39.6"), new BigDecimal("2.2"))));
var result = service.inboundCandidates(query);
assertThat(result.total()).isEqualTo(2);
assertThat(result.records()).extracting(InboundCandidate::palletId,
InboundCandidate::palletNo, InboundCandidate::availablePackageCount)
.containsExactly(
org.assertj.core.groups.Tuple.tuple(801L, "DP-260914-0004", 8),
org.assertj.core.groups.Tuple.tuple(802L, "DP-260914-0005", 4));
assertThat(result.records()).allSatisfy(candidate -> {
assertThat(candidate.unitType()).isEqualTo("SEALED_PALLET");
assertThat(candidate.indivisible()).isTrue();
});
}
@Test
void combinesAllUnfinishedStatusesBeforeReturningTheRequestedPage() {
InboundCandidateQuery query = new InboundCandidateQuery(