feat(task): TransportTaskService 扩展 RPC 创建方法(TDD)

- 新增 TransportTaskService.createTransportTaskByRpc() 接口方法
- 实现幂等检查(同 bizType+bizId 下未完结任务返回已有任务ID)
- 参数完整时状态置为待下发(040),否则生成(010)
- 添加单元测试覆盖正常创建和幂等返回两种场景
- 添加服务器模块测试依赖(JUnit 5, Mockito, AssertJ)
- 将 DTO 移至正确的 Maven 子模块位置
This commit is contained in:
2026-07-14 17:35:04 +08:00
parent 5684575abe
commit c6dffbcb61
10 changed files with 393 additions and 0 deletions

View File

@@ -115,6 +115,33 @@
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-monitor</artifactId>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -4,6 +4,7 @@ import java.util.*;
import jakarta.validation.*;
import cn.code.nl.module.task.controller.admin.transporttask.vo.*;
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
import cn.code.nl.module.task.dto.TransportTaskCreateReqDTO;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.common.pojo.PageParam;
@@ -22,6 +23,14 @@ public interface TransportTaskService {
*/
Long createTransportTask(@Valid TransportTaskSaveReqVO createReqVO);
/**
* 通过 RPC 创建搬运任务LMS/WMS 调用)
*
* @param reqDTO 创建请求
* @return 任务ID
*/
Long createTransportTaskByRpc(@Valid TransportTaskCreateReqDTO reqDTO);
/**
* 更新搬运任务
*

View File

@@ -6,6 +6,10 @@ import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskPag
import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskSaveReqVO;
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper;
import cn.code.nl.module.task.dto.TransportTaskCreateReqDTO;
import cn.code.nl.module.task.enums.CallbackStatusEnum;
import cn.code.nl.module.task.enums.TransportTaskStatusEnum;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -37,6 +41,31 @@ public class TransportTaskServiceImpl implements TransportTaskService {
return transportTask.getTaskId();
}
@Override
public Long createTransportTaskByRpc(TransportTaskCreateReqDTO reqDTO) {
// 1. 幂等检查:同 bizType + bizId 下是否有未完结任务
TransportTaskDO existing = transportTaskMapper.selectUnfinishedByBiz(
reqDTO.getBizType(), reqDTO.getBizId());
if (existing != null) {
return existing.getTaskId();
}
// 2. 构建 DO 并保存
TransportTaskDO task = BeanUtils.toBean(reqDTO, TransportTaskDO.class);
// 参数完整 → 待下发(040),否则 → 生成(010)
boolean paramComplete = StrUtil.isNotBlank(reqDTO.getPointCode1())
&& StrUtil.isNotBlank(reqDTO.getPointCode2());
task.setTaskStatus(paramComplete
? String.format("%03d", TransportTaskStatusEnum.READY.getCode())
: String.format("%03d", TransportTaskStatusEnum.CREATED.getCode()));
task.setCallbackStatus(CallbackStatusEnum.PENDING.getCode());
task.setCallbackRetryCount(0);
task.setCreateMode("RPC");
transportTaskMapper.insert(task);
return task.getTaskId();
}
@Override
public void updateTransportTask(TransportTaskSaveReqVO updateReqVO) {
// 校验存在

View File

@@ -0,0 +1,74 @@
package cn.code.nl.module.task.service.transporttask;
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper;
import cn.code.nl.module.task.dto.TransportTaskCreateReqDTO;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TransportTaskServiceImplTest {
@Mock
private TransportTaskMapper transportTaskMapper;
@InjectMocks
private TransportTaskServiceImpl transportTaskService;
@Test
void testCreateTransportTaskByRpc_shouldReturnTaskId() {
// given
TransportTaskCreateReqDTO req = new TransportTaskCreateReqDTO();
req.setTaskName("测试任务");
req.setOwnerService("LMS");
req.setBizType("INBOUND");
req.setBizId("INB-001");
req.setHandleCode("inboundHandler");
req.setAcsTaskType("MOVE");
req.setAgvSystemType("AGV_TYPE_A");
when(transportTaskMapper.selectUnfinishedByBiz("INBOUND", "INB-001")).thenReturn(null);
doAnswer(inv -> {
inv.getArgument(0, TransportTaskDO.class).setTaskId(1L);
return 1;
}).when(transportTaskMapper).insert((TransportTaskDO) any());
// when
Long taskId = transportTaskService.createTransportTaskByRpc(req);
// then
assertNotNull(taskId);
verify(transportTaskMapper, times(1)).insert((TransportTaskDO) any());
}
@Test
void testCreateTransportTaskByRpc_shouldReturnExistingWhenDuplicated() {
// given
TransportTaskCreateReqDTO req = new TransportTaskCreateReqDTO();
req.setTaskName("测试任务");
req.setOwnerService("LMS");
req.setBizType("INBOUND");
req.setBizId("INB-001");
req.setHandleCode("inboundHandler");
req.setAcsTaskType("MOVE");
req.setAgvSystemType("AGV_TYPE_A");
TransportTaskDO existing = TransportTaskDO.builder().taskId(99L).taskStatus("040").build();
when(transportTaskMapper.selectUnfinishedByBiz("INBOUND", "INB-001")).thenReturn(existing);
// when
Long taskId = transportTaskService.createTransportTaskByRpc(req);
// then
assertNotNull(taskId);
org.assertj.core.api.Assertions.assertThat(taskId).isEqualTo(99L);
verify(transportTaskMapper, never()).insert((TransportTaskDO) any());
}
}