优化
This commit is contained in:
+4
-4
@@ -36,13 +36,13 @@ class PlatformSmartLoadingControllerContractTest {
|
||||
.contains("name: warehouseId")
|
||||
.contains("name: createdStart")
|
||||
.contains("name: createdEnd")
|
||||
.contains("name: expectedArrivalStart")
|
||||
.contains("name: expectedArrivalEnd")
|
||||
.contains("name: orderStatuses")
|
||||
.contains("maxItems: 4")
|
||||
.contains("PENDING_REVIEW, WAIT_MEASURE, WAIT_SPLIT, LOADING")
|
||||
.contains("SmartLoadingInboundCandidatePageEnvelope")
|
||||
.doesNotContain("name: orderStatus,")
|
||||
.doesNotContain("name: expectedArrivalStart")
|
||||
.doesNotContain("name: expectedArrivalEnd")
|
||||
.doesNotContain("name: bookingId");
|
||||
assertThat(yaml).contains("canAssign: {type: boolean, description: 当前是否可加入柜次");
|
||||
}
|
||||
@@ -85,8 +85,8 @@ class PlatformSmartLoadingControllerContractTest {
|
||||
.contains("items[].version 是递增后的 itemVersion")
|
||||
.contains("数量调整或动态增量不会覆盖已有 warehouseRemark")
|
||||
.contains("柜内总容积和总重量分别允许达到柜型额定值的150%")
|
||||
.contains("人工分配不限制订单渠道与柜次渠道一致")
|
||||
.contains("渠道只约束智能推荐")
|
||||
.contains("人工分配不限制订单国内仓及渠道与柜次一致")
|
||||
.contains("智能推荐允许跨国内仓,但仍只选择柜次渠道")
|
||||
.contains("canAssign: {type: boolean}")
|
||||
.contains("canEdit: {type: boolean}")
|
||||
.contains("pickedPackageCount: {type: integer, minimum: 0}")
|
||||
|
||||
+9
-6
@@ -39,7 +39,7 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
|
||||
@Test
|
||||
void selectsLatestApprovedBatch() throws Exception {
|
||||
Method list = SmartLoadingCandidateMapper.class.getDeclaredMethod("candidates", long.class);
|
||||
Method list = SmartLoadingCandidateMapper.class.getDeclaredMethod("candidates", Long.class);
|
||||
String sql = String.join(" ", list.getAnnotation(Select.class).value());
|
||||
|
||||
assertThat(sql)
|
||||
@@ -106,7 +106,7 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalCandidateDateFilterUsesTheRepresentativeOrderCreationDate() throws Exception {
|
||||
void globalCandidateDateFiltersUseRepresentativeCreationAndExpectedArrivalDates() throws Exception {
|
||||
Method units = SmartLoadingCandidateMapper.class.getDeclaredMethod("globalCandidateUnits",
|
||||
Page.class, InboundCandidateQuery.class, Set.class);
|
||||
String sql = String.join(" ", units.getAnnotation(Select.class).value());
|
||||
@@ -115,7 +115,8 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
.contains("o.created_at createdAt")
|
||||
.contains("MIN(eligible.createdAt)>=#{query.createdStart}")
|
||||
.contains("MIN(eligible.createdAt)<DATE_ADD(#{query.createdEnd},INTERVAL 1 DAY)")
|
||||
.doesNotContain("query.expectedArrivalStart", "query.expectedArrivalEnd");
|
||||
.contains("MIN(eligible.expectedArrivalAt)>=#{query.expectedArrivalStart}")
|
||||
.contains("MIN(eligible.expectedArrivalAt)<DATE_ADD(#{query.expectedArrivalEnd},INTERVAL 1 DAY)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -146,6 +147,7 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
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"),
|
||||
java.time.LocalDate.parse("2026-09-05"), java.time.LocalDate.parse("2026-10-05"),
|
||||
List.of(com.baiyue.firstleg.dto.SmartLoadingDtos.CandidateOrderStatus.WAIT_MEASURE,
|
||||
com.baiyue.firstleg.dto.SmartLoadingDtos.CandidateOrderStatus.WAIT_SPLIT), 1, 20);
|
||||
String renderedUnits = driver.createSqlSource(configuration, unitScript, Map.class)
|
||||
@@ -153,6 +155,7 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
assertThat(renderedUnits)
|
||||
.contains("o.channel_code IN")
|
||||
.contains("MIN(eligible.createdAt)>=", "MIN(eligible.createdAt)<DATE_ADD")
|
||||
.contains("MIN(eligible.expectedArrivalAt)>=", "MIN(eligible.expectedArrivalAt)<DATE_ADD")
|
||||
.contains("eligible.candidateStatus='WAIT_MEASURE'")
|
||||
.contains("eligible.candidateStatus='WAIT_SPLIT'")
|
||||
.contains("MAX(CASE WHEN LOWER(eligible.inboundCode)")
|
||||
@@ -188,9 +191,9 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void detailUsesSameBatchRule() throws Exception {
|
||||
void detailUsesSameBatchRuleWithoutRestrictingTheCabinetWarehouse() throws Exception {
|
||||
Method detail = SmartLoadingCandidateMapper.class.getDeclaredMethod(
|
||||
"candidate", long.class, long.class, long.class, long.class);
|
||||
"candidate", long.class, long.class, long.class);
|
||||
String sql = String.join(" ", detail.getAnnotation(Select.class).value());
|
||||
|
||||
assertThat(sql)
|
||||
@@ -199,7 +202,7 @@ class SmartLoadingCandidateMapperContractTest {
|
||||
.contains("o.expected_arrival_at expectedArrivalAt")
|
||||
.contains("m.status='APPROVED'")
|
||||
.contains("SELECT MAX(m2.id)")
|
||||
.contains("o.warehouse_id=#{warehouseId}")
|
||||
.doesNotContain("o.warehouse_id=#{warehouseId}")
|
||||
.contains("o.process_status='WAIT_SPLIT'")
|
||||
.contains("o.process_status='LOADING'")
|
||||
.contains("same_plan_item.loading_plan_id=#{planId}")
|
||||
|
||||
@@ -196,6 +196,7 @@ class SmartLoadingServiceTest {
|
||||
"MATSON_MAX_TRUCK", "美森加班海卡");
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), null, null, null, null, null,
|
||||
null, null,
|
||||
List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 20);
|
||||
CandidateUnit unit = new CandidateUnit(null, 9L, 10L, null, 10L);
|
||||
when(repository.globalCandidateUnits(eq(query), anySet()))
|
||||
@@ -219,14 +220,14 @@ class SmartLoadingServiceTest {
|
||||
@Test
|
||||
void combinesAllUnfinishedStatusesBeforeReturningTheRequestedPage() {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("EXX"), null, null, null, null, null, List.of(), 1, 20);
|
||||
List.of("EXX"), null, null, null, null, null, null, null, List.of(), 1, 20);
|
||||
var pending = new PendingReviewOrderClient.Row(31L, "O31", "I31", 9L, "客户",
|
||||
100L, "EXX_TRUCK", "EXX海卡", 3, LocalDateTime.parse("2026-09-01T09:00:00"),
|
||||
"PENDING_REVIEW");
|
||||
LocalDateTime.parse("2026-09-08T09:00:00"), "PENDING_REVIEW");
|
||||
when(pendingReviewOrders.page(anyString(), anyList(), isNull(), isNull(), isNull(),
|
||||
isNull(), isNull(), anyList(), anyLong(), anyLong())).thenAnswer(invocation -> {
|
||||
long page = invocation.getArgument(8);
|
||||
long size = invocation.getArgument(9);
|
||||
isNull(), isNull(), isNull(), isNull(), anyList(), anyLong(), anyLong())).thenAnswer(invocation -> {
|
||||
long page = invocation.getArgument(10);
|
||||
long size = invocation.getArgument(11);
|
||||
return ApiResponse.success(new PageResult<>(page == 1 ? List.of(pending) : List.of(),
|
||||
page, size, 1, 1));
|
||||
});
|
||||
@@ -256,13 +257,14 @@ class SmartLoadingServiceTest {
|
||||
CandidateOrderStatus.WAIT_MEASURE, CandidateOrderStatus.WAIT_SPLIT,
|
||||
CandidateOrderStatus.LOADING));
|
||||
verify(pendingReviewOrders).page(anyString(), anyList(), isNull(), isNull(), isNull(),
|
||||
isNull(), isNull(), anyList(), eq(1L), eq(20L));
|
||||
isNull(), isNull(), isNull(), isNull(), anyList(), eq(1L), eq(20L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusDoesNotBlockAssignmentButAnActiveContainerOccupationDoes() {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(List.of("EXX"), null, null, null,
|
||||
null, null, List.of(CandidateOrderStatus.WAIT_MEASURE, CandidateOrderStatus.LOADING), 1, 20);
|
||||
null, null, null, null,
|
||||
List.of(CandidateOrderStatus.WAIT_MEASURE, CandidateOrderStatus.LOADING), 1, 20);
|
||||
Candidate waiting = withStatus(candidate(9L, 10L, 20L, 30L, 4), "WAIT_MEASURE", false);
|
||||
Candidate loading = withStatus(candidate(19L, 11L, 21L, 31L, 0), "LOADING", true);
|
||||
List<CandidateUnit> units = List.of(new CandidateUnit(null, 9L, 10L, null, 10L),
|
||||
@@ -285,7 +287,7 @@ class SmartLoadingServiceTest {
|
||||
@Test
|
||||
void keepsAnOccupiedLoadingGroupAsOneNonAssignablePagingUnit() {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(List.of("EXX"), null, null, null,
|
||||
null, null, List.of(CandidateOrderStatus.LOADING), 1, 20);
|
||||
null, null, null, null, List.of(CandidateOrderStatus.LOADING), 1, 20);
|
||||
Candidate first = withStatus(withGroup(candidate(9L, 10L, 20L, 30L, 0), 2, 10),
|
||||
"LOADING", true);
|
||||
Candidate second = withStatus(withGroup(candidate(19L, 11L, 21L, 31L, 0), 2, 10),
|
||||
@@ -310,15 +312,17 @@ class SmartLoadingServiceTest {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("EXX"), 193000000000200002L, null, "EXXHK2609020361",
|
||||
LocalDate.parse("2026-09-02"), LocalDate.parse("2026-09-02"),
|
||||
LocalDate.parse("2026-09-08"), LocalDate.parse("2026-09-09"),
|
||||
List.of(CandidateOrderStatus.PENDING_REVIEW), 1, 20);
|
||||
var row = new PendingReviewOrderClient.Row(2095052002489335810L, "FL-361",
|
||||
"EXXHK2609020361", 2092797167699816450L, "客户", 193000000000200002L,
|
||||
"EXX_TRUCK", "EXX海卡", 100, LocalDateTime.parse("2026-09-02T15:31:36"),
|
||||
"PENDING_REVIEW");
|
||||
LocalDateTime.parse("2026-09-08T10:00:00"), "PENDING_REVIEW");
|
||||
when(repository.occupiedOrderIds(eq(query), anySet())).thenReturn(List.of(998L));
|
||||
when(pendingReviewOrders.page(anyString(), anyList(), eq(193000000000200002L),
|
||||
isNull(), eq("EXXHK2609020361"), eq("2026-09-02"),
|
||||
eq("2026-09-02"), eq(List.of(998L)), eq(1L), eq(20L)))
|
||||
eq("2026-09-02"), eq("2026-09-08"), eq("2026-09-09"),
|
||||
eq(List.of(998L)), eq(1L), eq(20L)))
|
||||
.thenReturn(ApiResponse.success(new PageResult<>(List.of(row), 1, 20, 1, 1)));
|
||||
|
||||
var result = service.inboundCandidates(query);
|
||||
@@ -331,6 +335,7 @@ class SmartLoadingServiceTest {
|
||||
assertThat(candidate.canAssign()).isTrue();
|
||||
assertThat(candidate.blockReason()).isNull();
|
||||
assertThat(candidate.availablePackageCount()).isEqualTo(100);
|
||||
assertThat(candidate.expectedArrivalAt()).isEqualTo(LocalDateTime.parse("2026-09-08T10:00:00"));
|
||||
});
|
||||
verify(repository, never()).globalCandidateUnits(any(), anySet());
|
||||
verify(repository, never()).globalCandidatesByUnits(anyList());
|
||||
@@ -344,7 +349,7 @@ class SmartLoadingServiceTest {
|
||||
String inboundCode = "EXXHK2609020361";
|
||||
var pending = new PendingReviewOrderClient.Row(orderId, "FL-361", inboundCode,
|
||||
customerId, "客户", 100L, "SLOW", "慢船", 5,
|
||||
LocalDateTime.parse("2026-09-02T15:31:36"), "PENDING_REVIEW");
|
||||
LocalDateTime.parse("2026-09-02T15:31:36"), null, "PENDING_REVIEW");
|
||||
var snapshot = new com.baiyue.firstleg.dto.OrderApprovedInboundCommand(
|
||||
customerId, orderId, "FL-361", inboundCode, customerId, "客户", 100L, "义乌仓",
|
||||
null, null, null, "FIRST_LEG", "SLOW", "慢船", null, null, null,
|
||||
@@ -354,7 +359,7 @@ class SmartLoadingServiceTest {
|
||||
var cargo = new OrderCargoClient.CargoBinding(20L, orderId, 1, "货物", 5,
|
||||
new BigDecimal("50"), new BigDecimal("2.5"));
|
||||
when(pendingReviewOrders.page(anyString(), isNull(), isNull(), eq(customerId),
|
||||
eq(inboundCode), isNull(), isNull(), isNull(), eq(1L), eq(2L)))
|
||||
eq(inboundCode), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1L), eq(2L)))
|
||||
.thenReturn(ApiResponse.success(new PageResult<>(List.of(pending), 1, 2, 1, 1)));
|
||||
when(cargoClient.inboundSnapshot(anyString(), eq(customerId), eq(orderId)))
|
||||
.thenReturn(ApiResponse.success(snapshot));
|
||||
@@ -430,19 +435,75 @@ class SmartLoadingServiceTest {
|
||||
7L, "u", "wait-measure-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void assignsWaitSplitInboundToCabinetFromAnotherDomesticWarehouse() {
|
||||
Candidate crossWarehouse = withWarehouse(candidate(1), 101L);
|
||||
InboundOrderEntity projection = new InboundOrderEntity();
|
||||
projection.setId(10L);
|
||||
projection.setTenantId(9L);
|
||||
projection.setWarehouseId(101L);
|
||||
projection.setProcessStatus("WAIT_SPLIT");
|
||||
AtomicInteger version = new AtomicInteger();
|
||||
List<LoadingPlanItemEntity> saved = new ArrayList<>();
|
||||
when(repository.inbound(10L)).thenReturn(projection);
|
||||
when(repository.plan(1L)).thenAnswer(invocation -> plan("EDITING", version.get()));
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.candidates(null)).thenReturn(List.of(crossWarehouse));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(crossWarehouse);
|
||||
when(repository.activeItemsByInbound(1L, 9L, 10L)).thenReturn(List.of());
|
||||
when(repository.activeItem(1L, 9L, 20L)).thenReturn(null);
|
||||
when(repository.items(1L)).thenAnswer(invocation -> List.copyOf(saved));
|
||||
when(repository.touch(eq(1L), anyInt(), eq(7L), eq("u"))).thenAnswer(invocation -> {
|
||||
int expected = invocation.getArgument(1);
|
||||
if (expected != version.get()) return 0;
|
||||
version.incrementAndGet();
|
||||
return 1;
|
||||
});
|
||||
doAnswer(invocation -> {
|
||||
LoadingPlanItemEntity item = invocation.getArgument(0);
|
||||
item.setId(800L);
|
||||
saved.add(item);
|
||||
return null;
|
||||
}).when(repository).insert(any(LoadingPlanItemEntity.class));
|
||||
|
||||
Plan result = service.assignInbound(1L,
|
||||
new AssignInboundRequest(10L, 1, 0, "assign-inbound-cross-warehouse"), 7L, "u");
|
||||
|
||||
assertThat(result.version()).isEqualTo(1);
|
||||
assertThat(saved).singleElement().satisfies(item -> {
|
||||
assertThat(item.getInboundId()).isEqualTo(10L);
|
||||
assertThat(item.getPackageCount()).isEqualTo(1);
|
||||
});
|
||||
verify(repository).candidates(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void failsClosedWhenPendingReviewOrderSourceIsUnavailable() {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("EXX"), null, null, null, null, null,
|
||||
null, null,
|
||||
List.of(CandidateOrderStatus.PENDING_REVIEW), 1, 20);
|
||||
when(pendingReviewOrders.page(anyString(), anyList(), isNull(), isNull(), isNull(),
|
||||
isNull(), isNull(), anyList(), eq(1L), eq(20L))).thenThrow(new RuntimeException("offline"));
|
||||
isNull(), isNull(), isNull(), isNull(), anyList(), eq(1L), eq(20L))).thenThrow(new RuntimeException("offline"));
|
||||
|
||||
assertThatThrownBy(() -> service.inboundCandidates(query))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("待审核订单服务暂时不可用");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsReversedExpectedArrivalRangeBeforeQueryingCandidates() {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("EXX"), null, null, null, null, null,
|
||||
LocalDate.parse("2026-09-10"), LocalDate.parse("2026-09-09"),
|
||||
List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 20);
|
||||
|
||||
assertThatThrownBy(() -> service.inboundCandidates(query))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("预计到货开始日期不能晚于结束日期");
|
||||
verify(repository, never()).globalCandidateUnits(any(), anySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
void pagesWorkbenchContainersWithTheSameGlobalFilters() {
|
||||
WorkbenchContainer container = new WorkbenchContainer(99L, "CB-1", "CAB-1", null,
|
||||
@@ -473,7 +534,8 @@ class SmartLoadingServiceTest {
|
||||
"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-01"),
|
||||
LocalDate.parse("2026-09-01"), List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 1);
|
||||
LocalDate.parse("2026-09-01"), null, null,
|
||||
List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 1);
|
||||
CandidateUnit unit = new CandidateUnit(700L, null, null,
|
||||
LocalDateTime.parse("2026-09-01T09:00:00"), 10L);
|
||||
when(repository.globalCandidateUnits(eq(query), anySet()))
|
||||
@@ -495,6 +557,7 @@ class SmartLoadingServiceTest {
|
||||
void excludesIncompleteColoadGroupInsteadOfPublishingPartialMember() {
|
||||
InboundCandidateQuery query = new InboundCandidateQuery(
|
||||
List.of("MATSON_CLX"), 100L, null, null, null, null,
|
||||
null, null,
|
||||
List.of(CandidateOrderStatus.WAIT_SPLIT), 1, 20);
|
||||
when(repository.globalCandidateUnits(eq(query), anySet()))
|
||||
.thenReturn(new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
@@ -593,9 +656,9 @@ class SmartLoadingServiceTest {
|
||||
when(repository.planByBooking(99L)).thenAnswer(invocation -> plan("EDITING", version.get()));
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.inbound(10L)).thenReturn(inbound(9L, 10L));
|
||||
when(repository.candidates(100L)).thenReturn(List.of(first, second));
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(first);
|
||||
when(repository.candidate(1L, 100L, 11L, 21L)).thenReturn(second);
|
||||
when(repository.candidates(null)).thenReturn(List.of(first, second));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(first);
|
||||
when(repository.candidate(1L, 11L, 21L)).thenReturn(second);
|
||||
when(repository.items(1L)).thenAnswer(invocation -> List.copyOf(saved));
|
||||
when(repository.activeItemsByInbound(anyLong(), anyLong())).thenReturn(List.of());
|
||||
when(repository.activeItemsByInbound(anyLong(), anyLong(), anyLong())).thenReturn(List.of());
|
||||
@@ -636,7 +699,7 @@ class SmartLoadingServiceTest {
|
||||
org.mockito.ArgumentMatchers.startsWith("LOCK-"), eq(7L), eq("u"));
|
||||
verify(loadingModelBridge, times(2)).bindIncrementalAllocation(eq(1L), anyLong(), anyLong(),
|
||||
eq(7L), eq("u"), anyString());
|
||||
verify(repository, times(1)).candidates(100L);
|
||||
verify(repository, times(1)).candidates(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -654,7 +717,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.planByBooking(99L)).thenReturn(plan);
|
||||
when(repository.booking(99L)).thenReturn(small);
|
||||
when(repository.items(1L)).thenReturn(List.of());
|
||||
when(repository.candidates(100L)).thenReturn(List.of(first, second, third));
|
||||
when(repository.candidates(null)).thenReturn(List.of(first, second, third));
|
||||
when(coloadGroups.findByInbound(anyLong(), anyLong())).thenReturn(group);
|
||||
|
||||
Plan result = service.recommend(1L, new RecommendRequest(0, "recommend-group-too-large"), 7L, "u");
|
||||
@@ -681,9 +744,9 @@ class SmartLoadingServiceTest {
|
||||
when(repository.planByBooking(99L)).thenAnswer(invocation -> plan("EDITING", version.get()));
|
||||
when(repository.booking(99L)).thenReturn(small);
|
||||
when(repository.items(1L)).thenAnswer(invocation -> List.copyOf(saved));
|
||||
when(repository.candidates(100L)).thenReturn(List.of(ordinary, groupFirst, groupSecond, later));
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(ordinary);
|
||||
when(repository.candidate(1L, 100L, 13L, 23L)).thenReturn(later);
|
||||
when(repository.candidates(null)).thenReturn(List.of(ordinary, groupFirst, groupSecond, later));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(ordinary);
|
||||
when(repository.candidate(1L, 13L, 23L)).thenReturn(later);
|
||||
when(repository.activeItemsByInbound(anyLong(), anyLong(), anyLong())).thenReturn(List.of());
|
||||
when(repository.activeItem(anyLong(), anyLong(), anyLong())).thenReturn(null);
|
||||
when(repository.touch(eq(1L), anyInt(), eq(7L), eq("u"))).thenAnswer(invocation -> {
|
||||
@@ -732,7 +795,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.booking(99L)).thenReturn(small);
|
||||
when(repository.inbound(11L)).thenReturn(inbound(9L, 11L));
|
||||
when(repository.items(1L)).thenReturn(List.of());
|
||||
when(repository.candidates(100L)).thenReturn(List.of(first, second));
|
||||
when(repository.candidates(null)).thenReturn(List.of(first, second));
|
||||
when(repository.activeItemsByInbound(anyLong(), anyLong())).thenReturn(List.of());
|
||||
when(coloadGroups.findByInbound(9L, 11L)).thenReturn(group);
|
||||
when(coloadGroups.findByInbound(9L, 12L)).thenReturn(group);
|
||||
@@ -1006,7 +1069,7 @@ class SmartLoadingServiceTest {
|
||||
LoadingPlanEntity plan = plan("EDITING", 0);
|
||||
when(repository.plan(1)).thenReturn(plan);
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.candidate(1, 100, 10, 20)).thenReturn(candidate(5));
|
||||
when(repository.candidate(1, 10, 20)).thenReturn(candidate(5));
|
||||
when(repository.activeItem(1L, 9L, 20L)).thenReturn(item(7, 9, 20, 4));
|
||||
|
||||
BizException error = catchThrowableOfType(() -> service.assign(1,
|
||||
@@ -1023,7 +1086,7 @@ class SmartLoadingServiceTest {
|
||||
linked.setCustomerId(88L);
|
||||
when(repository.plan(1L)).thenReturn(plan);
|
||||
when(repository.booking(99L)).thenReturn(linked);
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(candidate(5));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(candidate(5));
|
||||
|
||||
BizException error = catchThrowableOfType(() -> service.assign(1L,
|
||||
new AssignRequest(10L, 20L, 1, 0, "assign-customer-mismatch"), 7L, "u"), BizException.class);
|
||||
@@ -1032,6 +1095,20 @@ class SmartLoadingServiceTest {
|
||||
verify(repository, never()).touch(anyLong(), anyInt(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void manuallyAssignsCargoFromAnotherDomesticWarehouse() {
|
||||
stubAssignment();
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(
|
||||
withWarehouse(candidate(10), 101L));
|
||||
|
||||
Plan result = service.assign(1L,
|
||||
new AssignRequest(10L, 20L, 1, 0, "assign-cross-warehouse"), 7L, "u");
|
||||
|
||||
assertThat(result.version()).isEqualTo(1);
|
||||
verify(repository).insert(any(LoadingPlanItemEntity.class));
|
||||
verify(repository).touch(1L, 0, 7L, "u");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsVolumeAndWeightWithinOneHundredFiftyPercent() {
|
||||
stubAssignment();
|
||||
@@ -1121,7 +1198,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.booking(99)).thenReturn(booking());
|
||||
when(repository.touch(1, 5, 7, "u")).thenReturn(1);
|
||||
when(repository.items(1)).thenReturn(List.of());
|
||||
when(repository.candidate(1, 100, 10, 20)).thenReturn(candidate(10));
|
||||
when(repository.candidate(1, 10, 20)).thenReturn(candidate(10));
|
||||
when(repository.activeItem(1L, 9L, 20L)).thenReturn(null);
|
||||
when(loadingPickService.mutationSnapshot(1L)).thenReturn(
|
||||
new LoadingPickService.MutationSnapshot(77L, "LOADING", 6, Map.of()));
|
||||
@@ -1132,7 +1209,7 @@ class SmartLoadingServiceTest {
|
||||
Plan result = service.assign(1, new AssignRequest(10L, 20L, 1, 5, "assign-loading"), 7, "u");
|
||||
|
||||
assertThat(result.status()).isEqualTo("LOADING");
|
||||
verify(repository).candidate(1L, 100L, 10L, 20L);
|
||||
verify(repository).candidate(1L, 10L, 20L);
|
||||
var order = inOrder(loadingPickService, splitPreloadService, repository, loadingModelBridge);
|
||||
order.verify(loadingPickService).lockMutable(1L);
|
||||
order.verify(splitPreloadService).ensureForRunningLoadingAllocation(9L, 10L, 7L, "u");
|
||||
@@ -1152,7 +1229,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.booking(99)).thenReturn(booking());
|
||||
when(repository.touch(1, 5, 7, "u")).thenReturn(1);
|
||||
when(repository.items(1)).thenReturn(List.of());
|
||||
when(repository.candidate(1, 100, 10, 20)).thenReturn(candidate(10));
|
||||
when(repository.candidate(1, 10, 20)).thenReturn(candidate(10));
|
||||
when(repository.activeItem(1L, 9L, 20L)).thenReturn(null);
|
||||
when(loadingPickService.mutationSnapshot(1L)).thenReturn(
|
||||
new LoadingPickService.MutationSnapshot(77L, "LOADING", 6, Map.of()));
|
||||
@@ -1182,7 +1259,7 @@ class SmartLoadingServiceTest {
|
||||
Plan result = service.assign(1, request, 7, "u");
|
||||
|
||||
assertThat(result.status()).isEqualTo("LOADING");
|
||||
verify(repository, never()).candidate(anyLong(), anyLong(), anyLong(), anyLong());
|
||||
verify(repository, never()).candidate(anyLong(), anyLong(), anyLong());
|
||||
verify(cargoClient, never()).detail(anyString(), anyLong(), anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@@ -1401,7 +1478,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.plan(1L)).thenReturn(plan, plan("LOADING", 3));
|
||||
when(repository.item(1L, 8L)).thenReturn(line);
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(candidate(10));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(candidate(10));
|
||||
when(repository.items(1L)).thenReturn(List.of(line));
|
||||
when(repository.touch(1L, 2, 7L, "u")).thenReturn(1);
|
||||
when(repository.update(line)).thenReturn(1);
|
||||
@@ -1420,7 +1497,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.plan(1L)).thenReturn(plan, plan("LOADING", 94));
|
||||
when(repository.item(1L, 8L)).thenReturn(line);
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(candidate(-25));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(candidate(-25));
|
||||
when(repository.items(1L)).thenReturn(List.of(line));
|
||||
when(repository.touch(1L, 93, 7L, "u")).thenReturn(1);
|
||||
when(repository.update(line)).thenReturn(1);
|
||||
@@ -1439,7 +1516,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.plan(1L)).thenReturn(plan, plan("LOADING", 3));
|
||||
when(repository.item(1L, 8L)).thenReturn(line);
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(candidate(10));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(candidate(10));
|
||||
when(repository.items(1L)).thenReturn(List.of(line));
|
||||
when(repository.touch(1L, 2, 7L, "u")).thenReturn(1);
|
||||
when(repository.update(line)).thenReturn(1);
|
||||
@@ -1462,7 +1539,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.plan(1L)).thenReturn(plan);
|
||||
when(repository.item(1L, 8L)).thenReturn(line);
|
||||
when(repository.booking(99L)).thenReturn(booking());
|
||||
when(repository.candidate(1L, 100L, 10L, 20L)).thenReturn(candidate(10));
|
||||
when(repository.candidate(1L, 10L, 20L)).thenReturn(candidate(10));
|
||||
when(repository.items(1L)).thenReturn(List.of(line));
|
||||
|
||||
Plan result = service.adjust(1L, 8L,
|
||||
@@ -1488,7 +1565,7 @@ class SmartLoadingServiceTest {
|
||||
new AdjustRequest(1, 2, 0, "adjust-picked"), 7L, "u"))
|
||||
.hasMessageContaining("不能低于已拣货箱数");
|
||||
|
||||
verify(repository, never()).candidate(anyLong(), anyLong(), anyLong(), anyLong());
|
||||
verify(repository, never()).candidate(anyLong(), anyLong(), anyLong());
|
||||
verify(repository, never()).touch(anyLong(), anyInt(), anyLong(), anyString());
|
||||
}
|
||||
|
||||
@@ -1550,7 +1627,7 @@ class SmartLoadingServiceTest {
|
||||
when(repository.plan(1)).thenReturn(plan, plan("EDITING", 1));
|
||||
when(repository.booking(99)).thenReturn(booking());
|
||||
when(repository.items(1)).thenReturn(List.of());
|
||||
when(repository.candidate(1, 100, 10, 20)).thenReturn(candidate(10));
|
||||
when(repository.candidate(1, 10, 20)).thenReturn(candidate(10));
|
||||
when(repository.activeItem(1L, 9L, 20L)).thenReturn(null);
|
||||
when(repository.touch(1, 0, 7, "u")).thenReturn(1);
|
||||
}
|
||||
@@ -1622,6 +1699,16 @@ class SmartLoadingServiceTest {
|
||||
value.orderStatusSnapshot(), value.expectedArrivalAt());
|
||||
}
|
||||
|
||||
private static Candidate withWarehouse(Candidate value, long warehouseId) {
|
||||
return new Candidate(value.accountId(), value.inboundId(), value.inboundDetailId(), value.orderId(),
|
||||
value.orderNo(), value.inboundCode(), warehouseId, value.channelCode(), value.channelName(),
|
||||
value.destinationWarehouseId(), value.destinationWarehouseCode(), value.destinationWarehouseName(),
|
||||
value.customerName(), value.goodsName(), value.availablePackageCount(), value.unitGrossWeightKg(),
|
||||
value.unitNetWeightKg(), value.unitVolumeCbm(), value.coLoadGroupId(), value.groupNo(),
|
||||
value.memberCount(), value.groupTotalBoxes(), value.locked(), value.blockReason(),
|
||||
value.orderStatusSnapshot(), value.expectedArrivalAt());
|
||||
}
|
||||
|
||||
private static Candidate withArrival(Candidate value, String expectedArrivalAt) {
|
||||
return new Candidate(value.accountId(), value.inboundId(), value.inboundDetailId(), value.orderId(),
|
||||
value.orderNo(), value.inboundCode(), value.warehouseId(), value.channelCode(), value.channelName(),
|
||||
|
||||
Reference in New Issue
Block a user