diff --git a/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/IncomingInspectionTaskControllerService.java b/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/IncomingInspectionTaskControllerService.java index 4cf8034d..12d8d27e 100644 --- a/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/IncomingInspectionTaskControllerService.java +++ b/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/IncomingInspectionTaskControllerService.java @@ -1085,4 +1085,8 @@ public class IncomingInspectionTaskControllerService { public List getUnqualifiedRecordItems(Long taskId) { return incomingInspectionTaskRecordItemService.getUnqualifiedRecordItems(taskId); } + + public List getUnqualifiedRecordItemDataImages(Long taskId) { + return incomingInspectionTaskRecordItemService.getUnqualifiedRecordItemDataImages(taskId); + } } diff --git a/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/QmsIssueTicketControllerService.java b/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/QmsIssueTicketControllerService.java index bcd98274..b34405f3 100644 --- a/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/QmsIssueTicketControllerService.java +++ b/nflg-qms-admin/src/main/java/com/nflg/qms/admin/service/QmsIssueTicketControllerService.java @@ -172,7 +172,9 @@ public class QmsIssueTicketControllerService { + "\n" ); }); - + List images = incomingInspectionTaskControllerService.getUnqualifiedRecordItemDataImages(taskId); + images.removeIf(StrUtil::isBlank); + entity.setImageIds(StrUtil.join(",", images)); issueTicketService.save(entity); // 添加待办 @@ -183,13 +185,13 @@ public class QmsIssueTicketControllerService { .list(); List todoItems = users.stream().map(user -> new QmsTodoItem() .setCode(basdeSerialNumberControllerService.generateSerialNumber(32)) - .setSourceTypeId(dictionaryItemService.getIdByCode("MessageType","IncomingMaterialInspectionApproval")) + .setSourceTypeId(dictionaryItemService.getIdByCode("MessageType", "IncomingMaterialInspectionApproval")) .setSourceId(entity.getId()) .setCreateUserId(user.getId()) .setCreateUserName(user.getUserName()) .setCreateTime(LocalDateTime.now()) ).toList(); - if (CollectionUtil.isNotEmpty(todoItems)){ + if (CollectionUtil.isNotEmpty(todoItems)) { todoItemService.saveBatch(todoItems); } } diff --git a/nflg-qms-admin/src/test/java/com/nflg/qms/admin/ExternalInventoryInspectionApplyApiTest.java b/nflg-qms-admin/src/test/java/com/nflg/qms/admin/ExternalInventoryInspectionApplyApiTest.java new file mode 100644 index 00000000..6ab88957 --- /dev/null +++ b/nflg-qms-admin/src/test/java/com/nflg/qms/admin/ExternalInventoryInspectionApplyApiTest.java @@ -0,0 +1,382 @@ +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.qo.ExternalInventoryInspectionApplyQO; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +/** + * 对外接口-库存检测申请 接口测试 + *

+ * 测试前提: + * 1. qms-admin 服务已启动(默认 http://localhost:8105) + * 2. 测试账号已登录,将有效的 token 填入 TOKEN 常量 + * 3. 数据库中已存在物料编号为 VALID_MATERIAL_NO 的质检物料,且该物料有对应的已发布检验标准 + * 4. 该物料(或其所属物料类别层级)已绑定 IQE 质检人员(inspection_type = 1) + *

+ */ +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class ExternalInventoryInspectionApplyApiTest { + + // ===================== 配置区 ===================== + /** 服务地址 */ + private static final String BASE_URL = "http://localhost:8105"; + /** 当前登录用户的 token(需手动配置) */ + private static final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjEsInJuU3RyIjoidVFwSWM2R3RJeUoxcFNSczBadzJzb1hvMUZLZXB3czkiLCJuYW1lIjoi6LaF57qn566h55CG5ZGYIiwiY29kZSI6ImFkbWluIiwicm9sZXMiOlsiU3VwZXJBZG1pbiJdLCJ0eXBlIjoxfQ.FtQ2uVwvuxsjAFbXnB006hV1pODtRhZT0z_9nfuR0So"; + /** 有效的物料编号(数据库中已存在,且有已发布检验标准和绑定的IQE) */ + private static final String VALID_MATERIAL_NO = "2200052100"; + /** 有效的所属工厂 */ + private static final String VALID_FACTORY = "1010"; + /** 有效的所属仓库 */ + private static final String VALID_WAREHOUSE = "0007"; + /** 有效的所属储位 */ + private static final String VALID_STORAGE_LOCATION = "SL01"; + /** 有效的存储时长(天) */ + private static final int VALID_STORAGE_DAYS = 30; + // ===================== 配置区结束 ===================== + + private static final String API_PATH = "/external/incoming-inspection-task/inventory-apply"; + + // ==================== HTTP 工具方法 ==================== + + private static ApiResult post(String path, Object body, TypeReference> typeRef) { + String url = BASE_URL + path; + String reqBody = body == null ? "" : JSONUtil.toJsonStr(body); + HttpResponse resp = HttpRequest.post(url) + .header("authorization", TOKEN) + .header("Content-Type", "application/json") + .body(reqBody) + .execute(); + String raw = resp.body(); + System.out.println("[POST] " + path); + System.out.println(" 请求: " + reqBody); + System.out.println(" 响应: " + raw); + return JSONUtil.toBean(raw, typeRef, false); + } + + private static void assertSuccess(ApiResult 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. 能正常分配到质检人员 + * 4. 任务 dataType=1, inspectionType=1 + */ + @Test + @Order(1) + public void test01_inventoryApply_Success() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertSuccess(result, "库存检测申请失败"); + System.out.println(" ✅ 库存检测申请成功"); + } + + /** + * 【库存检测申请】最小检验数量(inspectionQty=1) + * 验证点:边界值最小合法检验数量 + */ + @Test + @Order(2) + public void test02_inventoryApply_MinInspectionQty() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setInspectionQty(1); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertSuccess(result, "最小检验数量库存检测申请失败"); + System.out.println(" ✅ 最小检验数量库存检测申请成功"); + } + + /** + * 【库存检测申请】最小存储时长(storageDays=1) + * 验证点:边界值最小合法存储时长 + */ + @Test + @Order(3) + public void test03_inventoryApply_MinStorageDays() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setStorageDays(1); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertSuccess(result, "最小存储时长库存检测申请失败"); + System.out.println(" ✅ 最小存储时长库存检测申请成功"); + } + + /** + * 【库存检测申请】大数量检验(inspectionQty=99999) + * 验证点:大数量时能正常处理 + */ + @Test + @Order(4) + public void test04_inventoryApply_LargeInspectionQty() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setInspectionQty(99999); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertSuccess(result, "大数量检验库存检测申请失败"); + System.out.println(" ✅ 大数量检验库存检测申请成功"); + } + + // ==================== 参数校验异常测试 ==================== + + /** + * 【库存检测申请】物料编号为空 + * 验证点:@NotBlank 校验,接口返回参数校验错误 + */ + @Test + @Order(10) + public void test10_inventoryApply_MaterialNoBlank() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setMaterialNo(null); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "物料编号为空应返回失败"); + System.out.println(" ✅ 物料编号为空校验通过"); + } + + /** + * 【库存检测申请】物料编号为空字符串 + * 验证点:@NotBlank 校验,空字符串也应返回失败 + */ + @Test + @Order(11) + public void test11_inventoryApply_MaterialNoEmpty() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setMaterialNo(""); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "物料编号为空字符串应返回失败"); + System.out.println(" ✅ 物料编号为空字符串校验通过"); + } + + /** + * 【库存检测申请】所属工厂为空 + * 验证点:@NotBlank 校验,接口返回参数校验错误 + */ + @Test + @Order(12) + public void test12_inventoryApply_FactoryBlank() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setFactory(null); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "所属工厂为空应返回失败"); + System.out.println(" ✅ 所属工厂为空校验通过"); + } + + /** + * 【库存检测申请】检验数量为空 + * 验证点:@NotNull 校验,接口返回参数校验错误 + */ + @Test + @Order(13) + public void test13_inventoryApply_InspectionQtyNull() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setInspectionQty(null); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "检验数量为空应返回失败"); + System.out.println(" ✅ 检验数量为空校验通过"); + } + + /** + * 【库存检测申请】检验数量为零 + * 验证点:@Min(1) 校验,检验数量必须大于0 + */ + @Test + @Order(14) + public void test14_inventoryApply_InspectionQtyZero() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setInspectionQty(0); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "检验数量为零应返回失败"); + System.out.println(" ✅ 检验数量为零校验通过"); + } + + /** + * 【库存检测申请】检验数量为负数 + * 验证点:@Min(1) 校验,负数应返回失败 + */ + @Test + @Order(15) + public void test15_inventoryApply_InspectionQtyNegative() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setInspectionQty(-1); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "检验数量为负数应返回失败"); + System.out.println(" ✅ 检验数量为负数校验通过"); + } + + /** + * 【库存检测申请】所属仓库为空 + * 验证点:@NotBlank 校验,库存检测必填仓库 + */ + @Test + @Order(16) + public void test16_inventoryApply_WarehouseBlank() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setWarehouse(null); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "所属仓库为空应返回失败"); + System.out.println(" ✅ 所属仓库为空校验通过"); + } + + /** + * 【库存检测申请】所属储位为空 + * 验证点:@NotBlank 校验,库存检测必填储位 + */ + @Test + @Order(17) + public void test17_inventoryApply_StorageLocationBlank() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setStorageLocation(null); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "所属储位为空应返回失败"); + System.out.println(" ✅ 所属储位为空校验通过"); + } + + /** + * 【库存检测申请】存储时长为空 + * 验证点:@NotNull 校验,库存检测必填存储时长 + */ + @Test + @Order(18) + public void test18_inventoryApply_StorageDaysNull() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setStorageDays(null); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "存储时长为空应返回失败"); + System.out.println(" ✅ 存储时长为空校验通过"); + } + + /** + * 【库存检测申请】存储时长为零 + * 验证点:@Min(1) 校验,存储时长必须大于0 + */ + @Test + @Order(19) + public void test19_inventoryApply_StorageDaysZero() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setStorageDays(0); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "存储时长为零应返回失败"); + System.out.println(" ✅ 存储时长为零校验通过"); + } + + /** + * 【库存检测申请】存储时长为负数 + * 验证点:@Min(1) 校验,负数应返回失败 + */ + @Test + @Order(20) + public void test20_inventoryApply_StorageDaysNegative() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setStorageDays(-5); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "存储时长为负数应返回失败"); + System.out.println(" ✅ 存储时长为负数校验通过"); + } + + // ==================== 业务校验异常测试 ==================== + + /** + * 【库存检测申请】物料编号不存在 + * 验证点:接口返回业务错误(物料编号不存在于质检物料表中) + */ + @Test + @Order(30) + public void test30_inventoryApply_MaterialNotExist() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setMaterialNo("NOT_EXIST_MATERIAL_999"); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "物料编号不存在应返回失败"); + System.out.println(" ✅ 物料编号不存在校验通过"); + } + + /** + * 【库存检测申请】物料存在但无对应的检验标准 + * 验证点:接口返回业务错误(该物料不存在对应的检验标准) + * 注意:需要一个存在于质检物料表但没有已发布检验标准的物料编号 + */ + @Test + @Order(31) + public void test31_inventoryApply_NoInspectionStandard() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setMaterialNo("MATERIAL_NO_STANDARD_999"); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "物料无检验标准应返回失败"); + System.out.println(" ✅ 物料无检验标准校验通过"); + } + + /** + * 【库存检测申请】物料及标准均存在但无绑定的质检人员 + * 验证点:接口返回业务错误(该物料未绑定质检人员,无法自动分配) + * 注意:需要一个有物料和标准但物料/类别层级均未绑定IQE的物料编号 + */ + @Test + @Order(32) + public void test32_inventoryApply_NoInspectorBound() { + ExternalInventoryInspectionApplyQO request = buildValidRequest(); + request.setMaterialNo("MATERIAL_NO_INSPECTOR_999"); + + ApiResult result = post(API_PATH, request, new TypeReference<>() {}); + assertFailed(result, "物料未绑定质检人员应返回失败"); + System.out.println(" ✅ 物料未绑定质检人员校验通过"); + } + + /** + * 【库存检测申请】请求体为空 + * 验证点:传入空 body 时接口返回失败 + */ + @Test + @Order(33) + public void test33_inventoryApply_EmptyBody() { + ApiResult result = post(API_PATH, null, new TypeReference<>() {}); + assertFailed(result, "空请求体应返回失败"); + System.out.println(" ✅ 空请求体校验通过"); + } + + // ==================== 辅助方法 ==================== + + /** + * 构建一个有效的库存检测申请请求参数(所有必填字段) + */ + private ExternalInventoryInspectionApplyQO buildValidRequest() { + ExternalInventoryInspectionApplyQO request = new ExternalInventoryInspectionApplyQO(); + request.setMaterialNo(VALID_MATERIAL_NO); + request.setFactory(VALID_FACTORY); + request.setInspectionQty(100); + request.setWarehouse(VALID_WAREHOUSE); + request.setStorageLocation(VALID_STORAGE_LOCATION); + request.setStorageDays(VALID_STORAGE_DAYS); + return request; + } +} diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/QmsIncomingInspectionTaskRecordItemMapper.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/QmsIncomingInspectionTaskRecordItemMapper.java index b7a9b1a8..5b492497 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/QmsIncomingInspectionTaskRecordItemMapper.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/QmsIncomingInspectionTaskRecordItemMapper.java @@ -20,4 +20,6 @@ public interface QmsIncomingInspectionTaskRecordItemMapper extends BaseMapper getNonconformanceDataGroups(Long recordId); List getUnqualifiedRecordItems(Long taskId); + + List getUnqualifiedRecordItemDataImages(Long taskId); } diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IQmsIncomingInspectionTaskRecordItemService.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IQmsIncomingInspectionTaskRecordItemService.java index 4649d9bf..9df4955e 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IQmsIncomingInspectionTaskRecordItemService.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IQmsIncomingInspectionTaskRecordItemService.java @@ -20,4 +20,6 @@ public interface IQmsIncomingInspectionTaskRecordItemService extends IService getNonconformanceDataGroups(Long recordId); List getUnqualifiedRecordItems(Long taskId); + + List getUnqualifiedRecordItemDataImages(Long taskId); } diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/QmsIncomingInspectionTaskRecordItemServiceImpl.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/QmsIncomingInspectionTaskRecordItemServiceImpl.java index 707b496f..13fe69ea 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/QmsIncomingInspectionTaskRecordItemServiceImpl.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/QmsIncomingInspectionTaskRecordItemServiceImpl.java @@ -21,6 +21,7 @@ import java.util.List; @Service public class QmsIncomingInspectionTaskRecordItemServiceImpl extends ServiceImpl implements IQmsIncomingInspectionTaskRecordItemService { + @Override public List getNonconformanceDataGroups(Long recordId) { return baseMapper.getNonconformanceDataGroups(recordId); @@ -30,4 +31,9 @@ public class QmsIncomingInspectionTaskRecordItemServiceImpl extends ServiceImpl< public List getUnqualifiedRecordItems(Long taskId) { return baseMapper.getUnqualifiedRecordItems(taskId); } + + @Override + public List getUnqualifiedRecordItemDataImages(Long taskId) { + return baseMapper.getUnqualifiedRecordItemDataImages(taskId); + } } diff --git a/nflg-wms-repository/src/main/resources/mapper/QmsIncomingInspectionTaskRecordItemMapper.xml b/nflg-wms-repository/src/main/resources/mapper/QmsIncomingInspectionTaskRecordItemMapper.xml index 03b4e1bb..a57b2ca4 100644 --- a/nflg-wms-repository/src/main/resources/mapper/QmsIncomingInspectionTaskRecordItemMapper.xml +++ b/nflg-wms-repository/src/main/resources/mapper/QmsIncomingInspectionTaskRecordItemMapper.xml @@ -17,6 +17,16 @@ INNER JOIN qms_incoming_inspection_task_record_item iitri ON iitr."id"=iitri.record_id INNER JOIN qms_inspection_standard_item_content isic ON isic."id"=iitri.inspection_standard_item_content_id INNER JOIN qms_inspection_standard_item isi ON isic.inspection_standard_item_id=isi."id" - WHERE iitr.task_id=#{taskId} + WHERE iitr.task_id=#{taskId} and iitri.unqualified_qty>0 + + +