fix(appointment): link customer work to original batch requirement
This commit is contained in:
+39
@@ -12,6 +12,45 @@ import static com.baiyue.lastleg.appointmentwork.AppointmentWorkModels.*;
|
||||
import static com.baiyue.lastleg.appointmentwork.AppointmentWorkFactGateway.*;
|
||||
|
||||
class AppointmentWorkSyncServiceTest {
|
||||
/** 同一实物批次拆成客户事项时,整体事项须有完整去向,运输仍保持唯一。 */
|
||||
@Test void batchWideDeliveryIsReplacedByItsExplicitCustomerRequirements() {
|
||||
var f=new WorkTestFixture();String batch="FBA_APPOINTMENT:1";
|
||||
var refs=List.of(new SourceReference("A","ORDER:1","FBA:ONT8"),new SourceReference("B","ORDER:2","FBA:ONT8"));
|
||||
// 先保存整体需求的真实历史事项,再按相同批次和来源拆出客户事项。
|
||||
var old=f.state("1",Type.DELIVERY,Flow.TRANSFER,batch);
|
||||
old.setWorkItemKey(AppointmentWorkPolicy.key("BATCH:"+batch,Type.DELIVERY,null));
|
||||
old.setBatchKey(batch);old.setBatchKeys(List.of(batch));old.setSources(refs);f.add(old);
|
||||
var sources=mock(com.baiyue.lastleg.appointmentplanning.AppointmentSourceService.class);
|
||||
var cargo=mock(com.baiyue.lastleg.appointmentplanning.AppointmentCargoVerificationService.class);
|
||||
var appointments=mock(com.baiyue.lastleg.inboundplan.service.InboundFbaAppointmentService.class);
|
||||
var mapping=mock(com.baiyue.lastleg.inboundplan.work.AppointmentWorkSourceMapper.class);
|
||||
var provider=new com.baiyue.lastleg.inboundplan.work.AppointmentWorkRequirementProvider(sources,cargo,appointments,mapping);
|
||||
when(mapping.containerSources("1")).thenReturn(List.of(new com.baiyue.lastleg.inboundplan.work.AppointmentWorkSourceMapper.Source(1L,"A","1","1","FBA","ONT8",1),new com.baiyue.lastleg.inboundplan.work.AppointmentWorkSourceMapper.Source(2L,"B","2","1","FBA","ONT8",1)));
|
||||
when(sources.canonicalOrders(anyList())).thenReturn(refs.stream().map(r->new com.baiyue.lastleg.appointmentplanning.AppointmentCoverageService.SourceRef(r.customerId(),r.sourceKey(),r.destinationKey())).toList());
|
||||
when(sources.resolveBatch(anyList())).thenReturn(refs.stream().map(r->new com.baiyue.lastleg.appointmentplanning.AppointmentSourceService.Source(r.sourceKey(),r.customerId(),Long.valueOf(r.sourceKey().substring(6)),null,null,"CNT",null,null,r.destinationKey(),"ONT8",1,"v1",true,List.of())).toList());
|
||||
var allocation=mock(com.baiyue.lastleg.appointmentplanning.AppointmentCargoVerificationService.Context.class);
|
||||
when(allocation.availablePackages()).thenReturn(0L);when(cargo.inspect(any(com.baiyue.lastleg.appointmentplanning.AppointmentSourceService.Source.class))).thenReturn(allocation);
|
||||
var snapshot=mock(com.baiyue.lastleg.inboundplan.dto.FbaAppointmentResponse.class);
|
||||
when(snapshot.batchKey()).thenReturn(batch);when(snapshot.appointmentNo()).thenReturn("AP-1");when(snapshot.fbaWarehouseCode()).thenReturn("ONT8");
|
||||
var items=refs.stream().map(r->{var item=mock(com.baiyue.lastleg.inboundplan.dto.FbaAppointmentResponse.Item.class);when(item.customerId()).thenReturn(r.customerId());when(item.sourceKey()).thenReturn(r.sourceKey());when(item.destinationKey()).thenReturn(r.destinationKey());return item;}).toList();
|
||||
when(snapshot.items()).thenReturn(items);
|
||||
when(appointments.relatedBatchSnapshots(anyList())).thenReturn(List.of(snapshot));
|
||||
var root=new Requirement("INBOUND:1",null,null,"FBA",null,"ONT8",null,List.of(),List.of(),refs);
|
||||
var source=new ContainerSource("1","CNT",null,LocalDateTime.parse("2026-10-01T10:00:00"),null,"v1",Flow.TRANSFER,null,List.of(root));
|
||||
doAnswer(c->provider.requirements(c.getArgument(0),c.getArgument(1))).when(f.gateway).requirements(any(),eq(Flow.TRANSFER));
|
||||
when(f.gateway.discover(null,10)).thenReturn(new SourcePage(List.of(source),null,true,"scope"));
|
||||
f.guard.setRequirementVersion(1);
|
||||
f.sync.synchronize(new SyncRequest(null,10));
|
||||
var deliveries=f.store.all().stream().filter(s->s.getType()==Type.DELIVERY && !s.isRetired()).toList();
|
||||
assertEquals(2,deliveries.size());
|
||||
var retired=f.store.get(old.getWorkItemKey());assertTrue(retired.isRetired());
|
||||
assertEquals(new HashSet<>(deliveries.stream().map(AppointmentWorkState::getWorkItemKey).toList()),new HashSet<>(retired.getReplacementKeys()));
|
||||
assertEquals(1,f.store.all().stream().filter(s->s.getType()==Type.TRANSPORT && !s.isRetired()).count());
|
||||
assertDoesNotThrow(f.store::requireInitialized);
|
||||
f.sync.synchronize(new SyncRequest(null,10));
|
||||
assertEquals(2,f.store.all().stream().filter(s->s.getType()==Type.DELIVERY && !s.isRetired()).count());
|
||||
}
|
||||
|
||||
@Test void onePhysicalBatchHasIndependentCustomerDeliveriesAndOneVehicleWithAllCustomerEdges() {
|
||||
var f=new WorkTestFixture();String batch="FBA_APPOINTMENT:1";
|
||||
var requirements=List.of("A","B").stream().map(customer->new Requirement(AppointmentWorkPolicy.customerRequirement(batch,customer),batch,"AP-1","FBA","海外仓","ONT8",null,List.of(),List.of(),List.of(new SourceReference(customer,"ORDER:"+customer,"FBA:ONT8")))).toList();
|
||||
|
||||
+1
@@ -75,6 +75,7 @@ class AppointmentWorkRequirementProviderTest {
|
||||
var result=provider.requirements(container,Flow.TRANSFER);
|
||||
assertEquals(List.of("FBA_APPOINTMENT:1|CUSTOMER:C"),result.stream().map(Requirement::requirementKey).toList());
|
||||
assertEquals(List.of(new SourceReference("C","ORDER:11","FBA:ONT8")),result.get(0).sources());
|
||||
assertTrue(result.get(0).replacesRequirementKeys().contains("FBA_APPOINTMENT:1"));
|
||||
}
|
||||
when(allocation.availablePackages()).thenReturn(20L);
|
||||
assertEquals(List.of("INBOUND:1","FBA_APPOINTMENT:1|CUSTOMER:C"),provider.requirements(container,Flow.TRANSFER).stream().map(Requirement::requirementKey).toList());
|
||||
|
||||
Reference in New Issue
Block a user