This commit is contained in:
2026-08-31 10:31:51 +08:00
parent d6f47e650c
commit b386f35ab4
11 changed files with 115 additions and 42 deletions
@@ -39,6 +39,7 @@ class ColoadGroupOpenApiContractTest {
.contains("fullPackageCount")
.contains("platform:firstleg:smart-loading:assign")
.contains("platform:firstleg:smart-loading:list")
.contains("任一冻结成员缺少有效 inboundCode 时失败关闭")
.contains("全部 WAIT_SPLIT")
.contains("国内仓和渠道一致")
.doesNotContain("destinationType")
@@ -39,7 +39,8 @@ class ColoadGroupServiceTest {
@Test
void readsCrossCustomerTwoMemberGroupByEitherInboundCodeWithoutInternalIdentifiers() {
when(mapper.groupsByInboundCode("IN-A")).thenReturn(List.of(lookup(500L, "ACTIVE")));
when(mapper.effectiveMemberCodes(500L)).thenReturn(List.of(code("IN-A"), code("IN-B")));
when(mapper.effectiveMemberCodes(500L)).thenReturn(List.of(
code(1L, 1001L, "IN-A"), code(2L, 1002L, "IN-B")));
var result = service.queryByInboundCode(" IN-A ");
@@ -50,10 +51,11 @@ class ColoadGroupServiceTest {
}
@Test
void returnsEveryEffectiveSplitFragmentAndEliminatesDuplicateInboundCodes() {
void returnsEveryEffectiveSplitFragmentWithItsUniqueInboundCode() {
when(mapper.groupsByInboundCode("MASTER-A-2")).thenReturn(List.of(lookup(500L, "LOCKED")));
when(mapper.effectiveMemberCodes(500L)).thenReturn(List.of(
code("MASTER-A-3"), code("MASTER-A-2"), code("MASTER-A-2"), code("ORDER-B")));
code(1L, 1001L, "MASTER-A-3"), code(2L, 1002L, "MASTER-A-2"),
code(3L, 1003L, "ORDER-B")));
var result = service.queryByInboundCode("MASTER-A-2");
@@ -66,7 +68,8 @@ class ColoadGroupServiceTest {
@Test
void preservesConsumedStatusWhileReadingClosedFrozenMemberships() {
when(mapper.groupsByInboundCode("IN-A")).thenReturn(List.of(lookup(500L, "CONSUMED")));
when(mapper.effectiveMemberCodes(500L)).thenReturn(List.of(code("IN-A"), code("IN-B")));
when(mapper.effectiveMemberCodes(500L)).thenReturn(List.of(
code(1L, 1001L, "IN-A"), code(2L, 1002L, "IN-B")));
assertThat(service.queryByInboundCode("IN-A").status()).isEqualTo("CONSUMED");
}
@@ -84,6 +87,21 @@ class ColoadGroupServiceTest {
.isInstanceOf(BizException.class).hasMessageContaining("多个有效");
}
@Test
void failsClosedInsteadOfReturningMissingOrDuplicateMemberInboundCode() {
when(mapper.groupsByInboundCode("BROKEN")).thenReturn(List.of(lookup(500L, "ACTIVE")));
when(mapper.effectiveMemberCodes(500L)).thenReturn(List.of(
code(1L, 1001L, "IN-A"), code(2L, 1002L, " ")));
when(mapper.groupsByInboundCode("DUPLICATE")).thenReturn(List.of(lookup(501L, "LOCKED")));
when(mapper.effectiveMemberCodes(501L)).thenReturn(List.of(
code(3L, 1003L, "IN-C"), code(4L, 1004L, "IN-C")));
assertThatThrownBy(() -> service.queryByInboundCode("BROKEN"))
.isInstanceOf(BizException.class).hasMessageContaining("缺失或无效");
assertThatThrownBy(() -> service.queryByInboundCode("DUPLICATE"))
.isInstanceOf(BizException.class).hasMessageContaining("重复");
}
@Test
void internalOrderAggregationKeepsTechnicalGroupSnapshotOffPlatformContract() {
when(mapper.linksByOrderIds(List.of(11L, 12L))).thenReturn(List.of(
@@ -273,6 +291,7 @@ class ColoadGroupServiceTest {
private static MemberRow member(long tenantId, long orderId, long inboundId, int packages) {
MemberRow value = new MemberRow();
value.setTenantId(tenantId); value.setOrderId(orderId); value.setInboundId(inboundId);
value.setInboundCode("IN-" + inboundId);
value.setFullPackageCount(packages);
return value;
}
@@ -284,8 +303,10 @@ class ColoadGroupServiceTest {
return value;
}
private static MemberCodeRow code(String inboundCode) {
private static MemberCodeRow code(long memberId, long inboundId, String inboundCode) {
MemberCodeRow value = new MemberCodeRow();
value.setMemberId(memberId);
value.setInboundId(inboundId);
value.setInboundCode(inboundCode);
return value;
}
@@ -69,7 +69,8 @@ class ColoadGroupSqlContractTest {
.contains("'ACTIVE','LOCKED','CONSUMED'")
.doesNotContain("group_no", "order_id=#{");
assertThat(memberSql)
.contains("SELECT DISTINCT inbound.inbound_code inboundCode")
.contains("member.id memberId", "member.inbound_id inboundId", "inbound.inbound_code inboundCode")
.contains("LEFT JOIN fl_inbound_order inbound")
.contains("member.group_id=#{groupId}")
.contains("inbound.deleted=0")
.doesNotContain("member.active_flag=1", "inbound_role", "split_status", "split_purpose");
@@ -822,7 +822,7 @@ class LoadingPickServiceTest {
complete.setPickedPackageCount(5);
complete.setItemStatus("PICKED");
GroupSnapshot group = coloadGroup("LOCKED", 10L,
new Member(101L, 301L, 50L, 5), new Member(101L, 301L, 60L, 5));
new Member(101L, 301L, 50L, "IN-50", 5), new Member(101L, 301L, 60L, "IN-60", 5));
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.allTaskItemsResolved(20L)).thenReturn(true);
when(repository.inboundOwners(20L)).thenReturn(List.of(
@@ -883,8 +883,8 @@ class LoadingPickServiceTest {
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));
new Member(101L, 301L, 50L, "IN-50", 1), new Member(101L, 302L, 60L, "IN-60", 1),
new Member(202L, 303L, 70L, "IN-70", 1), new Member(202L, 304L, 80L, "IN-80", 1));
when(coloadGroups.findByInbound(anyLong(), anyLong())).thenReturn(group);
service.processCompletion(completionCommand(903L, "async-multi"), "worker-multi");
@@ -144,7 +144,7 @@ class SmartLoadingServiceTest {
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));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(19L, 31L, 11L, "IN-11", 6));
when(repository.booking(99L)).thenReturn(booking());
when(repository.candidates(100L)).thenReturn(List.of(first, second));
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
@@ -166,7 +166,7 @@ class SmartLoadingServiceTest {
void rejectsIndividualAssignmentForColoadMemberWithoutWriting() {
stubAssignment();
GroupSnapshot group = group("ACTIVE", null,
new Member(9L, 30L, 10L, 10), new Member(19L, 31L, 11L, 5));
new Member(9L, 30L, 10L, "IN-10", 10), new Member(19L, 31L, 11L, "IN-11", 5));
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
assertThatThrownBy(() -> service.assign(1L,
@@ -183,9 +183,9 @@ class SmartLoadingServiceTest {
Candidate first = candidate(9L, 10L, 20L, 30L, 4);
Candidate second = candidate(9L, 11L, 21L, 30L, 6, "FBA2");
GroupSnapshot active = group("ACTIVE", null,
new Member(9L, 30L, 10L, 4), new Member(9L, 30L, 11L, 6));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(9L, 30L, 11L, "IN-11", 6));
GroupSnapshot locked = group("LOCKED", 1L,
new Member(9L, 30L, 10L, 4), new Member(9L, 30L, 11L, 6));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(9L, 30L, 11L, "IN-11", 6));
AtomicInteger version = new AtomicInteger();
List<LoadingPlanItemEntity> saved = new ArrayList<>();
when(repository.plan(1L)).thenAnswer(invocation -> plan("EDITING", version.get()));
@@ -242,8 +242,8 @@ class SmartLoadingServiceTest {
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));
new Member(9L, 30L, 10L, "IN-10", 5), new Member(19L, 31L, 11L, "IN-11", 5),
new Member(29L, 32L, 12L, "IN-12", 5));
ContainerBookingEntity small = booking();
small.setCapacityCbm(new BigDecimal("5"));
LoadingPlanEntity plan = plan("EDITING", 0);
@@ -269,7 +269,7 @@ class SmartLoadingServiceTest {
Candidate groupSecond = candidate(9L, 12L, 22L, 32L, 4);
Candidate later = candidate(9L, 13L, 23L, 33L, 1);
GroupSnapshot group = group("ACTIVE", null,
new Member(9L, 31L, 11L, 4), new Member(9L, 32L, 12L, 4));
new Member(9L, 31L, 11L, "IN-11", 4), new Member(9L, 32L, 12L, "IN-12", 4));
ContainerBookingEntity small = booking();
small.setCapacityCbm(new BigDecimal("5"));
AtomicInteger version = new AtomicInteger();
@@ -321,7 +321,7 @@ class SmartLoadingServiceTest {
Candidate first = candidate(9L, 11L, 21L, 31L, 4);
Candidate second = candidate(9L, 12L, 22L, 32L, 4);
GroupSnapshot group = group("ACTIVE", null,
new Member(9L, 31L, 11L, 4), new Member(9L, 32L, 12L, 4));
new Member(9L, 31L, 11L, "IN-11", 4), new Member(9L, 32L, 12L, "IN-12", 4));
ContainerBookingEntity small = booking();
small.setCapacityCbm(new BigDecimal("3"));
when(repository.plan(1L)).thenReturn(plan("EDITING", 0));
@@ -348,7 +348,7 @@ class SmartLoadingServiceTest {
LoadingPlanEntity plan = plan("EDITING", 0);
LoadingPlanItemEntity item = item(8L, 9L, 20L, 4);
GroupSnapshot group = group("LOCKED", 1L,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(19L, 31L, 11L, "IN-11", 6));
when(repository.plan(1L)).thenReturn(plan);
when(repository.item(1L, 8L)).thenReturn(item);
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
@@ -370,7 +370,7 @@ class SmartLoadingServiceTest {
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));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(19L, 31L, 11L, "IN-11", 6));
when(repository.plan(1L)).thenReturn(plan);
when(repository.booking(99L)).thenReturn(booking());
when(repository.items(1L)).thenReturn(List.of(first));
@@ -396,7 +396,7 @@ class SmartLoadingServiceTest {
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));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(19L, 31L, 11L, "IN-11", 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());
@@ -407,7 +407,7 @@ class SmartLoadingServiceTest {
when(coloadGroups.findByInbound(9L, 10L)).thenReturn(group);
when(coloadGroups.findByInbound(19L, 11L)).thenReturn(group);
GroupSnapshot unlocked = group("ACTIVE", null,
new Member(9L, 30L, 10L, 4), new Member(19L, 31L, 11L, 6));
new Member(9L, 30L, 10L, "IN-10", 4), new Member(19L, 31L, 11L, "IN-11", 6));
when(coloadGroups.unlockWholeGroupAfterRemoval(eq(700L), eq(1L),
anyString(), eq(7L), eq("u"))).thenReturn(unlocked);