liu
2026-10-23 962f78c8383e7c884ddb08c951c15e5ba6eb4cb8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskResultServiceImpl.java
@@ -15,15 +15,17 @@
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_LINE_ALREADY_TAKEN;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_LINE_NOT_MATCH;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_RESULT_NOT_EXISTS;
/**
 * MES 盘点结果 Service 实现类
 *
 * @author 芋道源码
 * @author 超级管理员
 */
@Service
@Validated
@@ -51,8 +53,9 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createStockTakingTaskResult(MesWmStockTakingTaskResultSaveReqVO createReqVO) {
        // 1. 校验任务处于盘点中状态
        // 1. 校验任务处于盘点中状态,且结果审批已提交、未审核时禁止写入
        stockTakingTaskService.validateStockTakingTaskExistsAndApproving(createReqVO.getTaskId());
        stockTakingTaskService.validateResultApprovalNotPending(createReqVO.getTaskId());
        // 2. 确定 lineId 和账面数量
        Long lineId = createReqVO.getLineId();
@@ -70,10 +73,16 @@
        } else {
            // 2.3 如果传递了 lineId,从 line 中获取 quantity
            existingLine = stockTakingTaskLineService.validateStockTakingTaskLineExists(lineId);
            // 2.4 防止串单:盘点行必须属于请求指定的盘点任务
            if (ObjUtil.notEqual(existingLine.getTaskId(), createReqVO.getTaskId())) {
                throw exception(WM_STOCK_TAKING_TASK_LINE_NOT_MATCH);
            }
        }
        if (existingLine != null
                && existingLine.getTakingQuantity() != null
                && existingLine.getTakingQuantity().compareTo(BigDecimal.ZERO) > 0) {
        // 2.5 防止重复:同一盘点任务行只允许存在一条盘点结果(无论实盘数量是否为 0)
        Long finalLineId = lineId;
        boolean resultExists = stockTakingTaskResultMapper.selectListByTaskId(createReqVO.getTaskId()).stream()
                .anyMatch(result -> Objects.equals(result.getLineId(), finalLineId));
        if (resultExists) {
            throw exception(WM_STOCK_TAKING_TASK_LINE_ALREADY_TAKEN);
        }
        BigDecimal quantity = existingLine != null ? existingLine.getQuantity() : BigDecimal.ZERO; // 账面数量
@@ -94,8 +103,9 @@
        updateReqVO.setLineId(null); // lineId 不能修改,避免误操作
        // 1.1 校验记录存在
        MesWmStockTakingTaskResultDO oldResult = validateStockTakingTaskResultExists(updateReqVO.getId());
        // 1.2 校验任务处于盘点中状态
        // 1.2 校验任务处于盘点中状态,且结果审批已提交、未审核时禁止修改
        stockTakingTaskService.validateStockTakingTaskExistsAndApproving(oldResult.getTaskId());
        stockTakingTaskService.validateResultApprovalNotPending(oldResult.getTaskId());
        // 2. 更新 result 记录
        MesWmStockTakingTaskResultDO result = BeanUtils.toBean(updateReqVO, MesWmStockTakingTaskResultDO.class);
@@ -111,15 +121,21 @@
    public void deleteStockTakingTaskResult(Long id) {
        // 1.1 校验 result 是否存在
        MesWmStockTakingTaskResultDO result = validateStockTakingTaskResultExists(id);
        // 1.2 校验 task 是否处于 APPROVING 状态
        // 1.2 校验 task 是否处于 APPROVING 状态,且结果审批已提交、未审核时禁止删除
        stockTakingTaskService.validateStockTakingTaskExistsAndApproving(result.getTaskId());
        stockTakingTaskService.validateResultApprovalNotPending(result.getTaskId());
        // 2. 删除 result 记录
        stockTakingTaskResultMapper.deleteById(id);
        // 3. 更新对应 line 的盘点数量和状态
        // 3. 按剩余盘点结果重算对应 line 的实盘数量(无剩余结果时置 0),避免覆盖成负数
        BigDecimal remainingTakingQuantity = stockTakingTaskResultMapper.selectListByTaskId(result.getTaskId()).stream()
                .filter(item -> Objects.equals(item.getLineId(), result.getLineId()))
                .map(MesWmStockTakingTaskResultDO::getTakingQuantity)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        stockTakingTaskLineService.updateStockTakingTaskLineTakingQuantity(
                result.getLineId(), result.getTakingQuantity().negate());
                result.getLineId(), remainingTakingQuantity);
    }
    @Override
@@ -132,6 +148,29 @@
        return stockTakingTaskResultMapper.selectListByTaskId(taskId);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upsertResultForImport(MesWmStockTakingTaskLineDO line, BigDecimal takingQuantity) {
        // 1. 查询该任务下是否已存在该行的盘点结果
        MesWmStockTakingTaskResultDO existing = stockTakingTaskResultMapper.selectListByTaskId(line.getTaskId()).stream()
                .filter(result -> Objects.equals(result.getLineId(), line.getId()))
                .findFirst().orElse(null);
        if (existing != null) {
            // 2. 已存在:覆盖实盘数量(重复导入以最后一次为准)
            existing.setTakingQuantity(takingQuantity);
            stockTakingTaskResultMapper.updateById(existing);
            return;
        }
        // 3. 不存在:按盘点行维度新建,账面数量取行账面数量,保证核销差额口径一致
        MesWmStockTakingTaskResultDO result = MesWmStockTakingTaskResultDO.builder()
                .taskId(line.getTaskId()).lineId(line.getId()).materialStockId(line.getMaterialStockId())
                .itemId(line.getItemId()).batchId(line.getBatchId()).batchCode(line.getBatchCode())
                .warehouseId(line.getWarehouseId()).locationId(line.getLocationId()).areaId(line.getAreaId())
                .quantity(line.getQuantity()).takingQuantity(takingQuantity)
                .build();
        stockTakingTaskResultMapper.insert(result);
    }
    /**
     * 校验盘点结果是否存在
     *