发布:将已验 TEST 功能更新至既有生产灰度(2026-10-23) #30
+1
-1
@@ -123,7 +123,7 @@ class PlatformDispatchOutboundContractTest {
|
||||
assertTrue(Arrays.stream(DispatchController.class.getDeclaredMethods())
|
||||
.noneMatch(method -> Set.of("depart", "cancel").contains(method.getName())));
|
||||
assertEquals(Set.of("recordVersion", "idempotencyKey", "vehicle", "driver",
|
||||
"plannedDepartureAt", "estimatedArrivalAt", "remark", "publishLooseboardDemand"),
|
||||
"plannedDepartureAt", "estimatedArrivalAt", "remark", "publishLooseboardDemand", "maintenance"),
|
||||
Arrays.stream(DispatchCommands.Update.class.getRecordComponents())
|
||||
.map(component -> component.getName()).collect(java.util.stream.Collectors.toSet()));
|
||||
assertEquals(Set.of("recordVersion", "idempotencyKey", "reason"),
|
||||
|
||||
+15
-7
@@ -20,7 +20,7 @@ import static org.mockito.Mockito.*;
|
||||
import static com.baiyue.lastleg.inboundplan.receiving.FbaReceivingContracts.*;
|
||||
|
||||
class AppointmentWorkPreArrangementPersistenceTest {
|
||||
@Test void siblingPlanChangeNeverAuthorizesUnconfirmedFbaCargoToEnterDispatch() {
|
||||
@Test void siblingPlanChangePreservesPrearrangementButNeverAuthorizesUnpickedDeparture() {
|
||||
try(var context=new AnnotationConfigApplicationContext(FbaAppointmentPersistenceTest.Config.class)) {
|
||||
var sources=context.getBean(AppointmentSourceService.class);
|
||||
var cargo=List.of(source("B",1,60),source("D",2,40));
|
||||
@@ -45,15 +45,18 @@ class AppointmentWorkPreArrangementPersistenceTest {
|
||||
var tx=new TransactionTemplate(context.getBean(PlatformTransactionManager.class));
|
||||
var before=candidates.read(batch.batchKey()).candidates().stream().filter(c->c.customerId().equals("B")).findFirst().orElseThrow();
|
||||
assertFalse(before.blockReasons().isEmpty());assertEquals(60,before.packageCount());
|
||||
assertNotBindable(tx,binding,mapper,before);
|
||||
assertPrearrangementAllowed(tx,binding,mapper,before);
|
||||
batch=receiving.plan("operator",new Plan("pending-d",new Selection(batch.batchKey(),batch.version(),"D"),plan("PENDING"),"transport-v1")).batches().get(0);
|
||||
assertEquals("PENDING",batch.appointmentStatus());assertEquals(originalB,store.plan(batch.batchKey(),"B"));
|
||||
var after=candidates.read(batch.batchKey()).candidates().stream().filter(c->c.customerId().equals("B")).findFirst().orElseThrow();
|
||||
assertEquals(before.packageCount(),after.packageCount());assertEquals(before.blockReasons(),after.blockReasons());
|
||||
assertNotEquals(before.allocations().get(0).recordVersion(),after.allocations().get(0).recordVersion());assertNotBindable(tx,binding,mapper,after);
|
||||
assertNotEquals(before.allocations().get(0).recordVersion(),after.allocations().get(0).recordVersion());assertPrearrangementAllowed(tx,binding,mapper,after);
|
||||
var bound=new AppointmentWorkDispatchMapper.Bound(20L,201L,101L,batch.batchKey(),"B","ORDER:1","FBA:ONT8",60);
|
||||
doReturn(List.of(bound)).when(mapper).bindings("DP-B");
|
||||
assertTrue(assertThrows(ResponseStatusException.class,()->binding.requireDeparture("DP-B")).getReason().contains("尚无有效收货确认"));
|
||||
// 预约号门槛归整车审核;来源端口不伪造正式确认,且预排不能替代真实拣货。
|
||||
assertTrue(binding.reviewEvidence("DP-B").isEmpty());
|
||||
doReturn(List.of()).when(mapper).pickedPhysical(201L,"B");
|
||||
assertTrue(assertThrows(ResponseStatusException.class,()->binding.requireDeparture("DP-B")).getReason().contains("缺少真实逐票分配"));
|
||||
// Unchanged real-source guards still reject an unverified pallet and an allocation owned by another customer.
|
||||
doReturn(List.of(new AppointmentWorkDispatchMapper.Physical(1L,"B","FBA:ONT8",60,null))).when(mapper).physical(101L,"B");
|
||||
assertFalse(candidates.read(batch.batchKey()).candidates().get(0).blockReasons().isEmpty());
|
||||
@@ -65,11 +68,16 @@ class AppointmentWorkPreArrangementPersistenceTest {
|
||||
assertTrue(mapper.byDispatch(20).isEmpty());
|
||||
}
|
||||
}
|
||||
private static void assertNotBindable(TransactionTemplate tx,AppointmentWorkDispatchBinding binding,AppointmentWorkDispatchMapper mapper,AppointmentWorkDispatchCandidates.Candidate candidate) {
|
||||
assertThrows(ResponseStatusException.class,()->tx.executeWithoutResult(status->{
|
||||
/** 最新契约允许先排后约,但真实来源、数量及发车确认仍独立复验;回滚本段以隔离后续负例。 */
|
||||
private static void assertPrearrangementAllowed(TransactionTemplate tx,AppointmentWorkDispatchBinding binding,AppointmentWorkDispatchMapper mapper,AppointmentWorkDispatchCandidates.Candidate candidate) {
|
||||
tx.executeWithoutResult(status->{
|
||||
binding.lockBatches(Map.of(candidate.allocations().get(0).batchKey(),candidate.allocations().get(0).recordVersion()));
|
||||
binding.bindItems(20,List.of(new AppointmentWorkDispatchPort.PhysicalItem(201L,"B",101L,"RECEIVED",60)),candidate.allocations());
|
||||
}));
|
||||
var allocated=mapper.byDispatch(20);
|
||||
assertEquals(1,allocated.size());assertEquals("B",allocated.get(0).customerId());
|
||||
assertEquals(60,allocated.get(0).packages());assertEquals("ORDER:1",allocated.get(0).sourceKey());
|
||||
status.setRollbackOnly();
|
||||
});
|
||||
assertTrue(mapper.byDispatch(20).isEmpty());
|
||||
}
|
||||
private static FbaAppointmentDetails plan(String status) {return new FbaAppointmentDetails(LocalDate.of(2026,10,25),null,null,null,null,null,status,"仓库暂无确认",null,null);}
|
||||
|
||||
Reference in New Issue
Block a user