From ef0f6918459bd1ff64b37108af8425d0a80044ba Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 22 Oct 2026 18:47:58 +0800 Subject: [PATCH] fix(booking): require arrival time before release --- .../service/OceanBookingService.java | 4 ++-- .../resources/openapi/ocean-bookings-v1.yaml | 2 +- .../service/OceanBookingServiceTest.java | 19 ++++++------------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingService.java b/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingService.java index c7153d1ec..7faa97e10 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingService.java @@ -262,13 +262,13 @@ public class OceanBookingService { } } private static void validateRange(LocalDateTime from, LocalDateTime to) { if (from != null && to != null && to.isBefore(from)) throw badRequest("预计到港时间不能早于预计开船时间"); } - /** 放舱核对必要运输资料;预计到港为可选计划,不阻断放舱。 */ + /** 放舱要求预计到港,供关联柜次的到港日历及默认到仓日期使用。 */ private static void validateRelease(OceanBookingEntity booking, List parties, List requirements) { if (!StringUtils.hasText(booking.getChannelCode()) || booking.getWarehouseId() == null || !StringUtils.hasText(booking.getBillOfLadingNo()) || !StringUtils.hasText(booking.getVesselName()) || !StringUtils.hasText(booking.getVoyageNo()) || booking.getEstimatedSailingAt() == null - || booking.getShippingCompanyId() == null + || booking.getEstimatedArrivalAt() == null || booking.getShippingCompanyId() == null || (!StringUtils.hasText(booking.getDeparturePortName()) && !StringUtils.hasText(booking.getDeparturePortCode())) || (!StringUtils.hasText(booking.getDestinationPortName()) && !StringUtils.hasText(booking.getDestinationPortCode())) || !StringUtils.hasText(booking.getPlaceOfDelivery()) diff --git a/firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml b/firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml index 48ef6a28b..e2386486b 100644 --- a/firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml +++ b/firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml @@ -200,7 +200,7 @@ components: destinationPortName: {type: string, nullable: true} placeOfDelivery: {type: string, nullable: true} estimatedSailingAt: {type: string, format: date-time, nullable: true} - estimatedArrivalAt: {type: string, format: date-time, nullable: true, description: 可选预计到港时间;放舱不要求填写,填写时不得早于预计开船时间} + estimatedArrivalAt: {type: string, format: date-time, nullable: true, description: 草稿可留空,放舱前必填;不得早于预计开船时间,关联柜次后作为到港日历及默认到仓日期来源} remark: {type: string, nullable: true} freightTerm: {type: string, maxLength: 64, nullable: true, description: 运费条款;新建页面默认FREIGHT PREPAID} serviceTerm: {type: string, maxLength: 64, nullable: true, description: 运输条款;新建页面默认CY-CY} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingServiceTest.java index edfa3e646..1e527bcea 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingServiceTest.java @@ -231,24 +231,17 @@ class OceanBookingServiceTest { verify(repository, times(1)).transition(1L, "DRAFT", "RELEASED", 3, 9L, "admin"); } - /** 不录预计到港仍可放舱,其余资料及附件门禁保持有效。 */ + /** 缺预计到港不能放舱,避免关联柜次后丢失日历及默认到仓日期来源。 */ @Test - void releasesWithoutEstimatedArrival() { - stubMasterData(); + void rejectsReleaseWithoutEstimatedArrival() { OceanBookingEntity draft = completeBooking("DRAFT", 3); - OceanBookingEntity released = completeBooking("RELEASED", 4); draft.setEstimatedArrivalAt(null); - released.setEstimatedArrivalAt(null); - when(repository.find(1L)).thenReturn(draft, released); + when(repository.find(1L)).thenReturn(draft); when(repository.parties(1L)).thenReturn(parties()); when(repository.requirements(1L)).thenReturn(List.of(requirement())); - when(repository.transition(1L, "DRAFT", "RELEASED", 3, 9L, "admin")).thenReturn(1); - - Detail result = service.release(1L, 9L, "admin", "release-no-arrival", new ReleaseRequest(3, "确认放舱")); - - assertThat(result.oceanBooking().getStatus()).isEqualTo("RELEASED"); - assertThat(result.oceanBooking().getEstimatedArrivalAt()).isNull(); - verify(documents).requireActiveValidDocument(draft); + assertThatThrownBy(() -> service.release(1L, 9L, "admin", "release-no-arrival", new ReleaseRequest(3, "确认放舱"))) + .isInstanceOf(BizException.class).hasMessageContaining("尚未填写完整"); + verify(repository, never()).transition(anyLong(), anyString(), anyString(), anyInt(), anyLong(), anyString()); } @Test