fix(firstleg): allow booking link before container pickup
This commit is contained in:
+6
-3
@@ -62,8 +62,9 @@ class ContainerControllerContractTest {
|
||||
.contains("首次关联允许 WAIT_LOADING 或已有预排货的 EDITING 模拟柜")
|
||||
.contains("RELEASED oceanBookingId")
|
||||
.contains("未满配 requirementId")
|
||||
.contains("唯一 containerNo")
|
||||
.contains("校验ISO 6346结构、设备类别和校验位")
|
||||
.contains("containerNo 可空")
|
||||
.contains("提柜后由拖车链调用柜次服务原子补录真实柜号")
|
||||
.contains("校验 ISO 6346 结构、设备类别、校验位和全局唯一性")
|
||||
.doesNotContain("/api/platform/v1/containers/{id}/transport:")
|
||||
.doesNotContain("ContainerOceanBookingUnlinkRequest")
|
||||
.doesNotContain("ContainerTransportUpdateRequest")
|
||||
@@ -81,7 +82,9 @@ class ContainerControllerContractTest {
|
||||
assertThat(openapi)
|
||||
.contains("/api/platform/v1/containers/{id}/clearance/document/{fileId}/download:")
|
||||
.contains("Content-Disposition 与 Cache-Control no-store")
|
||||
.contains("required: [oceanBookingId, requirementId, containerNo, expectedVersion]")
|
||||
.contains("required: [oceanBookingId, requirementId, expectedVersion]")
|
||||
.contains("containerNo: {type: string, nullable: true")
|
||||
.doesNotContain("required: [oceanBookingId, requirementId, containerNo, expectedVersion]")
|
||||
.contains("required: [id, bookingNo, cabinetNo, sourceType, recordStatus")
|
||||
.contains("sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING]")
|
||||
.contains("recordStatus: {type: string, enum: [ACTIVE, MERGED]")
|
||||
|
||||
+11
-2
@@ -75,14 +75,17 @@ class ContainerBookingMapperContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("货柜草稿更新不得形成真实柜号或内部柜次号写入口")
|
||||
void onlyOceanBookingLinkWritesInitialContainerNumber() throws Exception {
|
||||
@DisplayName("真实柜号只允许订舱关联或提柜后原子补录")
|
||||
void onlyBookingLinkOrPickupAssignmentWritesContainerNumber() throws Exception {
|
||||
String draftSql = String.join("\n", ContainerBookingMapper.class
|
||||
.getDeclaredMethod("updateDraft", ContainerBookingEntity.class, int.class,
|
||||
long.class, String.class).getAnnotation(Update.class).value());
|
||||
String linkSql = String.join("\n", Arrays.stream(ContainerBookingMapper.class.getDeclaredMethods())
|
||||
.filter(method -> method.getName().equals("linkReleasedBooking"))
|
||||
.findFirst().orElseThrow().getAnnotation(Update.class).value());
|
||||
String pickupSql = String.join("\n", ContainerBookingMapper.class
|
||||
.getDeclaredMethod("assignRealContainerNo", long.class, String.class, int.class,
|
||||
long.class, String.class).getAnnotation(Update.class).value());
|
||||
assertThat(draftSql)
|
||||
.contains("capacity_cbm")
|
||||
.contains("p.plan_status!='EDITING'")
|
||||
@@ -92,6 +95,11 @@ class ContainerBookingMapperContractTest {
|
||||
.doesNotContain(">");
|
||||
assertThat(linkSql).contains("container_no=#{containerNo}", "source_type='SIMULATION'",
|
||||
"ocean_booking_id IS NULL");
|
||||
assertThat(pickupSql)
|
||||
.contains("container_no=#{containerNo}", "container_no IS NULL", "ocean_booking_id IS NOT NULL",
|
||||
"ocean_booking_requirement_id IS NOT NULL", "version=#{version}", "fl_loading_pick_task",
|
||||
"fl_loading_cabinet_evidence", "fl_container_document")
|
||||
.doesNotContain("ocean_booking_id=#{");
|
||||
assertThat(Arrays.stream(ContainerBookingMapper.class.getDeclaredMethods()).map(java.lang.reflect.Method::getName))
|
||||
.doesNotContain("updateTransport", "unlinkReleasedBooking");
|
||||
}
|
||||
@@ -105,6 +113,7 @@ class ContainerBookingMapperContractTest {
|
||||
}) {
|
||||
assertThat(source)
|
||||
.contains("国内唯一权威真实集装箱号")
|
||||
.contains("提柜后可原子补录")
|
||||
.contains("UNIQUE KEY uk_container_booking_container_no (container_no)")
|
||||
.contains("CONSTRAINT chk_container_booking_iso6346")
|
||||
.contains("container_no REGEXP '^[A-Z]{3}[UJZ][0-9]{7}$'");
|
||||
|
||||
@@ -212,6 +212,58 @@ class ContainerServiceTest {
|
||||
verify(oceanBookings).insert(any(OceanBookingContainerAllocationEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("模拟柜允许不带真实柜号原子关联已发布订舱需求")
|
||||
void linksReleasedBookingWithoutRealContainerNumber() {
|
||||
stubLinkContext();
|
||||
ContainerBookingEntity container = repository.find(11L);
|
||||
when(repository.find(11L)).thenReturn(container, container);
|
||||
when(repository.linkReleasedBooking(eq(11L), eq(21L), eq(31L), isNull(),
|
||||
any(OceanBookingEntity.class), eq(2), eq(9L), eq("admin"))).thenReturn(1);
|
||||
|
||||
ContainerBookingEntity result = service.linkOceanBooking(11L, 9L, "admin",
|
||||
new OceanBookingLinkRequest(21L, 31L, null, 2));
|
||||
|
||||
assertThat(result.getContainerNo()).isNull();
|
||||
assertThat(result.getCabinetNo()).isEqualTo("柜-001");
|
||||
verify(repository, never()).containerNoExists(anyString(), anyLong());
|
||||
verify(repository).linkReleasedBooking(eq(11L), eq(21L), eq(31L), isNull(),
|
||||
any(OceanBookingEntity.class), eq(2), eq(9L), eq("admin"));
|
||||
verify(oceanBookings).insert(any(OceanBookingContainerAllocationEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("提柜后按柜次版本原子补录真实柜号")
|
||||
void assignsRealContainerNumberAfterPickup() {
|
||||
ContainerBookingEntity linked = booking("EDITING", 3);
|
||||
linked.setContainerNo(null); linked.setOceanBookingId(21L); linked.setOceanBookingRequirementId(31L);
|
||||
ContainerBookingEntity assigned = booking("EDITING", 4);
|
||||
assigned.setContainerNo("MSCU6639870"); assigned.setOceanBookingId(21L); assigned.setOceanBookingRequirementId(31L);
|
||||
when(repository.find(11L)).thenReturn(linked, assigned);
|
||||
when(repository.assignRealContainerNo(11L, "MSCU6639870", 3, 9L, "admin")).thenReturn(1);
|
||||
|
||||
ContainerBookingEntity result = service.assignRealContainerNo(
|
||||
11L, " ms cu 663987 0 ", 3, 9L, "admin");
|
||||
|
||||
assertThat(result.getContainerNo()).isEqualTo("MSCU6639870");
|
||||
verify(repository).assignRealContainerNo(11L, "MSCU6639870", 3, 9L, "admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("提柜补录真实柜号仍拒绝全局重复号")
|
||||
void rejectsDuplicateRealContainerNumberAfterPickup() {
|
||||
ContainerBookingEntity linked = booking("EDITING", 3);
|
||||
linked.setContainerNo(null); linked.setOceanBookingId(21L); linked.setOceanBookingRequirementId(31L);
|
||||
when(repository.find(11L)).thenReturn(linked);
|
||||
when(repository.containerNoExists("MSCU6639870", 11L)).thenReturn(true);
|
||||
|
||||
assertThatThrownBy(() -> service.assignRealContainerNo(
|
||||
11L, "MSCU6639870", 3, 9L, "admin"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("已存在");
|
||||
|
||||
verify(repository, never()).assignRealContainerNo(anyLong(), anyString(), anyInt(), anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("首次关联拒绝错误ISO 6346校验位")
|
||||
void rejectsInvalidContainerNumberCheckDigit() {
|
||||
|
||||
Reference in New Issue
Block a user