fix(lastleg): allow appointment registration before dispatch assignment

This commit is contained in:
2026-10-22 08:16:51 +08:00
parent 738b778edf
commit 8adaea75fa
2 changed files with 29 additions and 1 deletions
@@ -52,6 +52,33 @@ class FbaAppointmentExecutionAdapterTest {
assertThrows(org.springframework.web.server.ResponseStatusException.class,()->adapter.lockAndInspect(List.of(),"empty","operator"));
verifyNoInteractions(mapper,amendments,dispatches);
}
/** 有真实客户货物但尚未排车时,可按当前完整版本登记预约,不调用原排车锁。 */
@Test void unassignedCustomerCanRebookWithoutLockingAnEmptyDispatchScope() {
when(mapper.transportRows(List.of(batch),List.of())).thenReturn(List.of());
var current=adapter.inspect(List.of(b));
var locked=adapter.lockAndInspect(List.of(b),current.version(),"operator");
assertEquals(current.version(),locked.version());
assertFalse(locked.members().get(0).completed());assertTrue(locked.members().get(0).canRebook());
verifyNoInteractions(amendments,dispatches);
}
/** 无排车不免除乐观锁,过期的完整执行版本仍须拒绝。 */
@Test void unassignedCustomerStillRequiresTheCurrentCompleteExecutionVersion() {
when(mapper.transportRows(List.of(batch),List.of())).thenReturn(List.of());
var error=assertThrows(org.springframework.web.server.ResponseStatusException.class,
()->adapter.lockAndInspect(List.of(b),"stale-version","operator"));
assertEquals(409,error.getStatusCode().value());
verifyNoInteractions(amendments,dispatches);
}
/** 首读无排车、复核时已关联排车,必须拒绝并要求刷新,不能沿空范围放行。 */
@Test void dispatchAssociatedDuringTheEmptyScopeRecheckInvalidatesTheVersion() {
when(mapper.transportRows(List.of(batch),List.of())).thenReturn(List.of(),List.of(),List.of(row("B","BEFORE_LOADING","PLANNED")));
var prior=adapter.inspect(List.of(b));
var error=assertThrows(org.springframework.web.server.ResponseStatusException.class,
()->adapter.lockAndInspect(List.of(b),prior.version(),"operator"));
assertEquals(409,error.getStatusCode().value());
verifyNoInteractions(amendments);
verify(dispatches,never()).completion(anyString(),eq(true));verify(dispatches,never()).lockForPlanning(anyString());
}
/** 同车总发运量不能替代本客户的真实签收数量。 */
@Test void onePhysicalDispatchUsesCustomerEvidenceInsteadOfTheWholeCarShipmentTotal() {
var rows=List.of(new AppointmentWorkDispatchMapper.TransportRow(1,"D-ONE","A","ACTIVE","DELIVERING",2L,200,200,LocalDateTime.of(2026,10,1,12,0),11,101,100,"RECEIVED",batch,"ORDER:1","FBA:ONT8",100,"T-ONE",2L,"IN_TRANSIT",201L,"OUTBOUNDED","COMPLETED"),