97 lines
9.0 KiB
Java
97 lines
9.0 KiB
Java
package com.baiyue.lastleg.appointmentplanning;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import java.time.LocalDateTime;
|
|
import java.util.List;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.mockito.ArgumentMatchers.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
class AppointmentCoverageServiceTest {
|
|
private static final LocalDateTime BEFORE=LocalDateTime.of(2026,10,9,1,0), AFTER=BEFORE.plusHours(1);
|
|
private static AppointmentCoverageMapper.Source order() {
|
|
return new AppointmentCoverageMapper.Source(1L,"A","FBA","ONT8",20,2,BEFORE,false);
|
|
}
|
|
private static AppointmentCoverageMapper.Fact fact(long line,int packages,String status) {
|
|
return new AppointmentCoverageMapper.Fact(1L,"A","AP-1",status,AFTER.plusDays(1),null,AFTER,line,packages,"ONT8","ORDER:1","ORDER:2","EXT-1","America/Los_Angeles",null);
|
|
}
|
|
@Test void completeQuantitySharesOneAppointmentWithItsActualConfirmationAndTimezone() {
|
|
var mapper=mock(AppointmentCoverageMapper.class); var gateway=mock(AppointmentExternalSourceGateway.class);
|
|
when(mapper.sources(anyList())).thenReturn(List.of(order()));
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(fact(10,10,"SUCCESS"),fact(11,10,"SUCCESS")));
|
|
var result=new AppointmentCoverageService(mapper,gateway).query(List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"))).get(0);
|
|
assertEquals("CONFIRMED",result.status()); assertEquals(1,result.appointments().size());
|
|
assertEquals("America/Los_Angeles",result.appointments().get(0).timezone()); assertEquals("EXT-1",result.appointments().get(0).confirmationNo());assertFalse(result.missingFields().contains("APPOINTMENT_TIMEZONE_UNVERIFIED"));
|
|
assertFalse(result.changeReviewRequired()); verifyNoInteractions(gateway);
|
|
}
|
|
@Test void confirmedNumberWithoutATimeRemainsConfirmedAndQuantityOnlyVerificationKeepsOriginalReferences() {
|
|
var mapper=mock(AppointmentCoverageMapper.class);
|
|
when(mapper.sources(anyList())).thenReturn(List.of(order()));
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(new AppointmentCoverageMapper.Fact(1L,"A","AP-1","SUCCESS",null,null,AFTER,10L,20,"ONT8","ORDER:1","ORDER:2","EXT-1","America/Los_Angeles",1)));
|
|
var evidence=new AppointmentCargoVerification();evidence.setCustomerId("A");evidence.setSourceKey("ORDER:1");evidence.setDestinationKey("FBA:ONT8");
|
|
evidence.setSourceVersion("ORDER:2");evidence.setSourcePackages(20);evidence.setPackageCount(20);evidence.setVersion(1);evidence.setShipmentReferencesJson("[]");
|
|
when(mapper.verifications(anyList())).thenReturn(List.of(evidence));
|
|
var service=new AppointmentCoverageService(mapper,mock(AppointmentExternalSourceGateway.class));
|
|
var refs=List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"));
|
|
var result=service.query(refs).get(0);
|
|
assertEquals("CONFIRMED",result.status());assertEquals("EXT-1",result.appointments().get(0).confirmationNo());
|
|
assertNull(result.appointments().get(0).confirmedAt());assertFalse(result.missingFields().contains("FBA_SHIPMENT_REFERENCES"));
|
|
when(mapper.sources(anyList())).thenReturn(List.of(new AppointmentCoverageMapper.Source(1L,"A","FBA","ONT8",20,2,BEFORE,true)));
|
|
assertTrue(service.query(refs).get(0).missingFields().contains("FBA_SHIPMENT_REFERENCES"));
|
|
}
|
|
@Test void partialPendingAndDuplicateClaimsNeverAppearAsCompleteCoverage() {
|
|
var mapper=mock(AppointmentCoverageMapper.class); when(mapper.sources(anyList())).thenReturn(List.of(order()));
|
|
var service=new AppointmentCoverageService(mapper,mock(AppointmentExternalSourceGateway.class));
|
|
var refs=List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"));
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(fact(10,10,"SUCCESS")));
|
|
assertEquals("PARTIAL",service.query(refs).get(0).status());
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(fact(10,20,"PENDING")));
|
|
assertEquals("PENDING",service.query(refs).get(0).status());
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(fact(10,10,"SUCCESS"),fact(10,10,"SUCCESS")));
|
|
assertEquals("REVIEW_REQUIRED",service.query(refs).get(0).status());
|
|
}
|
|
@Test void externalBookingKeepsItsIdentityBeforeAndAfterRealCargoExists() {
|
|
var mapper=mock(AppointmentCoverageMapper.class); var gateway=mock(AppointmentExternalSourceGateway.class);
|
|
var refs=List.of(new AppointmentCoverageService.SourceRef("A","BOOKING:B-1","FBA:ONT8"));
|
|
var service=new AppointmentCoverageService(mapper,gateway);
|
|
when(gateway.resolve(anyList())).thenReturn(List.of(new AppointmentExternalSourceGateway.Source("A","B-1","TR-1","CONFIRMED","100","FBA:ONT8",null,20,1L)));
|
|
assertEquals("SOURCE_NOT_MATERIALIZED",service.query(refs).get(0).status()); verify(mapper,never()).sources(anyList());
|
|
when(gateway.resolve(anyList())).thenReturn(List.of(new AppointmentExternalSourceGateway.Source("A","B-1","TR-1","BOUND","100","FBA:ONT8",1L,20,2L)));
|
|
when(mapper.sources(anyList())).thenReturn(List.of(order())); when(mapper.appointments(anyList())).thenReturn(List.of(new AppointmentCoverageMapper.Fact(1L,"A","AP-1","SUCCESS",AFTER.plusDays(1),null,AFTER,10L,20,"ONT8","BOOKING:B-1","BOOKING:2/ORDER:2","EXT-1","America/Los_Angeles",null)));
|
|
var result=service.query(refs).get(0); assertEquals("BOOKING:B-1",result.sourceKey()); assertEquals("CONFIRMED",result.status());
|
|
assertThrows(IllegalArgumentException.class, () -> service.query(List.of(refs.get(0),new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"))));
|
|
}
|
|
@Test void anotherCustomerAndChangedDestinationCannotBorrowAppointmentCoverage() {
|
|
var mapper=mock(AppointmentCoverageMapper.class); var gateway=mock(AppointmentExternalSourceGateway.class);
|
|
when(mapper.sources(anyList())).thenReturn(List.of(order())); when(mapper.appointments(anyList())).thenReturn(List.of(fact(10,20,"SUCCESS")));
|
|
var service=new AppointmentCoverageService(mapper,gateway);
|
|
assertEquals("SOURCE_NOT_FOUND",service.query(List.of(new AppointmentCoverageService.SourceRef("B","ORDER:1","FBA:ONT8"))).get(0).status());
|
|
assertEquals("DESTINATION_MISMATCH",service.query(List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:LAX9"))).get(0).status());
|
|
}
|
|
@Test void changedSourcesAndMissingShipmentReferencesAreExplicitWithoutChangingConfirmedTime() {
|
|
var mapper=mock(AppointmentCoverageMapper.class);
|
|
when(mapper.sources(anyList())).thenReturn(List.of(new AppointmentCoverageMapper.Source(1L,"A","FBA","ONT8",20,3,AFTER.plusHours(1),true)));
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(fact(10,20,"SUCCESS")));
|
|
var result=new AppointmentCoverageService(mapper,mock(AppointmentExternalSourceGateway.class)).query(List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"))).get(0);
|
|
assertTrue(result.changeReviewRequired()); assertTrue(result.missingFields().containsAll(List.of("SOURCE_CHANGED_REVIEW","FBA_SHIPMENT_REFERENCES")));
|
|
assertEquals(AFTER.plusDays(1),result.appointments().get(0).confirmedAt());
|
|
verify(mapper,times(1)).sources(anyList()); verify(mapper,times(1)).appointments(anyList()); verify(mapper,times(1)).verifications(anyList()); verifyNoMoreInteractions(mapper);
|
|
}
|
|
@Test void independentVerificationSuppliesQuantityAndReferencesWithoutRewritingOriginalOrderFacts() {
|
|
var mapper=mock(AppointmentCoverageMapper.class);
|
|
when(mapper.sources(anyList())).thenReturn(List.of(new AppointmentCoverageMapper.Source(1L,"A","FBA","ONT8",null,2,BEFORE,true)));
|
|
var evidence=new AppointmentCargoVerification();evidence.setCustomerId("A");evidence.setSourceKey("ORDER:1");evidence.setDestinationKey("FBA:ONT8");
|
|
evidence.setSourceVersion("ORDER:2");evidence.setPackageCount(20);evidence.setVersion(1);evidence.setShipmentReferencesJson("[\"FBA-A\"]");
|
|
when(mapper.verifications(anyList())).thenReturn(List.of(evidence));
|
|
when(mapper.appointments(anyList())).thenReturn(List.of(new AppointmentCoverageMapper.Fact(1L,"A","AP-1","SUCCESS",AFTER.plusDays(1),null,AFTER,10L,20,"ONT8","ORDER:1","ORDER:2","EXT-1","America/Los_Angeles",1)));
|
|
var service=new AppointmentCoverageService(mapper,mock(AppointmentExternalSourceGateway.class));
|
|
var refs=List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"));
|
|
var result=service.query(refs).get(0);
|
|
assertEquals("CONFIRMED",result.status());assertFalse(result.changeReviewRequired());assertFalse(result.missingFields().contains("FBA_SHIPMENT_REFERENCES"));
|
|
evidence.setVersion(2);evidence.setShipmentReferencesJson("[\"FBA-CHANGED\"]");
|
|
var changed=service.query(refs).get(0);
|
|
assertTrue(changed.changeReviewRequired());assertTrue(changed.missingFields().contains("SOURCE_CHANGED_REVIEW"));
|
|
assertEquals(result.appointments(),changed.appointments(),"核实资料变更不能重写原确认时间");
|
|
}
|
|
}
|