From 15ab355dc219f913be8aef5ab3c0ca959ef60dbe Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 10 Oct 2026 18:37:38 +0800 Subject: [PATCH] fix(appointments): include destination timezone in batch preview --- .../AppointmentBatchPreviewService.java | 5 +++-- .../resources/openapi/appointment-planning-v1.yaml | 1 + .../AppointmentBatchPreviewServiceTest.java | 13 ++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewService.java index 16f20a393..d879d084e 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewService.java @@ -16,7 +16,7 @@ public class AppointmentBatchPreviewService { this.sources=sources;this.mapper=mapper; } public record Preview(AppointmentPlanningPolicy.Group group,String originWarehouseName, - String destinationWarehouseCode,List sources, + String destinationWarehouseCode,String destinationTimezone,List sources, List missingFields) { } public Preview preview(List refs) { var resolved=sources.resolveBatch(refs); @@ -38,7 +38,8 @@ public class AppointmentBatchPreviewService { }).toList(); try { var group=AppointmentPlanningPolicy.group(cargo); - return new Preview(group,resolved.get(0).originWarehouseName(),resolved.get(0).destinationWarehouseCode(),resolved, + return new Preview(group,resolved.get(0).originWarehouseName(),resolved.get(0).destinationWarehouseCode(), + sources.destinationTimezone(resolved.get(0).destinationWarehouseCode()),resolved, group.unknownQuantitySources()>0?List.of("READY_WINDOW_UNVERIFIED","CARGO_QUANTITY_REVIEW"):List.of("READY_WINDOW_UNVERIFIED")); } catch(IllegalArgumentException error) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST,error.getMessage(),error); diff --git a/lastleg-service/src/main/resources/openapi/appointment-planning-v1.yaml b/lastleg-service/src/main/resources/openapi/appointment-planning-v1.yaml index faf22b634..d308929f7 100644 --- a/lastleg-service/src/main/resources/openapi/appointment-planning-v1.yaml +++ b/lastleg-service/src/main/resources/openapi/appointment-planning-v1.yaml @@ -154,6 +154,7 @@ paths: properties: originWarehouseName: {type: string} destinationWarehouseCode: {type: string} + destinationTimezone: {type: string, nullable: true, description: 当前目的仓主档IANA时区;主档为空时为null,读取失败返回错误,不使用历史预约快照} sources: {type: array, items: {$ref: '#/components/schemas/PlanningSource'}} missingFields: {type: array, items: {type: string}} group: diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewServiceTest.java index d862afc51..8f9ff1197 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/appointmentplanning/AppointmentBatchPreviewServiceTest.java @@ -15,12 +15,14 @@ class AppointmentBatchPreviewServiceTest { var refs=List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"),new AppointmentCoverageService.SourceRef("B","BOOKING:B-1","FBA:ONT8")); when(sources.resolveBatch(refs)).thenReturn(List.of(source("ORDER:1","A",1L,"100","FBA:ONT8"),source("BOOKING:B-1","B",null,"100","FBA:ONT8"))); when(mapper.flags(List.of(1L))).thenReturn(List.of(new AppointmentBatchPreviewMapper.Flags(1L,false,false,false))); + when(sources.destinationTimezone("ONT8")).thenReturn("America/Los_Angeles"); var preview=new AppointmentBatchPreviewService(sources,mapper).preview(refs); + assertEquals("America/Los_Angeles",preview.destinationTimezone()); assertEquals(2,preview.group().customerCount());assertEquals(20,preview.group().packages()); assertTrue(preview.group().readinessIncomplete());assertNull(preview.group().readyFrom()); assertEquals(List.of("READY_WINDOW_UNVERIFIED"),preview.missingFields()); assertNull(preview.sources().get(1).orderId()); - verify(sources).resolveBatch(refs);verify(mapper).flags(List.of(1L));verifyNoMoreInteractions(sources,mapper); + verify(sources).resolveBatch(refs);verify(mapper).flags(List.of(1L));verify(sources).destinationTimezone("ONT8");verifyNoMoreInteractions(sources,mapper); } @Test void missingRowsDetentionMixedDestinationsAndPriorAppointmentsBlockGrouping() { var sources=mock(AppointmentSourceService.class);var mapper=mock(AppointmentBatchPreviewMapper.class); @@ -40,4 +42,13 @@ class AppointmentBatchPreviewServiceTest { assertThrows(ResponseStatusException.class,()->new AppointmentBatchPreviewService(sources,mapper).preview(refs)); verifyNoInteractions(mapper); } + @Test void absentTimezoneStaysUnknownAndLookupFailureIsNotMasked() { + var sources=mock(AppointmentSourceService.class);var mapper=mock(AppointmentBatchPreviewMapper.class); + var refs=List.of(new AppointmentCoverageService.SourceRef("A","BOOKING:A","FBA:ONT8")); + when(sources.resolveBatch(refs)).thenReturn(List.of(source("BOOKING:A","A",null,"100","FBA:ONT8"))); + var service=new AppointmentBatchPreviewService(sources,mapper); + assertNull(service.preview(refs).destinationTimezone()); + when(sources.destinationTimezone("ONT8")).thenThrow(new ResponseStatusException(org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE,"lookup failed")); + assertEquals(503,assertThrows(ResponseStatusException.class,()->service.preview(refs)).getStatusCode().value()); + } }