perf(lastleg): batch live appointment work facts and filter candidates

This commit is contained in:
2026-10-15 19:10:57 +08:00
parent abf4e45e39
commit 097bec33b1
24 changed files with 441 additions and 40 deletions
@@ -0,0 +1,32 @@
package com.baiyue.lastleg.appointmentplanning;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import java.util.*;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
class AppointmentCargoVerificationBatchTest {
@Test void inspectionUsesTwoBoundedBatchesAndRetainsPerSourcePrerequisitesAndAllocations() {
var sources=mock(AppointmentSourceService.class);var mapper=mock(AppointmentCargoVerificationMapper.class);
var service=new AppointmentCargoVerificationService(sources,mapper,new ObjectMapper());
var refs=IntStream.rangeClosed(1,200).mapToObj(i->new AppointmentCoverageService.SourceRef("C","ORDER:"+i,"FBA:ONT8")).toList();
when(sources.inspectBatch(anyList())).thenAnswer(call->call.<List<AppointmentCoverageService.SourceRef>>getArgument(0).stream().map(ref->
ref.sourceKey().equals("ORDER:2")?new AppointmentSourceService.Resolution(ref,null,new ResponseStatusException(HttpStatus.BAD_REQUEST,"接仓点不在启用的美国仓目录中")):
new AppointmentSourceService.Resolution(ref,new AppointmentSourceService.Source(ref.sourceKey(),ref.customerId(),Long.valueOf(ref.sourceKey().substring(6)),"IN",null,"CONTAINER","100","仓",ref.destinationKey(),"ONT8",10,"ORDER:1",true,List.of()),null)).toList());
when(mapper.allocatedBatch(anyList())).thenAnswer(call->call.<List<AppointmentCoverageService.SourceRef>>getArgument(0).stream().filter(r->r.sourceKey().equals("ORDER:1"))
.map(r->new AppointmentCargoVerificationMapper.SourceAllocation(r.customerId(),r.sourceKey(),4,0)).toList());
var result=service.inspectBatch(refs);
assertEquals(200,result.size());assertEquals(6L,result.get(0).requireContext().availablePackages());
assertEquals("接仓点不在启用的美国仓目录中",assertThrows(ResponseStatusException.class,()->result.get(1).requireContext()).getReason());
assertEquals(10L,result.get(199).requireContext().availablePackages());
verify(sources,times(2)).inspectBatch(argThat(batch->batch.size()==100));
verify(mapper,times(2)).latestBatch(anyList());verify(mapper,times(2)).allocatedBatch(anyList());verifyNoMoreInteractions(mapper,sources);
when(sources.inspectBatch(anyList())).thenThrow(new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE,"目录不可用"));
assertEquals(503,assertThrows(ResponseStatusException.class,()->service.inspectBatch(refs)).getStatusCode().value());
}
}
@@ -31,6 +31,7 @@ class AppointmentCoverageMapperTest {
s.execute("INSERT INTO ll_appointment_cargo_verification(id,customer_id,source_key,destination_key,version,package_count,shipment_references_json,operator_id,command_key,request_hash,created_at) VALUES(1,'A','ORDER:1','FBA:ONT8',1,19,'[]','operator','one',REPEAT('a',64),CURRENT_TIMESTAMP),(2,'A','ORDER:1','FBA:ONT8',2,20,'[\"FBA-A\"]','operator','two',REPEAT('b',64),CURRENT_TIMESTAMP),(3,'B','ORDER:1','FBA:ONT8',1,8,'[]','operator','one',REPEAT('c',64),CURRENT_TIMESTAMP)");
}
var config=new Configuration(new Environment("test",new JdbcTransactionFactory(),ds));config.setMapUnderscoreToCamelCase(true);config.addMapper(AppointmentCoverageMapper.class);
config.addMapper(AppointmentCargoVerificationMapper.class);
try(var session=new SqlSessionFactoryBuilder().build(config).openSession(true)) {
var mapper=session.getMapper(AppointmentCoverageMapper.class);
var source=mapper.sources(List.of(new AppointmentCoverageMapper.OrderRef("A",1L))).get(0);assertFalse(source.shipmentReferencesMissing());assertEquals(20,source.packages());
@@ -42,6 +43,14 @@ class AppointmentCoverageMapperTest {
assertTrue(mapper.sources(List.of(new AppointmentCoverageMapper.OrderRef("B",2L))).get(0).shipmentReferencesMissing());
var evidence=mapper.verifications(List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8")));
assertEquals(1,evidence.size());assertEquals(2,evidence.get(0).getVersion());assertEquals(20,evidence.get(0).getPackageCount());
var cargo=session.getMapper(AppointmentCargoVerificationMapper.class);
var refs=List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"),new AppointmentCoverageService.SourceRef("B","ORDER:1","FBA:ONT8"),new AppointmentCoverageService.SourceRef("D","BOOKING:B-1","FBA:ONT8"));
var latest=cargo.latestBatch(refs);assertEquals(2,latest.size());
assertEquals(2,latest.stream().filter(r->r.getCustomerId().equals("A")).findFirst().orElseThrow().getVersion());
assertEquals(1,latest.stream().filter(r->r.getCustomerId().equals("B")).findFirst().orElseThrow().getVersion());
var allocations=cargo.allocatedBatch(refs);assertEquals(2,allocations.size());
assertEquals(new AppointmentCargoVerificationMapper.SourceAllocation("A","ORDER:1",20,0),allocations.stream().filter(r->r.customerId().equals("A")).findFirst().orElseThrow());
assertEquals(new AppointmentCargoVerificationMapper.SourceAllocation("D","BOOKING:B-1",0,1),allocations.stream().filter(r->r.customerId().equals("D")).findFirst().orElseThrow());
}
}
}
@@ -25,6 +25,14 @@ class AppointmentSourceServiceTest {
var refs=List.of(new AppointmentCoverageService.SourceRef("A","ORDER:1","FBA:ONT8"),new AppointmentCoverageService.SourceRef("B","ORDER:2","FBA:ONT8"));
var result=service.resolveBatch(refs);assertEquals(2,result.size());assertEquals(20,result.get(1).packages());
verify(orders,times(1)).selectBatchIds(anyCollection());verify(shipping,times(1)).selectBatchIds(anyCollection());verify(warehouse,times(1)).catalog("token");verify(gateway,times(1)).resolveOrders(anyList());verifyNoMoreInteractions(gateway);
b.setOverseasWarehouseId("unknown");
var inspected=service.inspectBatch(refs);assertNotNull(inspected.get(0).requireSource());
assertEquals("接仓点不在启用的美国仓目录中",inspected.get(1).error().getReason());
assertThrows(ResponseStatusException.class,()->service.resolveBatch(refs));
var unauthorized=service.inspectBatch(List.of(new AppointmentCoverageService.SourceRef("OTHER","ORDER:1","FBA:ONT8")));
assertEquals(404,assertThrows(ResponseStatusException.class,()->unauthorized.get(0).requireSource()).getStatusCode().value());
when(warehouse.catalog("token")).thenThrow(new IllegalStateException("offline"));
assertEquals(503,assertThrows(ResponseStatusException.class,()->service.inspectBatch(refs)).getStatusCode().value());
assertThrows(ResponseStatusException.class,()->service.resolveBatch(List.of(refs.get(0),refs.get(0))));
assertThrows(ResponseStatusException.class,()->service.resolveBatch(List.of(new AppointmentCoverageService.SourceRef("OTHER","ORDER:1","FBA:ONT8"))));
}