refactor(inspection): 优化来料检验任务服务代码结构和逻辑

- 将方法名 IncomingApply 重命名为 incomingApply,遵循驼峰命名规范
- 将方法名 CalculatedAqlType 重命名为 calculatedAqlType,遵循驼峰命名规范
- 修复任务创建时物料ID和检验标准ID设置错误的问题
- 改进AQL查找逻辑,使用orElseThrow替代get避免空指针异常
- 使用检验项目名称而非编码进行匹配,提高准确性
- 修正转办检查中的状态判断逻辑
- 实现事务同步机制确保异步回调在事务提交后执行
- 优化文件上传记录查询,避免N+1查询性能问题
- 移除事务包装确保回调结果更新不会被回滚
- 添加回调结果更新保护机制防止成功状态被覆盖
This commit is contained in:
曹鹏飞 2026-06-13 16:36:04 +08:00
parent e373b39379
commit c30d5e3083
3 changed files with 76 additions and 41 deletions

View File

@ -34,7 +34,7 @@ public class ExternalIncomingInspectionTaskController extends BaseController {
*/ */
@PostMapping("incoming-apply") @PostMapping("incoming-apply")
public ApiResult<Void> IncomingApply(@Valid @RequestBody List<ExternalIncomingInspectionApplyQO> requests) { public ApiResult<Void> IncomingApply(@Valid @RequestBody List<ExternalIncomingInspectionApplyQO> requests) {
incomingInspectionTaskControllerService.IncomingApply(requests); incomingInspectionTaskControllerService.incomingApply(requests);
return ApiResult.success(); return ApiResult.success();
} }

View File

@ -19,6 +19,8 @@ import org.apache.commons.lang3.tuple.Pair;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
@ -125,7 +127,7 @@ public class IncomingInspectionTaskControllerService {
* - 若质检人员设置了转办人则使用转办人代替 * - 若质检人员设置了转办人则使用转办人代替
*/ */
@Transactional @Transactional
public void IncomingApply(List<ExternalIncomingInspectionApplyQO> requests) { public void incomingApply(List<ExternalIncomingInspectionApplyQO> requests) {
for (ExternalIncomingInspectionApplyQO request : requests) { for (ExternalIncomingInspectionApplyQO request : requests) {
applySingle(request); applySingle(request);
} }
@ -163,7 +165,6 @@ public class IncomingInspectionTaskControllerService {
String inspectorName; String inspectorName;
User inspectorUser; User inspectorUser;
if (Objects.nonNull(inspector.getChangeUserId())) { if (Objects.nonNull(inspector.getChangeUserId())) {
// 转办人是 user.id需查询对应的 qms_quality_inspector 记录
QmsQualityInspector agentInspector = qualityInspectorService.getById(inspector.getChangeUserId()); QmsQualityInspector agentInspector = qualityInspectorService.getById(inspector.getChangeUserId());
if (Objects.nonNull(agentInspector)) { if (Objects.nonNull(agentInspector)) {
inspectorId = agentInspector.getId(); inspectorId = agentInspector.getId();
@ -218,7 +219,7 @@ public class IncomingInspectionTaskControllerService {
Long inspectionStandardId = dictionaryItemService.getIdByCode("InspectionStandardTestingMethod", "Sampling"); Long inspectionStandardId = dictionaryItemService.getIdByCode("InspectionStandardTestingMethod", "Sampling");
VUtil.trueThrowBusinessError(Objects.isNull(inspectionStandardId)).throwMessage("检测方式不存在"); VUtil.trueThrowBusinessError(Objects.isNull(inspectionStandardId)).throwMessage("检测方式不存在");
if (Objects.equals(standard.getTestingMethodDictItemId(), inspectionStandardId)) { if (Objects.equals(standard.getTestingMethodDictItemId(), inspectionStandardId)) {
Pair<Long, Short> aqlType = CalculatedAqlType(task, standard Pair<Long, Short> aqlType = calculatedAqlType(task, standard
, dictionaryItemService.getListByDictionaryCode("InspectionStandardSQLType")); , dictionaryItemService.getListByDictionaryCode("InspectionStandardSQLType"));
incomingInspectionTaskAqlRuleService.save(new QmsIncomingInspectionTaskAqlRule() incomingInspectionTaskAqlRuleService.save(new QmsIncomingInspectionTaskAqlRule()
.setTaskId(task.getId()) .setTaskId(task.getId())
@ -357,7 +358,7 @@ public class IncomingInspectionTaskControllerService {
Long inspectionStandardId = dictionaryItemService.getIdByCode("InspectionStandardTestingMethod", "Sampling"); Long inspectionStandardId = dictionaryItemService.getIdByCode("InspectionStandardTestingMethod", "Sampling");
VUtil.trueThrowBusinessError(Objects.isNull(inspectionStandardId)).throwMessage("检测方式不存在"); VUtil.trueThrowBusinessError(Objects.isNull(inspectionStandardId)).throwMessage("检测方式不存在");
if (Objects.equals(standard.getTestingMethodDictItemId(), inspectionStandardId)) { if (Objects.equals(standard.getTestingMethodDictItemId(), inspectionStandardId)) {
Pair<Long, Short> aqlType = CalculatedAqlType(task, standard Pair<Long, Short> aqlType = calculatedAqlType(task, standard
, dictionaryItemService.getListByDictionaryCode("InspectionStandardSQLType")); , dictionaryItemService.getListByDictionaryCode("InspectionStandardSQLType"));
incomingInspectionTaskAqlRuleService.save(new QmsIncomingInspectionTaskAqlRule() incomingInspectionTaskAqlRuleService.save(new QmsIncomingInspectionTaskAqlRule()
.setTaskId(task.getId()) .setTaskId(task.getId())
@ -412,8 +413,8 @@ public class IncomingInspectionTaskControllerService {
QmsIncomingInspectionTask newTask = new QmsIncomingInspectionTask() QmsIncomingInspectionTask newTask = new QmsIncomingInspectionTask()
.setRequestNo(task.getRequestNo()) .setRequestNo(task.getRequestNo())
.setTaskNo(taskNo) .setTaskNo(taskNo)
.setMaterialId(task.getId()) .setMaterialId(task.getMaterialId())
.setInspectionStandardId(task.getId()) .setInspectionStandardId(task.getInspectionStandardId())
.setTestingMethodDictItemId(testingMethodDictItemId) .setTestingMethodDictItemId(testingMethodDictItemId)
.setSupplierCode(task.getSupplierCode()) .setSupplierCode(task.getSupplierCode())
.setSupplierName(task.getSupplierName()) .setSupplierName(task.getSupplierName())
@ -530,14 +531,17 @@ public class IncomingInspectionTaskControllerService {
} }
private DictionaryItem getAql(Long id, List<DictionaryItem> aqls) { private DictionaryItem getAql(Long id, List<DictionaryItem> aqls) {
return aqls.stream().filter(aql -> Objects.equals(aql.getId(), id)).findFirst().get(); return aqls.stream()
.filter(aql -> Objects.equals(aql.getId(), id))
.findFirst()
.orElseThrow(() -> new NflgException(STATE.BusinessError,"未找到AQL"));
} }
private Pair<Long, Short> CalculatedAqlType(QmsIncomingInspectionTask task, QmsInspectionStandard standard private Pair<Long, Short> calculatedAqlType(QmsIncomingInspectionTask task, QmsInspectionStandard standard
, List<DictionaryItem> aqls) { , List<DictionaryItem> aqls) {
DictionaryItem sqlzc = aqls.stream().filter(aql -> StrUtil.equals(aql.getCode(), "正常")).findFirst().get(); DictionaryItem sqlzc = aqls.stream().filter(aql -> StrUtil.equals(aql.getName(), "正常")).findFirst().get();
DictionaryItem sqljy = aqls.stream().filter(aql -> StrUtil.equals(aql.getCode(), "加严")).findFirst().get(); DictionaryItem sqljy = aqls.stream().filter(aql -> StrUtil.equals(aql.getName(), "加严")).findFirst().get();
DictionaryItem sqlfw = aqls.stream().filter(aql -> StrUtil.equals(aql.getCode(), "放宽")).findFirst().get(); DictionaryItem sqlfw = aqls.stream().filter(aql -> StrUtil.equals(aql.getName(), "放宽")).findFirst().get();
log.info("【抽样严格性转移规则计算】检验项严格性为:" + getAql(standard.getAqlTypeDictItemId(), aqls).getName()); log.info("【抽样严格性转移规则计算】检验项严格性为:" + getAql(standard.getAqlTypeDictItemId(), aqls).getName());
List<QmsSupplierInspectionStatistics> statistics = supplierInspectionStatisticsService.lambdaQuery() List<QmsSupplierInspectionStatistics> statistics = supplierInspectionStatisticsService.lambdaQuery()
.eq(QmsSupplierInspectionStatistics::getInspectionStandardId, standard.getId()) .eq(QmsSupplierInspectionStatistics::getInspectionStandardId, standard.getId())
@ -778,7 +782,7 @@ public class IncomingInspectionTaskControllerService {
// 校验是否存在已检任务 // 校验是否存在已检任务
boolean hasFinished = tasks.stream() boolean hasFinished = tasks.stream()
.anyMatch(t -> t.getInspectionStatus() != null && t.getInspectionStatus() == 1); .anyMatch(t -> Objects.equals(t.getInspectionStatus(),(short)2));
VUtil.trueThrowBusinessError(hasFinished) VUtil.trueThrowBusinessError(hasFinished)
.throwMessage("已检状态的任务不允许转办"); .throwMessage("已检状态的任务不允许转办");
@ -1177,7 +1181,18 @@ public class IncomingInspectionTaskControllerService {
updateWrapper.update(); updateWrapper.update();
if (request.getQualified() && task.getUnqualifiedQty() == 0) { if (request.getQualified() && task.getUnqualifiedQty() == 0) {
wmsIncomingInspectionTaskCallbackService.processAsync(task.getId(), (short) 0); // 异步回调需等当前事务提交后再触发否则异步线程可能读到未提交的旧状态导致回调数据错误或漏回调
Long taskId = task.getId();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
wmsIncomingInspectionTaskCallbackService.processAsync(taskId, (short) 0);
}
});
} else {
wmsIncomingInspectionTaskCallbackService.processAsync(taskId, (short) 0);
}
} else { } else {
issueTicketControllerService.initiate(task.getId()); issueTicketControllerService.initiate(task.getId());
} }
@ -1241,10 +1256,33 @@ public class IncomingInspectionTaskControllerService {
.collect(Collectors.groupingBy(QmsIncomingInspectionTaskRecordItemData::getItemId)); .collect(Collectors.groupingBy(QmsIncomingInspectionTaskRecordItemData::getItemId));
} }
// 5. 组装返回VO // 5. 批量查询所有样本数据涉及的文件避免在组装时逐条查询N+1
List<Long> allImageIds = itemDataMap.values().stream()
.flatMap(List::stream)
.map(QmsIncomingInspectionTaskRecordItemData::getImageIds)
.filter(StrUtil::isNotBlank)
.flatMap(ids -> Arrays.stream(StrUtil.splitToLong(ids, ",")).boxed())
.distinct()
.toList();
Map<Long, FileUploadVO> fileMap = Map.of();
if (!allImageIds.isEmpty()) {
fileMap = fileUploadRecordService.lambdaQuery()
.in(FileUploadRecord::getId, allImageIds)
.list()
.stream()
.collect(Collectors.toMap(FileUploadRecord::getId,
file -> new FileUploadVO()
.setId(file.getId())
.setFileName(file.getFileName())
.setUrl(file.getUrl())
));
}
// 6. 组装返回VO
Map<Long, QmsInspectionStandardItemContent> finalContentMap = contentMap; Map<Long, QmsInspectionStandardItemContent> finalContentMap = contentMap;
Map<Long, QmsInspectionStandardItem> finalStandardItemMap = standardItemMap; Map<Long, QmsInspectionStandardItem> finalStandardItemMap = standardItemMap;
Map<Long, List<QmsIncomingInspectionTaskRecordItemData>> finalItemDataMap = itemDataMap; Map<Long, List<QmsIncomingInspectionTaskRecordItemData>> finalItemDataMap = itemDataMap;
Map<Long, FileUploadVO> finalFileMap = fileMap;
return items.stream().map(item -> { return items.stream().map(item -> {
QmsIncomingInspectionTaskRecordItemDetailVO vo = new QmsIncomingInspectionTaskRecordItemDetailVO(); QmsIncomingInspectionTaskRecordItemDetailVO vo = new QmsIncomingInspectionTaskRecordItemDetailVO();
vo.setId(item.getId()); vo.setId(item.getId());
@ -1287,15 +1325,10 @@ public class IncomingInspectionTaskControllerService {
dataVO.setQualified(data.getQualified()); dataVO.setQualified(data.getQualified());
if (StrUtil.isNotBlank(data.getImageIds())) { if (StrUtil.isNotBlank(data.getImageIds())) {
dataVO.setImages( dataVO.setImages(
fileUploadRecordService.lambdaQuery() Arrays.stream(StrUtil.splitToLong(data.getImageIds(), ","))
.in(FileUploadRecord::getId, Arrays.stream(StrUtil.splitToLong(data.getImageIds(), ",")).boxed().toList()) .boxed()
.list() .map(finalFileMap::get)
.stream() .filter(Objects::nonNull)
.map(file -> new FileUploadVO()
.setId(file.getId())
.setFileName(file.getFileName())
.setUrl(file.getUrl())
)
.collect(Collectors.toList()) .collect(Collectors.toList())
); );
} }

View File

@ -101,18 +101,13 @@ public class WmsIncomingInspectionTaskCallbackService {
); );
} }
boolean callbackResult = true; // 注意本方法不可被 @Transactional 包裹否则下面"标记失败"的更新会随异常一起回滚导致失败状态丢失
try { try {
wmsApiService.post(incomingUrl, qo, "来料检验任务回调WMS"); wmsApiService.post(incomingUrl, qo, "来料检验任务回调WMS");
updateCallbackResult(taskVO.getId(), true);
} catch (Exception e) { } catch (Exception e) {
callbackResult = false; updateCallbackResult(taskVO.getId(), false);
throw new NflgException(STATE.BusinessError, "调用WMS接口失败" + e.getMessage()); throw new NflgException(STATE.BusinessError, "调用WMS接口失败" + e.getMessage());
} finally {
incomingInspectionTaskService.lambdaUpdate()
.eq(QmsIncomingInspectionTask::getId, taskVO.getId())
.ne(QmsIncomingInspectionTask::getCallbackResult, true)
.set(QmsIncomingInspectionTask::getCallbackResult, callbackResult)
.update();
} }
} }
@ -149,7 +144,7 @@ public class WmsIncomingInspectionTaskCallbackService {
.toList() .toList()
); );
boolean callbackResult = true; // 注意本方法不可被 @Transactional 包裹否则下面"标记失败"的更新会随异常一起回滚导致失败状态丢失
try { try {
// wmsApiService.post(inventoryUrl, qo, "库存检验任务回调WMS"); // wmsApiService.post(inventoryUrl, qo, "库存检验任务回调WMS");
inventoryService.lambdaUpdate() inventoryService.lambdaUpdate()
@ -160,18 +155,24 @@ public class WmsIncomingInspectionTaskCallbackService {
.eq(WmsInventory::getWarehouseNo, taskVO.getWarehouse()) .eq(WmsInventory::getWarehouseNo, taskVO.getWarehouse())
.eq(WmsInventory::getBinLocation, taskVO.getStorageLocation()) .eq(WmsInventory::getBinLocation, taskVO.getStorageLocation())
.update(); .update();
updateCallbackResult(taskVO.getId(), true);
} catch (Exception e) { } catch (Exception e) {
callbackResult = false; updateCallbackResult(taskVO.getId(), false);
throw new NflgException(STATE.BusinessError, "调用WMS接口失败" + e.getMessage()); throw new NflgException(STATE.BusinessError, "调用WMS接口失败" + e.getMessage());
} finally {
incomingInspectionTaskService.lambdaUpdate()
.eq(QmsIncomingInspectionTask::getId, taskVO.getId())
.ne(QmsIncomingInspectionTask::getCallbackResult, true)
.set(QmsIncomingInspectionTask::getCallbackResult, callbackResult)
.update();
} }
} }
/**
* 更新回调结果标记仅当原结果非成功时才更新避免覆盖已成功的状态
*/
private void updateCallbackResult(Long taskId, boolean callbackResult) {
incomingInspectionTaskService.lambdaUpdate()
.eq(QmsIncomingInspectionTask::getId, taskId)
.ne(QmsIncomingInspectionTask::getCallbackResult, true)
.set(QmsIncomingInspectionTask::getCallbackResult, callbackResult)
.update();
}
/** /**
* WMS系统来料检验任务回调 * WMS系统来料检验任务回调
* @param taskId 来料检验任务ID * @param taskId 来料检验任务ID
@ -189,7 +190,7 @@ public class WmsIncomingInspectionTaskCallbackService {
public void process(Long taskId) { public void process(Long taskId) {
QmsIncomingInspectionTaskVO taskVO = incomingInspectionTaskService.getDetail(taskId); QmsIncomingInspectionTaskVO taskVO = incomingInspectionTaskService.getDetail(taskId);
VUtil.trueThrowBusinessError(Objects.equals(taskVO.getCallbackResult(), true)).throwMessage("请勿重复回调"); VUtil.trueThrowBusinessError(Objects.equals(taskVO.getCallbackResult(), true)).throwMessage("请勿重复回调");
VUtil.trueThrowBusinessError(taskVO.getInspectionStatus() != 2).throwMessage("来料检验任务状态不允许回调"); VUtil.trueThrowBusinessError(!Objects.equals(taskVO.getInspectionStatus(),(short)2)).throwMessage("来料检验任务状态不允许回调");
if (taskVO.getInspectionResult()) { if (taskVO.getInspectionResult()) {
process(taskVO, (short) 0); process(taskVO, (short) 0);
} else { } else {
@ -231,6 +232,7 @@ public class WmsIncomingInspectionTaskCallbackService {
private void process(Long taskId, Short processingResult) { private void process(Long taskId, Short processingResult) {
QmsIncomingInspectionTaskVO taskVO = incomingInspectionTaskService.getDetail(taskId); QmsIncomingInspectionTaskVO taskVO = incomingInspectionTaskService.getDetail(taskId);
VUtil.trueThrowBusinessError(Objects.equals(taskVO.getCallbackResult(), true)).throwMessage("请勿重复回调"); VUtil.trueThrowBusinessError(Objects.equals(taskVO.getCallbackResult(), true)).throwMessage("请勿重复回调");
VUtil.trueThrowBusinessError(!Objects.equals(taskVO.getInspectionStatus(),(short)2)).throwMessage("来料检验任务状态不允许回调");
process(taskVO, processingResult); process(taskVO, processingResult);
} }
} }