This commit is contained in:
2026-08-30 17:02:19 +08:00
parent 0aa77327d5
commit ca9e7b60e8
40 changed files with 1471 additions and 6 deletions
@@ -0,0 +1,46 @@
package com.baiyue.firstleg.controller;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.firstleg.dto.LoadingAssociationDtos;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.prepost.PreAuthorize;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThat;
class PlatformLoadingAssociationControllerContractTest {
@Test
void technicalAssociationIdsAreExplicitStringsInResponseDto() {
assertThat(LoadingAssociationDtos.Summary.class.getRecordComponents())
.filteredOn(component -> component.getName().endsWith("Id"))
.allSatisfy(component -> assertThat(component.getType()).isEqualTo(String.class));
assertThat(LoadingAssociationDtos.ItemReference.class.getRecordComponents()[0].getType())
.isEqualTo(String.class);
}
@Test
void summaryUsesSmartLoadingReadPermission() throws Exception {
Method method = PlatformLoadingAssociationController.class.getDeclaredMethod(
"summary", AuthenticatedUser.class, Long.class, String.class);
assertThat(method.getAnnotation(PreAuthorize.class).value())
.isEqualTo("hasAuthority('platform:firstleg:smart-loading:list')");
}
@Test
void openApiKeepsBusinessNumbersPrimaryAndTechnicalIdsAsAssociations() throws Exception {
String yaml = Files.readString(Path.of("src/main/resources/openapi/firstleg-v1.yaml"));
assertThat(yaml)
.contains("/api/platform/v1/first-leg/loading-associations/summary:")
.contains("inboundId 与 inboundCode 必须且只能提供一个")
.contains("LoadingAssociationSummary:")
.contains("orderNo:", "loadingPlanNo:", "cabinetNo:", "containerNo:", "coLoadGroupNo:")
.contains("pdaTaskStatus:")
.contains("loadingPlanId:", "containerBookingId:", "taskId:", "itemId:")
.contains("仅为技术关联,不得替代业务号作为UI主标识");
}
}
@@ -0,0 +1,38 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import static org.assertj.core.api.Assertions.assertThat;
class LoadingAssociationMapperContractTest {
@Test
void mapperIsExplicitAndReadsOnlyFirstlegOwnedTables() throws Exception {
assertThat(LoadingAssociationMapper.class).hasAnnotation(Mapper.class);
Method method = LoadingAssociationMapper.class.getDeclaredMethod("byInboundId", long.class);
String sql = String.join(" ", method.getAnnotation(Select.class).value());
assertThat(sql)
.contains("fl_inbound_order", "fl_loading_plan_item", "fl_loading_plan",
"fl_container_booking", "fl_loading_pick_task", "fl_coload_group_member")
.contains("plan.plan_no loadingPlanNo")
.contains("inbound.order_no orderNo")
.contains("booking.cabinet_no cabinetNo", "booking.container_no containerNo")
.contains("group_row.group_no coLoadGroupNo")
.contains("'UNASSIGNED'", "'IN_PROGRESS'", "'AWAITING_REVIEW'", "'PROCESSING'",
"'COMPLETION_FAILED'", "'COMPLETED'")
.doesNotContain("baiyue_order", "baiyue_warehouse", "baiyue_iam");
}
@Test
void inboundCodeQueryUsesExactBusinessIdentifier() throws Exception {
Method method = LoadingAssociationMapper.class.getDeclaredMethod("byInboundCode", String.class);
String sql = String.join(" ", method.getAnnotation(Select.class).value());
assertThat(sql).contains("inbound.inbound_code=#{inboundCode}")
.doesNotContain("LIKE CONCAT");
}
}
@@ -0,0 +1,97 @@
package com.baiyue.firstleg.service;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.mapper.LoadingAssociationMapper;
import com.baiyue.firstleg.mapper.LoadingAssociationMapper.Row;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(LoadingAssociationQueryService.class)
class LoadingAssociationQueryServiceTest {
@MockBean
private LoadingAssociationMapper mapper;
@Resource
private LoadingAssociationQueryService service;
@Test
void returnsBusinessIdentifiersAndPreservesEveryTechnicalItemReference() {
Row first = row(800L);
Row second = row(801L);
when(mapper.byInboundCode("ZBYHK2608300001-2")).thenReturn(List.of(first, second));
var result = service.summary(null, " ZBYHK2608300001-2 ");
assertThat(result.inboundCode()).isEqualTo("ZBYHK2608300001-2");
assertThat(result.orderNo()).isEqualTo("FO-260830-0001");
assertThat(result.inboundId()).isEqualTo("100");
assertThat(result.loadingPlanId()).isEqualTo("200");
assertThat(result.loadingPlanNo()).isEqualTo("LP-260830-0001");
assertThat(result.cabinetNo()).isEqualTo("CAB-260830-0001");
assertThat(result.containerNo()).isEqualTo("MSCU1234567");
assertThat(result.loadingStatus()).isEqualTo("LOADING");
assertThat(result.pdaTaskStatus()).isEqualTo("AWAITING_REVIEW");
assertThat(result.coLoadGroupNo()).isEqualTo("CLG-260830-0001");
assertThat(result.items()).extracting(item -> item.itemId()).containsExactly("800", "801");
verify(mapper).byInboundCode("ZBYHK2608300001-2");
}
@Test
void returnsFragmentIdentityWhenItHasNoLoadingAssociation() {
Row row = new Row();
row.setInboundId(100L);
row.setInboundCode("ZBYHK2608300002");
when(mapper.byInboundId(100L)).thenReturn(List.of(row));
var result = service.summary(100L, null);
assertThat(result.inboundCode()).isEqualTo("ZBYHK2608300002");
assertThat(result.loadingPlanId()).isNull();
assertThat(result.pdaTaskStatus()).isNull();
assertThat(result.items()).isEmpty();
}
@Test
void selectorMustBeExclusiveAndExactCodeCannotResolveMultipleFragments() {
assertThatThrownBy(() -> service.summary(null, null))
.isInstanceOf(BizException.class).hasMessageContaining("必须且只能");
assertThatThrownBy(() -> service.summary(100L, "ZBYHK2608300001"))
.isInstanceOf(BizException.class).hasMessageContaining("必须且只能");
Row first = row(800L);
Row other = row(801L);
other.setInboundId(101L);
when(mapper.byInboundCode("DUPLICATE")).thenReturn(List.of(first, other));
assertThatThrownBy(() -> service.summary(null, "DUPLICATE"))
.isInstanceOfSatisfying(BizException.class, error ->
assertThat(error.getResultCode()).isEqualTo(ResultCode.CONFLICT));
}
private static Row row(long itemId) {
Row row = new Row();
row.setInboundId(100L);
row.setInboundCode("ZBYHK2608300001-2");
row.setOrderNo("FO-260830-0001");
row.setItemId(itemId);
row.setLoadingPlanId(200L);
row.setLoadingPlanNo("LP-260830-0001");
row.setContainerBookingId(300L);
row.setCabinetNo("CAB-260830-0001");
row.setContainerNo("MSCU1234567");
row.setLoadingStatus("LOADING");
row.setTaskId(400L);
row.setPdaTaskStatus("AWAITING_REVIEW");
row.setCoLoadGroupId(500L);
row.setCoLoadGroupNo("CLG-260830-0001");
return row;
}
}