fix(lastleg): preserve source validation during partial dispatch picking
This commit is contained in:
+29
-1
@@ -59,14 +59,16 @@ class AppointmentWorkDispatchBindingTest {
|
||||
when(sources.canonicalOrders(anyList())).thenReturn(List.of(new AppointmentCoverageService.SourceRef("C","ORDER:1",null)));
|
||||
assertDoesNotThrow(()->service.requireDeparture("D-20"));
|
||||
when(mapper.receivedPhysical(10,"C")).thenReturn(List.of(new AppointmentWorkDispatchMapper.Physical(1L,"C","FBA:ONT8",null,4)));
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of());
|
||||
var departure=java.time.Instant.parse("2026-10-18T12:00:00Z");
|
||||
var arrival=java.time.Instant.parse("2026-10-18T17:00:00Z");
|
||||
clearInvocations(mapper);
|
||||
assertNull(service.reviewBlockReason("D-20",departure,arrival));
|
||||
verify(mapper,never()).pickedPhysical(anyLong(),anyString());
|
||||
verify(mapper).pickedPhysical(30,"C");
|
||||
assertEquals(arrival,service.reviewEvidence("D-20").get(0).startAt(),"10点洛杉矶预约应按当地时区解释");
|
||||
// 目的仓编号及时间由整车入口校验;此端口只核实真实来源分配。
|
||||
assertNull(service.reviewBlockReason("D-20",departure,null));
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of(new AppointmentWorkDispatchMapper.Physical(1L,"C","FBA:ONT8",null,4)));
|
||||
when(item.packageCount()).thenReturn(4);when(mapper.allocated("FBA_APPOINTMENT:1","C","ORDER:1","FBA:ONT8",20)).thenReturn(1L);
|
||||
assertTrue(service.departureBlockReason("D-20").contains("分配量"));
|
||||
when(item.packageCount()).thenReturn(4);when(mapper.allocated("FBA_APPOINTMENT:1","C","ORDER:1","FBA:ONT8",20)).thenReturn(0L);
|
||||
@@ -85,6 +87,7 @@ class AppointmentWorkDispatchBindingTest {
|
||||
assertDoesNotThrow(()->service.requireDeparture("D-20"));
|
||||
when(receiving.currentAgreement("FBA_APPOINTMENT:1","C")).thenReturn(null);
|
||||
assertDoesNotThrow(()->service.requireDeparture("D-20"));
|
||||
when(mapper.receivedPhysical(10,"C")).thenReturn(List.of());
|
||||
assertNull(service.reviewBlockReason("D-20",departure,arrival));
|
||||
verifyNoInteractions(changes);
|
||||
}
|
||||
@@ -122,6 +125,31 @@ class AppointmentWorkDispatchBindingTest {
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of(new AppointmentWorkDispatchMapper.Physical(1L,"C","CUSTOMER:1",null,4)));
|
||||
assertDoesNotThrow(()->service.requireDeparture("D-20"));verifyNoInteractions(appointments);
|
||||
}
|
||||
@Test void partialPickingKeepsReviewEligibleButDepartureStillRequiresAllOriginalSources() {
|
||||
var mapper=mock(AppointmentWorkDispatchMapper.class);var sources=mock(AppointmentSourceService.class);
|
||||
var service=new AppointmentWorkDispatchBinding(mapper,mock(InboundFbaAppointmentService.class),sources,mock(AppointmentWorkChanges.class),mock(com.baiyue.lastleg.inboundplan.receiving.FbaReceivingStore.class),mock(AppointmentWorkDispatchCandidates.class));
|
||||
when(mapper.dispatchPhysical("D")).thenReturn(List.of(new AppointmentWorkDispatchMapper.DispatchPhysical(30,10L,"C","RECEIVED",4)));
|
||||
when(mapper.bindings("D")).thenReturn(List.of(
|
||||
new AppointmentWorkDispatchMapper.Bound(20,30,10,"DISPATCH:20","C","ORDER:1","FBA:A",1),
|
||||
new AppointmentWorkDispatchMapper.Bound(20,30,10,"DISPATCH:20","C","ORDER:2","FBA:A",3)));
|
||||
when(sources.canonicalOrders(anyList())).thenAnswer(call->((List<AppointmentExternalSourceGateway.OrderRef>)call.getArgument(0)).stream()
|
||||
.map(ref->new AppointmentCoverageService.SourceRef(ref.customerId(),"ORDER:"+ref.orderId(),null)).toList());
|
||||
var first=new AppointmentWorkDispatchMapper.Physical(1L,"C","FBA:A",null,1);
|
||||
var second=new AppointmentWorkDispatchMapper.Physical(2L,"C","FBA:A",null,3);
|
||||
when(mapper.receivedPhysical(10,"C")).thenReturn(List.of(second));
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of(first));
|
||||
assertNull(service.reviewBlockReason("D",null,null));
|
||||
assertNotNull(service.departureBlockReason("D"));
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of(new AppointmentWorkDispatchMapper.Physical(3L,"C","FBA:A",null,1)));
|
||||
assertNotNull(service.reviewBlockReason("D",null,null),"同箱数的其他来源不能补足原分配");
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of());
|
||||
assertNotNull(service.reviewBlockReason("D",null,null),"缺失真实扫码事实不能推算补齐");
|
||||
when(mapper.receivedPhysical(10,"C")).thenReturn(List.of());
|
||||
when(mapper.pickedPhysical(30,"C")).thenReturn(List.of(first,second));
|
||||
assertNull(service.reviewBlockReason("D",null,null));
|
||||
assertNull(service.departureBlockReason("D"));
|
||||
verify(mapper,atLeastOnce()).pickedPhysical(30,"C");
|
||||
}
|
||||
@Test void repeatedPhysicalRowsForSameOrderResolveByIdentityWithoutIndexingDistinctResults() {
|
||||
var sources=mock(AppointmentSourceService.class);
|
||||
var one=new AppointmentWorkDispatchMapper.Physical(1L,"C","FBA:A",4,4);
|
||||
|
||||
Reference in New Issue
Block a user