feat(qms-incoming-inspection-task): 实现来料检测任务管理模块

- 新增来料检测任务 Controller 服务,实现申请、查询、转办等功能
- 实现自动选择质检人员逻辑,支持物料绑定、物料类别递归绑定及转办人替换
- 支持来料检验申请,完成时间自动计算并生成检测单号
- 实现基于历史数据的抽样严格性转移规则计算逻辑
- 提供分页查询、待检任务查询及当前用户任务数量统计接口
- 实现任务转办功能,限制已检任务转办,校验代办人有效性
- 编写对应接口 Controller,提供 REST API 支持前端调用
- 新增数据访问层接口及 MyBatis Mapper,实现数据库操作支持
- 配置 Maven POM 文件,统一管理项目依赖及模块结构
This commit is contained in:
曹鹏飞 2026-04-23 09:58:48 +08:00
parent b05f5b24d6
commit cbf034db3e
21 changed files with 989 additions and 8 deletions

View File

@ -0,0 +1,33 @@
package com.nflg.qms.admin.controller;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskAqlRuleSearchQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskAqlRuleVO;
import com.nflg.wms.repository.service.IQmsIncomingInspectionTaskAqlRuleService;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 来料检验任务AQL规则
*/
@RestController
@RequestMapping("/incoming-inspection-task-aql-rule")
public class QmsIncomingInspectionTaskAqlRuleController extends BaseController {
@Resource
private IQmsIncomingInspectionTaskAqlRuleService incomingInspectionTaskAqlRuleService;
/**
* 分页查询来料检验任务AQL规则列表
*/
@PostMapping("search")
public ApiResult<PageData<QmsIncomingInspectionTaskAqlRuleVO>> search(@Valid @RequestBody QmsIncomingInspectionTaskAqlRuleSearchQO request) {
return ApiResult.success(incomingInspectionTaskAqlRuleService.search(request));
}
}

View File

@ -4,6 +4,7 @@ import com.nflg.qms.admin.service.IncomingInspectionTaskControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTransferQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
@ -43,6 +44,14 @@ public class QmsIncomingInspectionTaskController extends BaseController {
return ApiResult.success();
}
/**
* 查询当前登录用户的待检验任务列表
*/
@PostMapping("todo-search")
public ApiResult<PageData<QmsIncomingInspectionTaskVO>> todoSearch(@Valid @RequestBody QmsIncomingInspectionTaskTodoSearchQO request) {
return ApiResult.success(incomingInspectionTaskControllerService.todoSearch(request));
}
/**
* 查询当前登录用户的任务数量待检验数量检验中数量已延期数量
*/

View File

@ -1,10 +1,14 @@
package com.nflg.qms.admin.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.nflg.wms.common.constant.STATE;
import com.nflg.wms.common.exception.NflgException;
import com.nflg.wms.common.pojo.qo.ExternalIncomingInspectionApplyQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTransferQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
@ -14,6 +18,7 @@ import com.nflg.wms.repository.entity.*;
import com.nflg.wms.repository.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@ -31,6 +36,9 @@ public class IncomingInspectionTaskControllerService {
@Resource
private IQmsIncomingInspectionTaskService incomingInspectionTaskService;
@Resource
private IQmsInspectionStandardItemService inspectionStandardItemService;
@Resource
private IQmsQualityInspectorService qualityInspectorService;
@ -58,6 +66,15 @@ public class IncomingInspectionTaskControllerService {
@Resource
private IDictionaryItemService dictionaryItemService;
@Resource
private IQmsIncomingInspectionTaskAqlRuleService incomingInspectionTaskAqlRuleService;
@Resource
private IQmsSupplierInspectionStatisticsService supplierInspectionStatisticsService;
@Resource
private IQmsSamplingStrictnessTransferRuleService samplingStrictnessTransferRuleService;
/**
* 来料检验申请对外接口
* 业务规则
@ -157,6 +174,128 @@ public class IncomingInspectionTaskControllerService {
.setRequiredFinishTime(requiredFinishTime);
incomingInspectionTaskService.save(task);
// 8. 生成来料检验任务AQL方案
Long inspectionStandardId = dictionaryItemService.getIdByCode("InspectionStandardSamplingMethod", "Sampling");
VUtil.trueThrowBusinessError(Objects.isNull(inspectionStandardId)).throwMessage("检测方式不存在");
List<QmsInspectionStandardItem> inspectionStandardItems = inspectionStandardItemService.lambdaQuery()
.eq(QmsInspectionStandardItem::getInspectionStandardId, standard.getId())
.eq(QmsInspectionStandardItem::getTestingMethodDictItemId, inspectionStandardId)
.orderByAsc(QmsInspectionStandardItem::getSortNo)
.list();
if (!inspectionStandardItems.isEmpty()) {
incomingInspectionTaskAqlRuleService.saveBatch(
inspectionStandardItems.stream()
.map(item -> {
Pair<Long, Short> aqlType = CalculatedAqlType(task, item
, dictionaryItemService.getListByDictionaryCode("InspectionStandardSQLType"));
return new QmsIncomingInspectionTaskAqlRule()
.setTaskId(task.getId())
.setInspectionItemId(item.getId())
.setCalculatedAqlType(aqlType.getLeft())
.setUsedAqlType(aqlType.getLeft())
.setTriggerCategory(aqlType.getRight())
.setTriggerTime(LocalDateTime.now());
})
.toList()
);
}
}
private DictionaryItem getAql(Long id, List<DictionaryItem> aqls) {
return aqls.stream().filter(aql -> Objects.equals(aql.getId(), id)).findFirst().get();
}
private Pair<Long, Short> CalculatedAqlType(QmsIncomingInspectionTask task, QmsInspectionStandardItem item
, List<DictionaryItem> aqls) {
DictionaryItem sqlzc = aqls.stream().filter(aql -> StrUtil.equals(aql.getCode(), "正常")).findFirst().get();
DictionaryItem sqljy = aqls.stream().filter(aql -> StrUtil.equals(aql.getCode(), "加严")).findFirst().get();
DictionaryItem sqlfw = aqls.stream().filter(aql -> StrUtil.equals(aql.getCode(), "放宽")).findFirst().get();
log.info("【抽样严格性转移规则计算】检验项严格性为:" + getAql(item.getAqlTypeDictItemId(), aqls).getName());
List<QmsSupplierInspectionStatistics> statistics = supplierInspectionStatisticsService.lambdaQuery()
.eq(QmsSupplierInspectionStatistics::getInspectionItemId, item.getId())
.eq(QmsSupplierInspectionStatistics::getSupplierCode, task.getSupplierCode())
.orderByDesc(QmsSupplierInspectionStatistics::getId)
.last("LIMIT 20")
.list();
if (statistics.isEmpty()) {
log.info("【抽样严格性转移规则计算】历史检验记录为空,使用检验项严格性");
return Pair.of(item.getAqlTypeDictItemId(), (short) 0);
} else {
QmsSupplierInspectionStatistics s1 = statistics.get(0);
log.info("【抽样严格性转移规则计算】最新一次检验严格性为:" + getAql(s1.getAqlType(), aqls).getName());
LambdaQueryChainWrapper<QmsSamplingStrictnessTransferRule> queryWrapper = samplingStrictnessTransferRuleService.lambdaQuery()
.eq(QmsSamplingStrictnessTransferRule::getSamplingPlanId, item.getSamplingPlanId())
.eq(QmsSamplingStrictnessTransferRule::getIsEnabled, true);
if (Objects.equals(s1.getAqlType(), sqljy.getId())) {
log.info("【抽样严格性转移规则计算】检查是否符合 加严 => 正常 规则");
QmsSamplingStrictnessTransferRule rule = queryWrapper.eq(QmsSamplingStrictnessTransferRule::getRuleType, 3).one();
if (Objects.isNull(rule)) {
log.info("【抽样严格性转移规则计算】加严 => 正常 规则不存在,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
} else if (statistics.stream().limit(rule.getContinuousBatchCount()).allMatch(QmsSupplierInspectionStatistics::getQualified)) {
log.info("【抽样严格性转移规则计算】符合 加严 => 正常 规则,使用正常严格性");
return Pair.of(sqlzc.getId(), (short) 1);
} else {
log.info("【抽样严格性转移规则计算】不符合 加严 => 正常 规则,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
}
} else if (Objects.equals(s1.getAqlType(), sqlfw.getId())) {
log.info("【抽样严格性转移规则计算】检查是否符合 放宽 => 正常 规则");
QmsSamplingStrictnessTransferRule rule = queryWrapper.eq(QmsSamplingStrictnessTransferRule::getRuleType, 1).one();
if (Objects.isNull(rule)) {
log.info("【抽样严格性转移规则计算】放宽 => 正常 规则不存在,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
} else if (statistics.stream()
.limit(rule.getContinuousBatchCount())
.filter(stat -> !stat.getQualified())
.count() >= rule.getUnqualifiedBatchCount()
) {
log.info("【抽样严格性转移规则计算】符合 放宽 => 正常 规则,使用正常严格性");
return Pair.of(sqlzc.getId(), (short) 1);
} else {
log.info("【抽样严格性转移规则计算】不符合 放宽 => 正常 规则,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
}
} else if (Objects.equals(s1.getAqlType(), sqlzc.getId())) {
List<QmsSamplingStrictnessTransferRule> rules = queryWrapper.in(QmsSamplingStrictnessTransferRule::getRuleType, 0, 2).list();
if (CollectionUtil.isEmpty(rules)) {
log.info("【抽样严格性转移规则计算】正常 => 加严 和 正常 => 加严 规则都不存在,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
}
for (QmsSamplingStrictnessTransferRule rule : rules) {
if (rule.getRuleType() == 0) {
log.info("【抽样严格性转移规则计算】检查是否符合 正常 => 加严 规则");
if (statistics.stream()
.limit(rule.getContinuousBatchCount())
.filter(stat -> !stat.getQualified())
.count() >= rule.getUnqualifiedBatchCount()
) {
log.info("【抽样严格性转移规则计算】符合 正常 => 加严 规则,使用加严严格性");
return Pair.of(sqljy.getId(), (short) 1);
} else {
log.info("【抽样严格性转移规则计算】不符合 正常 => 加严 规则,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
}
} else if (rule.getRuleType() == 2) {
log.info("【抽样严格性转移规则计算】检查是否符合 正常 => 放宽 规则");
if (statistics.stream()
.limit(rule.getContinuousBatchCount())
.allMatch(QmsSupplierInspectionStatistics::getQualified)
) {
log.info("【抽样严格性转移规则计算】符合 正常 => 放宽 规则,使用放宽严格性");
return Pair.of(sqlfw.getId(), (short) 1);
} else {
log.info("【抽样严格性转移规则计算】不符合 正常 => 放宽 规则,使用最新一次检验严格性");
return Pair.of(s1.getAqlType(), (short) 0);
}
}
}
throw new NflgException(STATE.BusinessError, "无效的AQL类型");
} else {
throw new NflgException(STATE.BusinessError, "无效的AQL类型");
}
}
}
/**
@ -243,6 +382,24 @@ public class IncomingInspectionTaskControllerService {
return incomingInspectionTaskService.search(request);
}
/**
* 查询当前登录用户的待检验任务列表
* 只查询待检验0和检验中1的任务
* 只查询检验人或代办人为当前用户的数据
* 按要求完成时间正序排序
*/
public IPage<QmsIncomingInspectionTaskVO> todoSearch(QmsIncomingInspectionTaskTodoSearchQO request) {
Long userId = UserUtil.getUserId();
// 通过当前登录用户的 userId 查询对应的质检人员记录
QmsQualityInspector inspector = qualityInspectorService.lambdaQuery()
.eq(QmsQualityInspector::getUserId, userId)
.last("LIMIT 1")
.one();
VUtil.trueThrowBusinessError(Objects.isNull(inspector))
.throwMessage("当前用户不是质检人员,无法查询待检验任务");
return incomingInspectionTaskService.todoSearch(request, inspector.getId());
}
/**
* 查询当前登录用户的任务数量统计
* 待检验检验状态=0检验中检验状态=1已延期是否超期=true

View File

@ -0,0 +1,292 @@
package com.nflg.qms.admin;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoSearchQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
/**
* 待检验任务查询接口测试
* <p>
* 测试前提
* 1. qms-admin 服务已启动默认 http://localhost:8105
* 2. 测试账号已登录将有效的 token 填入 TOKEN 常量
* 3. 数据库中存在检验状态为待检0或检验中1且检验人或代办人为当前登录用户的任务
* 4. 根据实际情况修改下方搜索常量SEARCH_MATERIAL_NO 为数据库中真实存在的值
* </p>
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class QmsIncomingInspectionTaskTodoSearchApiTest {
// ===================== 配置区 =====================
/** 服务地址 */
private static final String BASE_URL = "http://localhost:8105";
/** 当前登录用户的 token */
private static final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiWjlpczhQa0I3YjNlMEtMa0JMQkRudFlhSkJGWUY0YW8iLCJuYW1lIjoi6LaF57qn566h55CG5ZGYIiwiY29kZSI6ImFkbWluIiwicm9sZXMiOlsiU3VwZXJBZG1pbiJdLCJ0eXBlIjoxfQ.SepkxVP75CbPm-7ImN2sn0fiskVbKZj7axikvAHijko";
/** 用于搜索的物料编号(需根据实际情况修改) */
private static final String SEARCH_MATERIAL_NO = "2200052100";
/** 用于搜索的物料图号(需根据实际情况修改) */
private static final String SEARCH_DRAWING_NO = "DWG";
/** 用于搜索的检测单号前缀(需根据实际情况修改) */
private static final String SEARCH_TASK_NO_PREFIX = "IC";
/** 用于搜索的供应商编号(需根据实际情况修改) */
private static final String SEARCH_SUPPLIER_CODE = "SUP";
/** 用于搜索的供应商名称(需根据实际情况修改) */
private static final String SEARCH_SUPPLIER_NAME = "供应商";
// ===================== 配置区结束 =====================
// ==================== HTTP 工具方法 ====================
private static <T> ApiResult<T> post(String path, Object body, TypeReference<ApiResult<T>> typeRef) {
String url = BASE_URL + path;
String reqBody = body == null ? "" : JSONUtil.toJsonStr(body);
String raw;
try (HttpResponse resp = HttpRequest.post(url)
.header("authorization", TOKEN)
.header("Content-Type", "application/json")
.body(reqBody)
.execute()) {
raw = resp.body();
}
System.out.println("[POST] " + path);
System.out.println(" 请求: " + reqBody);
System.out.println(" 响应: " + raw);
return JSONUtil.toBean(raw, typeRef, false);
}
private static <T> void assertSuccess(ApiResult<T> result, String msg) {
Assert.isTrue(result != null && result.getCode() == 200,
() -> new RuntimeException(msg + " => " + JSONUtil.toJsonStr(result)));
}
private static void assertFailed(ApiResult<?> result, String msg) {
Assert.isTrue(result != null && result.getCode() != 200,
() -> new RuntimeException(msg + " => 预期失败但实际成功"));
}
// ==================== 待检验任务查询接口测试 ====================
/**
* 待检验任务查询正常查询
* 验证点
* 1. 接口返回成功
* 2. 返回分页数据结构正确
* 3. 返回的数据中检验状态只包含待检0或检验中1
* 4. 数据按要求完成时间正序排列
*/
@Test
@Order(1)
public void test01_todoSearch_Success() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "待检验任务查询失败");
PageData<QmsIncomingInspectionTaskVO> pageData = result.getResult();
Assert.notNull(pageData, "分页数据不应为空");
Assert.isTrue(pageData.getPage() == 1, "当前页码应为1");
Assert.isTrue(pageData.getPageSize() == 10, "每页数量应为10");
// 验证返回的数据状态只包含 0 1
if (pageData.getItems() != null && !pageData.getItems().isEmpty()) {
for (QmsIncomingInspectionTaskVO item : pageData.getItems()) {
Short status = item.getInspectionStatus();
Assert.isTrue(status != null && (status == 0 || status == 1),
() -> new RuntimeException("返回了非待检/检验中的任务,状态=" + status));
}
// 验证按要求完成时间正序排列
for (int i = 1; i < pageData.getItems().size(); i++) {
var prev = pageData.getItems().get(i - 1).getRequiredFinishTime();
var curr = pageData.getItems().get(i).getRequiredFinishTime();
if (prev != null && curr != null) {
Assert.isTrue(!prev.isAfter(curr),
() -> new RuntimeException("数据未按要求完成时间正序排列"));
}
}
}
System.out.println(" ✅ 待检验任务查询成功,总数: " + pageData.getTotal());
}
/**
* 待检验任务查询按物料编号模糊搜索
* 验证点返回的物料编号包含搜索关键词
*/
@Test
@Order(2)
public void test02_todoSearch_ByMaterialNo() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setMaterialNo(SEARCH_MATERIAL_NO);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "按物料编号搜索失败");
PageData<QmsIncomingInspectionTaskVO> pageData = result.getResult();
if (pageData.getItems() != null && !pageData.getItems().isEmpty()) {
for (QmsIncomingInspectionTaskVO item : pageData.getItems()) {
Assert.isTrue(item.getMaterialNo() != null && item.getMaterialNo().contains(SEARCH_MATERIAL_NO),
() -> new RuntimeException("返回的物料编号不匹配: " + item.getMaterialNo()));
}
}
System.out.println(" ✅ 按物料编号搜索成功,匹配数: " + pageData.getTotal());
}
/**
* 待检验任务查询按物料图号模糊搜索
* 验证点返回匹配的数据
*/
@Test
@Order(3)
public void test03_todoSearch_ByDrawingNo() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setDrawingNo(SEARCH_DRAWING_NO);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "按物料图号搜索失败");
System.out.println(" ✅ 按物料图号搜索成功,匹配数: " + result.getResult().getTotal());
}
/**
* 待检验任务查询按检测单号模糊搜索
* 验证点返回的检测单号包含搜索关键词
*/
@Test
@Order(4)
public void test04_todoSearch_ByTaskNo() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setTaskNo(SEARCH_TASK_NO_PREFIX);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "按检测单号搜索失败");
PageData<QmsIncomingInspectionTaskVO> pageData = result.getResult();
if (pageData.getItems() != null && !pageData.getItems().isEmpty()) {
for (QmsIncomingInspectionTaskVO item : pageData.getItems()) {
Assert.isTrue(item.getTaskNo() != null && item.getTaskNo().contains(SEARCH_TASK_NO_PREFIX),
() -> new RuntimeException("返回的检测单号不匹配: " + item.getTaskNo()));
}
}
System.out.println(" ✅ 按检测单号搜索成功,匹配数: " + pageData.getTotal());
}
/**
* 待检验任务查询按供应商编号模糊搜索
* 验证点返回匹配的数据
*/
@Test
@Order(5)
public void test05_todoSearch_BySupplierCode() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setSupplierCode(SEARCH_SUPPLIER_CODE);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "按供应商编号搜索失败");
System.out.println(" ✅ 按供应商编号搜索成功,匹配数: " + result.getResult().getTotal());
}
/**
* 待检验任务查询按供应商名称模糊搜索
* 验证点返回匹配的数据
*/
@Test
@Order(6)
public void test06_todoSearch_BySupplierName() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setSupplierName(SEARCH_SUPPLIER_NAME);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "按供应商名称搜索失败");
System.out.println(" ✅ 按供应商名称搜索成功,匹配数: " + result.getResult().getTotal());
}
/**
* 待检验任务查询组合条件搜索
* 验证点多个条件同时生效返回同时满足的数据
*/
@Test
@Order(7)
public void test07_todoSearch_CombinedConditions() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setMaterialNo(SEARCH_MATERIAL_NO);
request.setSupplierName(SEARCH_SUPPLIER_NAME);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "组合条件搜索失败");
System.out.println(" ✅ 组合条件搜索成功,匹配数: " + result.getResult().getTotal());
}
/**
* 待检验任务查询分页参数验证
* 验证点第二页返回正确的分页信息
*/
@Test
@Order(8)
public void test08_todoSearch_Pagination() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(2);
request.setPageSize(5);
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "分页查询失败");
PageData<QmsIncomingInspectionTaskVO> pageData = result.getResult();
Assert.notNull(pageData, "分页数据不应为空");
Assert.isTrue(pageData.getPage() == 2, "当前页码应为2");
Assert.isTrue(pageData.getPageSize() == 5, "每页数量应为5");
// 如果有数据验证返回条数不超过 pageSize
if (pageData.getItems() != null) {
Assert.isTrue(pageData.getItems().size() <= 5,
() -> new RuntimeException("返回数据条数超过每页限制"));
}
System.out.println(" ✅ 分页查询成功,当前页: " + pageData.getPage() + ", 返回条数: " + pageData.getItems().size());
}
/**
* 待检验任务查询无匹配结果
* 验证点使用不可能存在的条件搜索返回空列表但接口成功
*/
@Test
@Order(9)
public void test09_todoSearch_NoResult() {
QmsIncomingInspectionTaskTodoSearchQO request = new QmsIncomingInspectionTaskTodoSearchQO();
request.setPage(1);
request.setPageSize(10);
request.setTaskNo("NOT_EXIST_TASK_NO_999999");
ApiResult<PageData<QmsIncomingInspectionTaskVO>> result = post("/incoming-inspection-task/todo-search", request, new TypeReference<>() {});
assertSuccess(result, "无结果查询失败");
PageData<QmsIncomingInspectionTaskVO> pageData = result.getResult();
Assert.notNull(pageData, "分页数据不应为空");
Assert.isTrue(pageData.getTotal() == 0, "总数应为0");
Assert.isTrue(pageData.getItems() == null || pageData.getItems().isEmpty(), "列表应为空");
System.out.println(" ✅ 无结果查询成功,返回空列表");
}
}

View File

@ -0,0 +1,32 @@
package com.nflg.wms.common.pojo.qo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 来料检验任务AQL规则 - 分页查询QO
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class QmsIncomingInspectionTaskAqlRuleSearchQO extends PageQO {
/**
* 供应商编号模糊匹配
*/
private String supplierCode;
/**
* 供应商名称模糊匹配
*/
private String supplierName;
/**
* 物料编码模糊匹配
*/
private String materialNo;
/**
* 检测项id精确匹配
*/
private Long inspectionItemId;
}

View File

@ -0,0 +1,37 @@
package com.nflg.wms.common.pojo.qo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 待检验任务查询条件
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class QmsIncomingInspectionTaskTodoSearchQO extends PageQO {
/**
* 物料编码模糊匹配
*/
private String materialNo;
/**
* 物料图号模糊匹配
*/
private String drawingNo;
/**
* 检测单号模糊匹配
*/
private String taskNo;
/**
* 供应商编号模糊匹配
*/
private String supplierCode;
/**
* 供应商名称模糊匹配
*/
private String supplierName;
}

View File

@ -0,0 +1,87 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 来料检验任务AQL规则 - 查询返回VO
*/
@Data
public class QmsIncomingInspectionTaskAqlRuleVO {
/**
* 检测任务编号
*/
private String taskNo;
/**
* 供应商编号
*/
private String supplierCode;
/**
* 供应商名称
*/
private String supplierName;
/**
* 物料编号
*/
private String materialNo;
/**
* 物料名称
*/
private String materialName;
/**
* 物料描述
*/
private String materialDesc;
/**
* 检测项id关联检验标准项表
*/
private Long inspectionItemId;
/**
* 检测项名称
*/
private String inspectionItemName;
/**
* 计算的AQL类型字典项id
*/
private Long calculatedAqlType;
/**
* 使用的AQL类型字典项id
*/
private Long usedAqlType;
/**
* 触发类别0=默认状态1=触发规则2=手动调整
*/
private Short triggerCategory;
/**
* 触发类别名称
*/
private String triggerCategoryName;
/**
* 触发时间
*/
private LocalDateTime triggerTime;
/**
* 触发人id
*/
private Long triggerUserId;
/**
* 触发人姓名
*/
private String triggerUserName;
}

View File

@ -0,0 +1,68 @@
package com.nflg.wms.repository.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 来料检验任务AQL规则
*/
@Getter
@Setter
@ToString
@Accessors(chain = true)
@TableName("qms_incoming_inspection_task_aql_rule")
public class QmsIncomingInspectionTaskAqlRule implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 检测任务id关联来料检验任务表
*/
private Long taskId;
/**
* 检测项id关联检验标准项表
*/
private Long inspectionItemId;
/**
* 计算的AQL类型字典项id
*/
private Long calculatedAqlType;
/**
* 使用的AQL类型字典项id
*/
private Long usedAqlType;
/**
* 触发类别0=默认状态1=触发规则2=手动调整
*/
private Short triggerCategory;
/**
* 触发时间
*/
private LocalDateTime triggerTime;
/**
* 触发人id
*/
private Long triggerUserId;
/**
* 触发人姓名
*/
private String triggerUserName;
}

View File

@ -0,0 +1,50 @@
package com.nflg.wms.repository.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 供应商检验统计
*/
@Getter
@Setter
@ToString
@Accessors(chain = true)
@TableName("qms_supplier_inspection_statistics")
public class QmsSupplierInspectionStatistics implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 供应商编号
*/
private String supplierCode;
/**
* 检测项id
*/
private Long inspectionItemId;
/**
* 是否合格
*/
private Boolean qualified;
/**
* AQL类型字典项id
*/
private Long aqlType;
}

View File

@ -0,0 +1,19 @@
package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskAqlRuleSearchQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskAqlRuleVO;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTaskAqlRule;
/**
* 来料检验任务AQL规则 Mapper
*/
public interface QmsIncomingInspectionTaskAqlRuleMapper extends BaseMapper<QmsIncomingInspectionTaskAqlRule> {
/**
* 分页查询来料检验任务AQL规则列表
*/
IPage<QmsIncomingInspectionTaskAqlRuleVO> search(QmsIncomingInspectionTaskAqlRuleSearchQO request, Page<Object> page);
}

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoSearchQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTask;
@ -13,4 +14,6 @@ import com.nflg.wms.repository.entity.QmsIncomingInspectionTask;
public interface QmsIncomingInspectionTaskMapper extends BaseMapper<QmsIncomingInspectionTask> {
IPage<QmsIncomingInspectionTaskVO> search(QmsIncomingInspectionTaskSearchQO request, Page<Object> page);
IPage<QmsIncomingInspectionTaskVO> todoSearch(QmsIncomingInspectionTaskTodoSearchQO request, Page<Object> page, Long inspectorId);
}

View File

@ -0,0 +1,10 @@
package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nflg.wms.repository.entity.QmsSupplierInspectionStatistics;
/**
* 供应商检验统计 Mapper
*/
public interface QmsSupplierInspectionStatisticsMapper extends BaseMapper<QmsSupplierInspectionStatistics> {
}

View File

@ -0,0 +1,18 @@
package com.nflg.wms.repository.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskAqlRuleSearchQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskAqlRuleVO;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTaskAqlRule;
/**
* 来料检验任务AQL规则 服务类
*/
public interface IQmsIncomingInspectionTaskAqlRuleService extends IService<QmsIncomingInspectionTaskAqlRule> {
/**
* 分页查询来料检验任务AQL规则列表
*/
IPage<QmsIncomingInspectionTaskAqlRuleVO> search(QmsIncomingInspectionTaskAqlRuleSearchQO request);
}

View File

@ -3,6 +3,7 @@ package com.nflg.wms.repository.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTransferQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
@ -18,6 +19,15 @@ public interface IQmsIncomingInspectionTaskService extends IService<QmsIncomingI
*/
IPage<QmsIncomingInspectionTaskVO> search(QmsIncomingInspectionTaskSearchQO request);
/**
* 查询当前登录用户的待检验任务列表
*
* @param request 查询条件
* @param inspectorId 质检人员id
* @return 分页结果
*/
IPage<QmsIncomingInspectionTaskVO> todoSearch(QmsIncomingInspectionTaskTodoSearchQO request, Long inspectorId);
/**
* 转办
*/

View File

@ -0,0 +1,10 @@
package com.nflg.wms.repository.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nflg.wms.repository.entity.QmsSupplierInspectionStatistics;
/**
* 供应商检验统计 服务类
*/
public interface IQmsSupplierInspectionStatisticsService extends IService<QmsSupplierInspectionStatistics> {
}

View File

@ -0,0 +1,23 @@
package com.nflg.wms.repository.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskAqlRuleSearchQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskAqlRuleVO;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTaskAqlRule;
import com.nflg.wms.repository.mapper.QmsIncomingInspectionTaskAqlRuleMapper;
import com.nflg.wms.repository.service.IQmsIncomingInspectionTaskAqlRuleService;
import org.springframework.stereotype.Service;
/**
* 来料检验任务AQL规则 服务实现类
*/
@Service
public class QmsIncomingInspectionTaskAqlRuleServiceImpl extends ServiceImpl<QmsIncomingInspectionTaskAqlRuleMapper, QmsIncomingInspectionTaskAqlRule> implements IQmsIncomingInspectionTaskAqlRuleService {
@Override
public IPage<QmsIncomingInspectionTaskAqlRuleVO> search(QmsIncomingInspectionTaskAqlRuleSearchQO request) {
return baseMapper.search(request, new Page<>(request.getPage(), request.getPageSize()));
}
}

View File

@ -4,13 +4,13 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoSearchQO;
import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTransferQO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskCountVO;
import com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTask;
import com.nflg.wms.repository.mapper.QmsIncomingInspectionTaskMapper;
import com.nflg.wms.repository.service.IQmsIncomingInspectionTaskService;
import com.nflg.wms.repository.service.IWmsSrmOrderItemService;
import org.springframework.stereotype.Service;
import java.util.List;
@ -21,17 +21,16 @@ import java.util.List;
@Service
public class QmsIncomingInspectionTaskServiceImpl extends ServiceImpl<QmsIncomingInspectionTaskMapper, QmsIncomingInspectionTask> implements IQmsIncomingInspectionTaskService {
private final IWmsSrmOrderItemService iWmsSrmOrderItemService;
public QmsIncomingInspectionTaskServiceImpl(IWmsSrmOrderItemService iWmsSrmOrderItemService) {
this.iWmsSrmOrderItemService = iWmsSrmOrderItemService;
}
@Override
public IPage<QmsIncomingInspectionTaskVO> search(QmsIncomingInspectionTaskSearchQO request) {
return baseMapper.search(request, new Page<>(request.getPage(), request.getPageSize()));
}
@Override
public IPage<QmsIncomingInspectionTaskVO> todoSearch(QmsIncomingInspectionTaskTodoSearchQO request, Long inspectorId) {
return baseMapper.todoSearch(request, new Page<>(request.getPage(), request.getPageSize()), inspectorId);
}
@Override
public void transfer(QmsIncomingInspectionTaskTransferQO request) {
// 转办逻辑由 ControllerService 处理此处留空

View File

@ -0,0 +1,15 @@
package com.nflg.wms.repository.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nflg.wms.repository.entity.QmsSupplierInspectionStatistics;
import com.nflg.wms.repository.mapper.QmsSupplierInspectionStatisticsMapper;
import com.nflg.wms.repository.service.IQmsSupplierInspectionStatisticsService;
import org.springframework.stereotype.Service;
/**
* 供应商检验统计 服务实现类
*/
@Service
public class QmsSupplierInspectionStatisticsServiceImpl extends ServiceImpl<QmsSupplierInspectionStatisticsMapper, QmsSupplierInspectionStatistics>
implements IQmsSupplierInspectionStatisticsService {
}

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.wms.repository.mapper.QmsIncomingInspectionTaskAqlRuleMapper">
<select id="search" resultType="com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskAqlRuleVO">
SELECT
t.task_no,
t.supplier_code,
t.supplier_name,
m.material_no,
m.material_name,
m.material_desc,
r.inspection_item_id,
si.name AS inspection_item_name,
r.calculated_aql_type,
r.used_aql_type,
r.trigger_category,
CASE r.trigger_category
WHEN 0 THEN '默认状态'
WHEN 1 THEN '触发规则'
WHEN 2 THEN '手动调整'
END AS trigger_category_name,
r.trigger_time,
r.trigger_user_id,
r.trigger_user_name
FROM qms_incoming_inspection_task_aql_rule r
INNER JOIN qms_incoming_inspection_task t ON r.task_id = t.id
INNER JOIN qms_qc_material m ON t.material_id = m.id
LEFT JOIN qms_inspection_standard_item si ON r.inspection_item_id = si.id
<where>
t.inspection_status IN (0, 1)
<if test="request.supplierCode != null and request.supplierCode != ''">
AND t.supplier_code ilike concat('%', #{request.supplierCode}, '%')
</if>
<if test="request.supplierName != null and request.supplierName != ''">
AND t.supplier_name ilike concat('%', #{request.supplierName}, '%')
</if>
<if test="request.materialNo != null and request.materialNo != ''">
AND m.material_no ilike concat('%', #{request.materialNo}, '%')
</if>
<if test="request.inspectionItemId != null">
AND r.inspection_item_id = #{request.inspectionItemId}
</if>
</where>
ORDER BY r.id ASC
</select>
</mapper>

View File

@ -88,4 +88,65 @@
ORDER BY t.id DESC
</select>
<select id="todoSearch" resultType="com.nflg.wms.common.pojo.vo.QmsIncomingInspectionTaskVO">
SELECT
t.id,
t.task_no,
t.material_id,
m.material_no,
m.material_desc,
m.drawing_no_ver,
t.inspection_standard_id,
s.version AS standard_version,
t.supplier_code,
t.supplier_name,
t.delivery_order_no,
t.delivery_order_line,
t.purchase_order_no,
t.purchase_order_line,
t.factory,
t.inspection_type,
t.inspection_qty,
t.qualified_qty,
t.unqualified_qty,
t.inspection_status,
t.inspection_result,
t.inspector_id,
t.inspector_name,
t.agent_id,
t.agent_name,
t.submit_time,
t.inspection_start_time,
t.inspection_finish_time,
t.required_finish_time,
t.is_overdue,
t.related_task_no,
t.update_user_id,
t.update_user_name,
t.update_time
FROM qms_incoming_inspection_task t
LEFT JOIN qms_qc_material m ON t.material_id = m.id
LEFT JOIN qms_inspection_standard s ON t.inspection_standard_id = s.id
<where>
t.inspection_status IN (0, 1)
AND (t.inspector_id = #{inspectorId} OR t.agent_id = #{inspectorId})
<if test="request.materialNo != null and request.materialNo != ''">
AND m.material_no ilike concat('%', #{request.materialNo}, '%')
</if>
<if test="request.drawingNo != null and request.drawingNo != ''">
AND m.drawing_no ilike concat('%', #{request.drawingNo}, '%')
</if>
<if test="request.taskNo != null and request.taskNo != ''">
AND t.task_no ilike concat('%', #{request.taskNo}, '%')
</if>
<if test="request.supplierCode != null and request.supplierCode != ''">
AND t.supplier_code ilike concat('%', #{request.supplierCode}, '%')
</if>
<if test="request.supplierName != null and request.supplierName != ''">
AND t.supplier_name ilike concat('%', #{request.supplierName}, '%')
</if>
</where>
ORDER BY t.required_finish_time ASC
</select>
</mapper>

View File

@ -37,7 +37,7 @@
<lombok.version>1.18.38</lombok.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
<hutool-all.version>5.8.36</hutool-all.version>
<hutool-all.version>5.8.40</hutool-all.version>
<sa-token.version>1.42.0</sa-token.version>
<mybatis-plus.version>3.5.12</mybatis-plus.version>
<!-- <mysql-connector.version>8.4.0</mysql-connector.version>-->