From 74f510a49b8a378b377f94c92f007a2b937f6744 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 22 Oct 2026 08:16:52 +0800 Subject: [PATCH] fix(lastleg): repair first appointment execution scope on validated release baseline --- .../work/FbaAppointmentExecutionAdapter.java | 3 ++- .../FbaAppointmentExecutionAdapterTest.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapter.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapter.java index 04242c5c0..297689303 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapter.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapter.java @@ -39,7 +39,8 @@ public class FbaAppointmentExecutionAdapter implements FbaAppointmentExecutionPo var members=members(input);if(members.isEmpty()) throw bad("请选择需要重新预约的客户"); var before=read(batches(members));var selected=selected(before,members); var tripNos=tripNos(selected);var numbers=dispatchNos(selected); - amendments.lockExistingAppointmentDispatches(new Actor(operator,ActorMode.PLATFORM,null),numbers); + // 尚未排车的客户仍需核对完整执行版本,但没有原排车资源需要加锁。 + if(!numbers.isEmpty()) amendments.lockExistingAppointmentDispatches(new Actor(operator,ActorMode.PLATFORM,null),numbers); for(var number:numbers) { dispatches.completion(number,true); dispatches.lockForPlanning(number); diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapterTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapterTest.java index 6d73f4d0d..fc81dcad2 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapterTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/work/FbaAppointmentExecutionAdapterTest.java @@ -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"),