🔥 删除司机端完成运单接口

- DriverWaybillController 去掉 POST /complete
- IDriverWaybillService/DriverWaybillServiceImpl 去掉 complete 及其独占的 assertNoUnresolvedException
- 末位打卡自动完成仍用 COMPLETABLE_STATUSES 与 canAutoCompleteWaybill
- 新增 WaybillCompleteEndpointTest:司机端完成端点已 404,管理端完成接口仍在
This commit is contained in:
2026-10-22 13:49:55 +08:00
parent 94b54db24d
commit 5f53a8671d
4 changed files with 72 additions and 43 deletions
@@ -201,13 +201,6 @@ public class DriverWaybillController extends BladeController {
return R.data(driverWaybillService.submitNode(dto));
}
@PostMapping("/complete")
@ApiOperationSupport(order = 10)
@Operation(summary = "司机完成运单", description = "校验司机归属后改状态为已完成,并检查生成应收应付明细(与管理端一致)")
public R complete(@Parameter(description = "运单ID", required = true) @RequestParam Long id) {
return R.status(driverWaybillService.complete(id));
}
/** 前端可能传空字符串表示「全部」 */
private Integer parseStatus(String status) {
if (Func.isEmpty(status)) {
@@ -157,11 +157,6 @@ public interface IDriverWaybillService {
*/
DriverNodePunchVO submitNode(NodeSubmitDTO dto);
/**
* 司机完成运单:校验归属后改状态为已完成,并走与管理端相同的应收应付明细生成逻辑。
*/
boolean complete(Long id);
/**
* 按运单与节点 key 取该运单实际生效的过程节点配置;节点不存在时返回 null。
* <p>
@@ -611,24 +611,6 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
return waybillService.updateById(waybill);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean complete(Long id) {
if (id == null) {
throw new ServiceException("运单ID不能为空");
}
requireCurrentDriver();
Waybill waybill = loadDriverWaybill(id);
waybill = normalizeAcceptStatus(waybill);
if (!COMPLETABLE_STATUSES.contains(waybill.getBusinessStatus())) {
throw new ServiceException("当前运单状态不允许完成");
}
// 有未了结异常时不允许完成——完成接口不要求节点全部打卡,不挡住就能绕过打卡门禁
assertNoUnresolvedException(waybill.getId());
// 与管理端完成逻辑一致:改状态 + 生成应收应付明细 + 尝试完成配载单
return waybillService.completeWithoutDeptCheck(waybill.getId());
}
private void assertAcceptable(Waybill waybill) {
if (WaybillProcessSupport.isTerminalBusinessStatus(waybill.getBusinessStatus())) {
throw new ServiceException("当前运单状态不允许接单");
@@ -1519,7 +1501,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
}
/**
* 自动完成的前置:与司机端「完成运单」同一套——业务状态允许完成,且没有未了结异常。
* 自动完成的前置:业务状态允许完成,且没有未了结异常。
* <p>
* 不满足返回 false,由调用方静默跳过,打卡不受影响。
*/
@@ -1528,18 +1510,6 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
&& unresolvedExceptionNodeCodeList(waybill.getId()).isEmpty();
}
/**
* 断言该运单没有未了结的异常。
* <p>
* 完成运单前必须校验:完成接口本身不要求节点全部打卡,不挡住它就能从
* 「完成运单」绕过打卡门禁。
*/
private void assertNoUnresolvedException(Long waybillId) {
if (!unresolvedExceptionNodeCodeList(waybillId).isEmpty()) {
throw new ServiceException("该运单存在未处理异常,处理完成后才能完成运单");
}
}
/**
* 组装过程配置 punch=是 的打卡节点列表。
* <p>
@@ -0,0 +1,71 @@
package org.springblade.transport.controller;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springblade.transport.service.IContractManageService;
import org.springblade.transport.service.ICustomerArchiveService;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IProjectApplyService;
import org.springblade.transport.service.ITransportPlanService;
import org.springblade.transport.service.IWaybillImportBatchService;
import org.springblade.transport.service.IWaybillService;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* 运单「完成运单」接口的边界:司机端不再有完成入口,管理端强制完成仍可达。
* <p>
* 走真实 HTTP 路由:司机端那条链删没删干净由 404 说话,管理端保持可用由 200 + 落到
* {@code waybillService.complete} 说话。
*/
class WaybillCompleteEndpointTest {
private IWaybillService waybillService;
private MockMvc driverMvc;
private MockMvc manageMvc;
@BeforeEach
void setUp() {
waybillService = mock(IWaybillService.class);
DriverWaybillController driverController = new DriverWaybillController(mock(IDriverWaybillService.class));
driverMvc = MockMvcBuilders.standaloneSetup(driverController).build();
WaybillController manageController = new WaybillController(
waybillService,
mock(IProjectApplyService.class),
mock(IContractManageService.class),
mock(ICustomerArchiveService.class),
mock(ITransportPlanService.class),
mock(IWaybillImportBatchService.class));
manageMvc = MockMvcBuilders.standaloneSetup(manageController).build();
}
@Test
@DisplayName("POST /blade-transport/waybill/complete:司机端完成运单路由已下线")
void driverCompleteRouteIsGone() throws Exception {
driverMvc.perform(post("/blade-transport/waybill/complete").param("id", "6001"))
.andExpect(status().isNotFound());
driverMvc.perform(post("/waybill/complete").param("id", "6001"))
.andExpect(status().isNotFound());
}
@Test
@DisplayName("POST /waybill-manage/complete:管理端强制完成仍可达")
void manageCompleteRouteIsKept() throws Exception {
when(waybillService.complete(6001L)).thenReturn(true);
manageMvc.perform(post("/waybill-manage/complete").param("id", "6001"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
verify(waybillService).complete(6001L);
}
}