Files
baiyue-firstleg/lastleg-service/src/test/java/com/baiyue/lastleg/appointmentplanning/AppointmentCoverageServiceTest.java
T

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(),"核实资料变更不能重写原确认时间");
}
}