fix: tolerate stale pallets in smart recommendation

This commit is contained in:
2026-09-14 15:01:05 +08:00
parent 1d258ab27b
commit febe265c50
3 changed files with 47 additions and 13 deletions
@@ -773,8 +773,8 @@ class SmartLoadingServiceTest {
}
@Test
void recommendAssignsDropshipCandidateThroughWholePalletCommand() {
Candidate dropship = candidate(9L, 10L, 20L, 30L, 10);
void recommendAssignsMultipleDropshipCandidatesThroughWholePalletCommands() {
Candidate dropship = candidate(9L, 10L, 20L, 30L, 20);
AtomicInteger version = new AtomicInteger();
List<LoadingPlanItemEntity> saved = new ArrayList<>();
InboundOrderEntity inbound = inbound(9L, 10L);
@@ -785,13 +785,17 @@ class SmartLoadingServiceTest {
when(repository.items(1L)).thenAnswer(invocation -> List.copyOf(saved));
when(repository.candidates(null)).thenReturn(List.of(dropship));
when(repository.inbound(9L, 10L)).thenReturn(inbound);
when(repository.activeItemsByPallet(801L)).thenReturn(List.of());
when(repository.activePalletItem(1L, 801L, 20L)).thenReturn(null);
when(repository.activeItemsByPallet(anyLong())).thenReturn(List.of());
when(repository.activePalletItem(eq(1L), anyLong(), eq(20L))).thenReturn(null);
when(dropshipPallets.palletCandidates(10L)).thenReturn(List.of(
new PalletCandidate(801L, "DP-260914-0021", "SEALED_PALLET", true,
10, 1, new BigDecimal("20"), new BigDecimal("5")),
new PalletCandidate(802L, "DP-260914-0022", "SEALED_PALLET", true,
10, 1, new BigDecimal("20"), new BigDecimal("5"))));
when(dropshipPallets.sealedPalletLines(801L)).thenReturn(List.of(
palletLine(801L, "DP-260914-0021", 10)));
when(dropshipPallets.sealedPalletLines(802L)).thenReturn(List.of(
palletLine(802L, "DP-260914-0022", 10)));
when(repository.touch(eq(1L), anyInt(), eq(7L), eq("u"))).thenAnswer(invocation -> {
int expected = invocation.getArgument(1);
if (expected != version.get()) return 0;
@@ -808,17 +812,39 @@ class SmartLoadingServiceTest {
Plan result = service.recommend(1L,
new RecommendRequest(0, "recommend-dropship-pallet"), 7L, "u");
assertThat(result.version()).isEqualTo(1);
assertThat(saved).singleElement().satisfies(item -> {
assertThat(result.version()).isEqualTo(2);
assertThat(saved).hasSize(2).allSatisfy(item -> {
assertThat(item.getUnitType()).isEqualTo("SEALED_PALLET");
assertThat(item.getPalletId()).isEqualTo(801L);
assertThat(item.getPalletNo()).isEqualTo("DP-260914-0021");
assertThat(item.getPackageCount()).isEqualTo(10);
assertThat(item.getIndivisible()).isTrue();
});
assertThat(saved).extracting(LoadingPlanItemEntity::getPalletId,
LoadingPlanItemEntity::getPalletNo).containsExactly(
org.assertj.core.groups.Tuple.tuple(801L, "DP-260914-0021"),
org.assertj.core.groups.Tuple.tuple(802L, "DP-260914-0022"));
verify(repository, never()).candidate(anyLong(), anyLong(), anyLong());
}
@Test
void recommendSkipsStalePalletCandidateInsteadOfFailingTheWholeRecommendation() {
Candidate dropship = candidate(9L, 10L, 20L, 30L, 10);
when(repository.plan(1L)).thenReturn(plan("EDITING", 0));
when(repository.planByBooking(99L)).thenReturn(plan("EDITING", 0));
when(repository.booking(99L)).thenReturn(booking());
when(repository.items(1L)).thenReturn(List.of());
when(repository.candidates(null)).thenReturn(List.of(dropship));
when(dropshipPallets.palletCandidates(10L)).thenReturn(List.of(
new PalletCandidate(801L, "DP-STALE", "SEALED_PALLET", true,
10, 1, new BigDecimal("20"), new BigDecimal("5"))));
when(dropshipPallets.sealedPalletLines(801L)).thenReturn(List.of());
Plan result = service.recommend(1L,
new RecommendRequest(0, "recommend-stale-pallet"), 7L, "u");
assertThat(result.items()).isEmpty();
verify(repository, never()).touch(anyLong(), anyInt(), anyLong(), anyString());
}
@Test
void recommendRechecksCurrentCapacitySkipsStaleGroupAndContinuesWithLaterCandidate() {
Candidate ordinary = candidate(9L, 10L, 20L, 30L, 4);