feat(firstleg): enforce indivisible coload loading

This commit is contained in:
2026-08-29 10:59:38 +08:00
parent ac6d3289a6
commit 3339ec91f9
11 changed files with 638 additions and 15 deletions
@@ -23,6 +23,8 @@ class PlatformSmartLoadingControllerContractTest {
@Test void everyMutationDeclaresDedicatedPermission() throws Exception {
authority("assign","platform:firstleg:smart-loading:assign",AuthenticatedUser.class,long.class,AssignRequest.class);
authority("assignInbound","platform:firstleg:smart-loading:assign",AuthenticatedUser.class,long.class,AssignInboundRequest.class);
authority("assignGroup","platform:firstleg:smart-loading:assign",AuthenticatedUser.class,long.class,AssignGroupRequest.class);
authority("removeGroup","platform:firstleg:smart-loading:delete",AuthenticatedUser.class,long.class,long.class,RemoveGroupRequest.class);
authority("recommend","platform:firstleg:smart-loading:assign",AuthenticatedUser.class,long.class,RecommendRequest.class);
authority("adjust","platform:firstleg:smart-loading:assign",AuthenticatedUser.class,long.class,long.class,AdjustRequest.class);
authority("warehouseRemark","platform:firstleg:preload:edit",AuthenticatedUser.class,long.class,long.class,WarehouseRemarkRequest.class);
@@ -13,7 +13,7 @@ class SmartLoadingCandidateMapperContractTest {
@Test
void candidateHasOnlyTheCanonicalMybatisConstructor() {
assertThat(Candidate.class.getDeclaredConstructors()).singleElement()
.satisfies(constructor -> assertThat(constructor.getParameterCount()).isEqualTo(18));
.satisfies(constructor -> assertThat(constructor.getParameterCount()).isEqualTo(24));
}
@Test
@@ -33,6 +33,8 @@ class SmartLoadingCandidateMapperContractTest {
.contains("o.process_status='WAIT_SPLIT'")
.contains("unitGrossWeightKg")
.contains("unitNetWeightKg")
.contains("NULL coLoadGroupId", "NULL groupNo", "NULL memberCount",
"NULL groupTotalBoxes", "NULL locked", "NULL blockReason")
.contains("o.actual_gross_weight_kg")
.contains("o.actual_net_weight_kg")
.doesNotContain("i.unit_weight_kg")
@@ -25,6 +25,9 @@ import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper;
import com.baiyue.firstleg.loading.service.LoadingDeliveryService;
import com.baiyue.firstleg.loading.bridge.dto.LoadingModelBridgeDtos.Link;
import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService;
import com.baiyue.firstleg.loading.coload.port.ColoadGroupAssignmentPort;
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.GroupSnapshot;
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.Member;
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
import com.baiyue.firstleg.mapper.LoadingPickItemMapper;
import com.baiyue.firstleg.repository.LoadingPickRepository;
@@ -43,6 +46,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.time.LocalDateTime;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
@@ -78,6 +82,8 @@ class LoadingPickServiceTest {
@MockBean
private LoadingDeliveryService loadingDeliveryService;
@MockBean
private ColoadGroupAssignmentPort coloadGroups;
@MockBean
private TruckAppointmentService truckAppointmentService;
@MockBean
private InboundStatusHistoryMapper inboundHistories;
@@ -800,6 +806,40 @@ class LoadingPickServiceTest {
verify(completionCommands, never()).insert(any());
}
@Test
void shortPickedColoadMemberCannotCreateCompletionCommandOrRemainderChild() {
LoadingPickTaskEntity task = task();
LoadingPickItemEntity shortPicked = item();
shortPicked.setInboundId(50L);
shortPicked.setPlannedPackageCount(5);
shortPicked.setPickedPackageCount(4);
shortPicked.setItemStatus("PARTIAL");
LoadingPickItemEntity complete = item();
complete.setId(31L);
complete.setInboundId(60L);
complete.setPlannedPackageCount(5);
complete.setPickedPackageCount(5);
complete.setItemStatus("PICKED");
GroupSnapshot group = coloadGroup("LOCKED", 10L,
new Member(101L, 301L, 50L, 5), new Member(202L, 302L, 60L, 5));
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.allTaskItemsResolved(20L)).thenReturn(true);
when(repository.inboundOwners(20L)).thenReturn(List.of(
new LoadingPickItemMapper.InboundOwner(101L, 50L),
new LoadingPickItemMapper.InboundOwner(202L, 60L)));
when(repository.items(20L)).thenReturn(List.of(shortPicked, complete));
when(coloadGroups.findByInbound(101L, 50L)).thenReturn(group);
when(coloadGroups.findByInbound(202L, 60L)).thenReturn(group);
assertThatThrownBy(() -> service.complete(20L,
new CompleteLoadingRequest(0, "complete-short-coload", "短拣异常"), 9L, "operator"))
.isInstanceOf(BizException.class).hasMessageContaining("全组箱数守恒");
verify(completionCommands, never()).insert(any());
verify(repository, never()).acceptCompletion(anyLong(), anyInt());
verify(settlementService, never()).settleOwner(anyLong(), anyLong(), anyLong(), anyString());
}
@Test
void workerProcessesFifteenInboundOwnersInStableOrderAndFinalizesOnce() {
LoadingPickTaskEntity completing = task();
@@ -841,6 +881,10 @@ class LoadingPickServiceTest {
when(repository.approve(20L, 9L, "operator", "checked")).thenReturn(1);
when(repository.completeAccepted(20L, 9L, "operator")).thenReturn(1);
when(completionCommands.complete(903L, "worker-multi")).thenReturn(true);
GroupSnapshot group = coloadGroup("LOCKED", 10L,
new Member(101L, 301L, 50L, 1), new Member(101L, 302L, 60L, 1),
new Member(202L, 303L, 70L, 1), new Member(202L, 304L, 80L, 1));
when(coloadGroups.findByInbound(anyLong(), anyLong())).thenReturn(group);
service.processCompletion(completionCommand(903L, "async-multi"), "worker-multi");
@@ -855,6 +899,8 @@ class LoadingPickServiceTest {
"COMPLETE_LOADING".equals(operation.getActionType())
&& "async-multi".equals(operation.getOperationId())));
verify(loadingListService, times(1)).publishCompletedEvent(10L);
verify(coloadGroups).consumeWholeGroup(eq(700L), eq(10L),
org.mockito.ArgumentMatchers.startsWith("PDA-CONSUME-"), eq(9L), eq("operator"));
verify(completionCommands).complete(903L, "worker-multi");
}
@@ -1200,4 +1246,9 @@ class LoadingPickServiceTest {
return assignment;
}
private static GroupSnapshot coloadGroup(String status, Long lockedPlanId, Member... members) {
return new GroupSnapshot(700L, "CLG-700", status, 101L, "FBA", "FBA", 201L,
"FBA1", lockedPlanId, 1, List.of(members), LocalDateTime.now(), LocalDateTime.now());
}
}
@@ -19,6 +19,9 @@ import com.baiyue.firstleg.entity.LoadingPlanItemEntity;
import com.baiyue.firstleg.entity.InboundOrderEntity;
import com.baiyue.firstleg.repository.SmartLoadingRepository;
import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService;
import com.baiyue.firstleg.loading.coload.port.ColoadGroupAssignmentPort;
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.GroupSnapshot;
import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.Member;
import com.baiyue.firstleg.split.service.SplitPreloadService;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.FeignException;
@@ -40,6 +43,9 @@ import java.sql.SQLException;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -57,6 +63,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.times;
@SpringJUnitConfig(SmartLoadingServiceTest.Config.class)
class SmartLoadingServiceTest {
@@ -65,6 +72,7 @@ class SmartLoadingServiceTest {
@MockBean private LoadingPickService loadingPickService;
@MockBean private LoadingModelBridgeService loadingModelBridge;
@MockBean private SplitPreloadService splitPreloadService;
@MockBean private ColoadGroupAssignmentPort coloadGroups;
@MockBean private FirstlegDocumentNumberGenerator documentNumbers;
@Resource private SmartLoadingService service;
@@ -110,10 +118,12 @@ class SmartLoadingServiceTest {
void groupsCandidateSpecificationsByInboundCodeForQuantityOnlyPlanning() {
Candidate first = new Candidate(9L, 10L, 20L, 30L, "O", "I", 100L,
"FBA", "FBA渠道", 200L, "FBA1", "FBA仓", "客户", "服装", 3,
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.2"));
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.2"),
null, null, null, null, null, null);
Candidate second = new Candidate(9L, 10L, 21L, 30L, "O", "I", 100L,
"FBA", "FBA渠道", 200L, "FBA1", "FBA仓", "客户", "鞋类", 7,
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.5"));
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.5"),
null, null, null, null, null, null);
when(repository.booking(99L)).thenReturn(booking());
when(repository.candidates(100L)).thenReturn(List.of(first, second));
@@ -129,17 +139,218 @@ class SmartLoadingServiceTest {
});
}
@Test
void exposesWholeColoadGroupFactsOnEveryMemberCandidate() {
Candidate first = candidate(9L, 10L, 20L, 30L, 4);
Candidate second = candidate(19L, 11L, 21L, 31L, 6);
GroupSnapshot group = group("ACTIVE", null,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
when(repository.booking(99L)).thenReturn(booking());
when(repository.candidates(100L)).thenReturn(List.of(first, second));
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
when(coloadGroups.findByInbound(19L, 11L)).thenReturn(group);
var result = service.inboundCandidates(99L, 100L);
assertThat(result).hasSize(2).allSatisfy(candidate -> {
assertThat(candidate.coLoadGroupId()).isEqualTo(700L);
assertThat(candidate.groupNo()).isEqualTo("CLG-700");
assertThat(candidate.memberCount()).isEqualTo(2);
assertThat(candidate.groupTotalBoxes()).isEqualTo(10);
assertThat(candidate.locked()).isFalse();
assertThat(candidate.blockReason()).isNull();
});
}
@Test
void rejectsIndividualAssignmentForColoadMemberWithoutWriting() {
stubAssignment();
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group("ACTIVE", null,
new Member(9L, 30L, 10L, 10), new Member(19L, 31L, 11L, 5)));
assertThatThrownBy(() -> service.assign(1L,
new AssignRequest(10L, 20L, 10, 0, "individual-group-member"), 7L, "u"))
.isInstanceOf(BizException.class).hasMessageContaining("整组分配");
verify(repository, never()).touch(anyLong(), anyInt(), anyLong(), anyString());
verify(splitPreloadService, never()).ensurePendingForLoadingAllocation(
anyLong(), anyLong(), anyLong(), anyString());
}
@Test
void atomicallyAssignsEveryMemberWithItsFullAvailablePackageCount() {
Candidate first = candidate(9L, 10L, 20L, 30L, 4);
Candidate second = candidate(19L, 11L, 21L, 31L, 6);
GroupSnapshot active = group("ACTIVE", null,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
GroupSnapshot locked = group("LOCKED", 1L,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
AtomicInteger version = new AtomicInteger();
List<LoadingPlanItemEntity> saved = new ArrayList<>();
when(repository.plan(1L)).thenAnswer(invocation -> plan("EDITING", version.get()));
when(repository.planByBooking(99L)).thenAnswer(invocation -> plan("EDITING", version.get()));
when(repository.booking(99L)).thenReturn(booking());
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.items(1L)).thenAnswer(invocation -> List.copyOf(saved));
when(repository.activeItemsByInbound(anyLong(), anyLong())).thenReturn(List.of());
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 -> {
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.size());
saved.add(item);
return null;
}).when(repository).insert(any(LoadingPlanItemEntity.class));
when(cargoClient.detail(anyString(), anyLong(), anyLong(), anyLong())).thenAnswer(invocation -> {
long orderId = invocation.getArgument(2);
long detailId = invocation.getArgument(3);
return ApiResponse.success(new OrderCargoClient.CargoBinding(detailId, orderId, 1,
"货物", orderId == 30L ? 4 : 6, BigDecimal.TEN, BigDecimal.ONE));
});
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(active);
when(coloadGroups.findByInbound(19L, 11L)).thenReturn(active);
when(coloadGroups.lockWholeGroupForAssignment(eq(9L), eq(10L), eq(1L),
anyString(), eq(7L), eq("u"))).thenReturn(locked);
Plan result = service.assignGroup(1L,
new com.baiyue.firstleg.dto.SmartLoadingDtos.AssignGroupRequest(
10L, 0, "assign-whole-group"), 7L, "u");
assertThat(result.version()).isEqualTo(2);
assertThat(saved).extracting(LoadingPlanItemEntity::getInboundId,
LoadingPlanItemEntity::getPackageCount).containsExactlyInAnyOrder(
org.assertj.core.groups.Tuple.tuple(10L, 4),
org.assertj.core.groups.Tuple.tuple(11L, 6));
verify(coloadGroups).lockWholeGroupForAssignment(eq(9L), eq(10L), eq(1L),
org.mockito.ArgumentMatchers.startsWith("LOCK-"), eq(7L), eq("u"));
verify(loadingModelBridge, times(2)).bindIncrementalAllocation(eq(1L), anyLong(), anyLong(),
eq(7L), eq("u"), anyString());
}
@Test
void recommendSkipsWholeThreeMemberGroupWhenCombinedCapacityDoesNotFit() {
Candidate first = candidate(9L, 10L, 20L, 30L, 5);
Candidate second = candidate(19L, 11L, 21L, 31L, 5);
Candidate third = candidate(29L, 12L, 22L, 32L, 5);
GroupSnapshot group = group("ACTIVE", null,
new Member(9L, 30L, 10L, 5), new Member(19L, 31L, 11L, 5),
new Member(29L, 32L, 12L, 5));
ContainerBookingEntity small = booking();
small.setCapacityCbm(new BigDecimal("5"));
LoadingPlanEntity plan = plan("EDITING", 0);
when(repository.plan(1L)).thenReturn(plan);
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(coloadGroups.findByInbound(anyLong(), anyLong())).thenReturn(group);
Plan result = service.recommend(1L, new RecommendRequest(0, "recommend-group-too-large"), 7L, "u");
assertThat(result.items()).isEmpty();
verify(coloadGroups, never()).lockWholeGroupForAssignment(anyLong(), anyLong(), anyLong(),
anyString(), anyLong(), anyString());
verify(repository, never()).touch(anyLong(), anyInt(), anyLong(), anyString());
}
@Test
void adjustAndIndividualDeleteRejectColoadMembersBeforeAnyWrite() {
LoadingPlanEntity plan = plan("EDITING", 0);
LoadingPlanItemEntity item = item(8L, 9L, 20L, 4);
when(repository.plan(1L)).thenReturn(plan);
when(repository.item(1L, 8L)).thenReturn(item);
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group("LOCKED", 1L,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6)));
assertThatThrownBy(() -> service.adjust(1L, 8L,
new AdjustRequest(4, 0, 0, "adjust-group-member"), 7L, "u"))
.isInstanceOf(BizException.class).hasMessageContaining("整组分配");
assertThatThrownBy(() -> service.delete(1L, 8L,
new DeleteRequest(0, 0, "delete-group-member"), 7L, "u"))
.isInstanceOf(BizException.class).hasMessageContaining("整组分配");
verify(repository, never()).touch(anyLong(), anyInt(), anyLong(), anyString());
verify(repository, never()).remove(anyLong(), anyLong(), anyInt(), anyLong(), anyString());
verify(loadingPickService, never()).remove(anyLong());
}
@Test
void pushPreloadRejectsIncompleteGroupBeforeAnyLifecycleOrPlanWrite() {
LoadingPlanEntity plan = plan("EDITING", 0);
LoadingPlanItemEntity first = item(8L, 9L, 20L, 4);
GroupSnapshot group = group("LOCKED", 1L,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
when(repository.plan(1L)).thenReturn(plan);
when(repository.booking(99L)).thenReturn(booking());
when(repository.items(1L)).thenReturn(List.of(first));
when(repository.activeItemsByInbound(9L, 10L)).thenReturn(List.of(first));
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
assertThatThrownBy(() -> service.pushPreload(1L, "push-incomplete-group",
new PushRequest(0), 7L, "u"))
.isInstanceOf(BizException.class).hasMessageContaining("全部在同一柜");
verify(repository, never()).push(anyLong(), anyString(), anyInt(), anyLong(), anyString());
verify(splitPreloadService, never()).ensurePendingForLoadingAllocation(
anyLong(), anyLong(), anyLong(), anyString());
verify(loadingModelBridge, never()).bindAllocatedBeforeLoading(
anyLong(), anyLong(), anyString(), anyString());
}
@Test
void removesEveryGroupMemberAndUnlocksOnlyAfterAllRowsAreRemoved() {
LoadingPlanEntity plan = plan("EDITING", 0);
LoadingPlanEntity after = plan("EDITING", 1);
LoadingPlanItemEntity first = item(8L, 9L, 20L, 4);
LoadingPlanItemEntity second = item(9L, 19L, 21L, 6);
second.setInboundId(11L);
GroupSnapshot group = group("LOCKED", 1L,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
when(repository.plan(1L)).thenReturn(plan, after);
when(repository.booking(99L)).thenReturn(booking());
when(repository.items(1L)).thenReturn(List.of(first, second), List.of());
when(repository.activeItemsByInbound(9L, 10L)).thenReturn(List.of(first));
when(repository.activeItemsByInbound(19L, 11L)).thenReturn(List.of(second));
when(repository.touch(1L, 0, 7L, "u")).thenReturn(1);
when(repository.remove(eq(1L), anyLong(), eq(0), eq(7L), eq("u"))).thenReturn(1);
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
when(coloadGroups.findByInbound(19L, 11L)).thenReturn(group);
when(coloadGroups.unlockWholeGroupAfterRemoval(eq(700L), eq(1L),
anyString(), eq(7L), eq("u"))).thenReturn(group("ACTIVE", null,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6)));
Plan result = service.removeGroup(1L, 700L,
new com.baiyue.firstleg.dto.SmartLoadingDtos.RemoveGroupRequest(
0, "remove-whole-group"), 7L, "u");
assertThat(result.items()).isEmpty();
verify(repository, times(2)).remove(eq(1L), anyLong(), eq(0), eq(7L), eq("u"));
verify(coloadGroups).unlockWholeGroupAfterRemoval(eq(700L), eq(1L),
org.mockito.ArgumentMatchers.startsWith("UNLOCK-"), eq(7L), eq("u"));
}
@Test
void proportionallyDistributesInboundQuantityWithoutLosingCartons() {
Candidate first = new Candidate(9L, 10L, 20L, 30L, "O", "I", 100L,
"FBA", "FBA渠道", 200L, "FBA1", "FBA仓", "客户", "A", 30,
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.2"));
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.2"),
null, null, null, null, null, null);
Candidate second = new Candidate(9L, 10L, 21L, 30L, "O", "I", 100L,
"FBA", "FBA渠道", 200L, "FBA1", "FBA仓", "客户", "B", 40,
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.5"));
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.5"),
null, null, null, null, null, null);
Candidate third = new Candidate(9L, 10L, 22L, 30L, "O", "I", 100L,
"FBA", "FBA渠道", 200L, "FBA1", "FBA仓", "客户", "C", 30,
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.8"));
new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.8"),
null, null, null, null, null, null);
var result = service.proportionalAllocations(List.of(first, second, third), 60);
@@ -987,8 +1198,19 @@ class SmartLoadingServiceTest {
}
private static Candidate candidate(int boxes) {
return new Candidate(9L, 10L, 20L, 30L, "O", "I", 100L, "FBA", "FBA渠道", 200L,
"FBA1", "FBA仓", "客户", "货物", boxes, new BigDecimal("2"), new BigDecimal("1.5"), new BigDecimal("0.5"));
return candidate(9L, 10L, 20L, 30L, boxes);
}
private static Candidate candidate(long tenantId, long inboundId, long detailId, long orderId, int boxes) {
return new Candidate(tenantId, inboundId, detailId, orderId, "O" + orderId, "I" + inboundId,
100L, "FBA", "FBA渠道", 200L, "FBA1", "FBA仓", "客户", "货物", boxes,
new BigDecimal("2"), new BigDecimal("1.5"),
new BigDecimal("0.5"), null, null, null, null, null, null);
}
private static GroupSnapshot group(String status, Long lockedPlanId, Member... members) {
return new GroupSnapshot(700L, "CLG-700", status, 100L, "FBA", "FBA", 200L,
"FBA1", lockedPlanId, 0, List.of(members), LocalDateTime.now(), LocalDateTime.now());
}
private static ContainerBookingEntity booking() {
@@ -16,6 +16,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.util.List;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -139,4 +141,12 @@ class SplitPreloadServiceTest {
verify(repository, never()).createPlan(any());
}
@Test
void splitPreloadNeverCreatesInboundChildrenOrFulfillmentSlices() throws Exception {
String source = Files.readString(Path.of(
"src/main/java/com/baiyue/firstleg/split/service/SplitPreloadService.java"));
assertThat(source).doesNotContain("cloneChild", "OrderFulfillmentSplitClient",
"PdaPickSettlementService", "REMAINDER");
}
}