diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java index 9f40356f..1f54276c 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java @@ -531,6 +531,12 @@ public class WaybillServiceImpl extends BaseServiceImpl } // 只有显式传 false 才是取消打卡,未传按已打卡处理 boolean punched = !Boolean.FALSE.equals(request.getPunched()); + // 待回单确认的运单司机已无待打卡节点,再补一条打卡流水与状态含义矛盾; + // 漏打的出路是先取消该节点的打卡退回进行中(punched=false),再重新补录。 + if (punched && WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM + .equalsIgnoreCase(waybill.getBusinessStatus())) { + throw new ServiceException("运单待业务员确认回单,不能补录打卡"); + } if (ENROUTE_PUNCH_TYPE.equalsIgnoreCase(TransportBusinessSupport.trimToEmpty(request.getType()))) { return saveEnroutePunchRecord(waybill, request, punched); } diff --git a/blade-service/blade-transport/src/test/java/org/springblade/transport/service/impl/WaybillPunchRecordSaveTest.java b/blade-service/blade-transport/src/test/java/org/springblade/transport/service/impl/WaybillPunchRecordSaveTest.java index 6b41a1ef..1778a850 100644 --- a/blade-service/blade-transport/src/test/java/org/springblade/transport/service/impl/WaybillPunchRecordSaveTest.java +++ b/blade-service/blade-transport/src/test/java/org/springblade/transport/service/impl/WaybillPunchRecordSaveTest.java @@ -18,6 +18,7 @@ import org.springblade.transport.pojo.dto.WaybillPunchRecordSaveRequest; import org.springblade.transport.pojo.entity.Waybill; import org.springblade.transport.pojo.entity.WaybillEnroutePunch; import org.springblade.transport.pojo.entity.WaybillNodePunch; +import org.springblade.transport.support.WaybillProcessSupport; import java.lang.reflect.Field; import java.util.ArrayList; @@ -165,6 +166,59 @@ class WaybillPunchRecordSaveTest { verify(nodePunchMapper, never()).updateById(any(WaybillNodePunch.class)); } + @Test + @DisplayName("待回单确认:补录打卡被拒——司机已无待打卡,漏打应先取消打卡退回进行中") + void rejectBackfillOnPendingReturnConfirm() { + Waybill waybill = waybill(); + waybill.setBusinessStatus(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM); + when(waybillMapper.selectById(WAYBILL_ID)).thenReturn(waybill); + when(nodePunchMapper.selectList(any())).thenReturn(List.of()); + + WaybillPunchRecordSaveRequest request = request("node", "load", "装货"); + request.setPunched(true); + + ServiceException exception = assertThrows(ServiceException.class, + () -> service.savePunchRecord(request)); + + assertEquals("运单待业务员确认回单,不能补录打卡", exception.getMessage()); + verify(nodePunchMapper, never()).insert(any(WaybillNodePunch.class)); + } + + @Test + @DisplayName("待回单确认:取消打卡仍放行——那是退回进行中的唯一路径") + void keepCancelPunchOnPendingReturnConfirm() { + Waybill waybill = waybill(); + waybill.setBusinessStatus(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM); + when(waybillMapper.selectById(WAYBILL_ID)).thenReturn(waybill); + when(nodePunchMapper.selectList(any())).thenReturn(List.of(nodePunch(7001L, "load", "装货"))); + + WaybillPunchRecordSaveRequest request = request("node", "load", "装货"); + request.setPunched(false); + + assertTrue(service.savePunchRecord(request)); + + ArgumentCaptor> captor = ArgumentCaptor.forClass(Collection.class); + verify(nodePunchMapper).deleteBatchIds(captor.capture()); + assertEquals(Set.of(7001L), new HashSet<>(captor.getValue())); + } + + @Test + @DisplayName("已完成运单仍可补录——门禁只对待回单确认生效") + void keepBackfillOnCompletedWaybill() { + Waybill waybill = waybill(); + waybill.setBusinessStatus("completed"); + when(waybillMapper.selectById(WAYBILL_ID)).thenReturn(waybill); + when(nodePunchMapper.selectList(any())).thenReturn(List.of()); + + WaybillPunchRecordSaveRequest request = request("node", "load", "装货"); + request.setPunched(true); + request.setPunchTime("2026-10-06 09:30:00"); + + assertTrue(service.savePunchRecord(request)); + + verify(nodePunchMapper).insert(any(WaybillNodePunch.class)); + } + @Test @DisplayName("接单节点:补录与取消打卡都拒绝——它的完成由运单的接单事实决定") void rejectAcceptNodePunchEdit() {