3 天以前 b852254d90e7d1955db31db154193ec8ee84d8b3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskLineServiceImpl.java
@@ -7,6 +7,8 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.line.MesWmStockTakingTaskLinePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.line.MesWmStockTakingTaskLineSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.line.MesWmStockTakingTaskLineImportExcelVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.line.MesWmStockTakingTaskLineImportRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.result.MesWmStockTakingTaskResultSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.plan.MesWmStockTakingPlanParamDO;
@@ -19,6 +21,7 @@
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
import cn.iocoder.yudao.module.mes.service.wm.stocktaking.plan.MesWmStockTakingPlanParamService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -50,6 +53,12 @@
    private MesWmMaterialStockService materialStockService;
    @Resource
    private MesWmStockTakingTaskService stockTakingTaskService;
    // 与 ResultService 相互引用(ResultServiceImpl 已注入 LineService),须用 @Lazy 打破循环
    @Lazy
    @Resource
    private MesWmStockTakingTaskResultService stockTakingTaskResultService;
    @Resource
    private cn.iocoder.yudao.module.mdm.api.item.MdmItemApi mdmItemApi;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -70,7 +79,8 @@
        // 3. 批量生成明细行
        List<MesWmStockTakingTaskLineDO> lines = convertList(stocks, stock -> MesWmStockTakingTaskLineDO.builder()
                .taskId(task.getId()).materialStockId(stock.getId()).itemId(stock.getItemId())
                .batchId(stock.getBatchId()).quantity(stock.getQuantity()).takingQuantity(BigDecimal.ZERO)
                .batchId(stock.getBatchId()).batchCode(stock.getBatchCode())
                .quantity(stock.getQuantity()).takingQuantity(BigDecimal.ZERO)
                .warehouseId(stock.getWarehouseId()).locationId(stock.getLocationId()).areaId(stock.getAreaId())
                .status(MesWmStockTakingTaskLineStatusEnum.LOSS.getStatus()).build());
        stockTakingTaskLineMapper.insertBatch(lines);
@@ -230,4 +240,62 @@
        return param != null ? param.getValueId() : null;
    }
    @Override
    public MesWmStockTakingTaskLineImportRespVO importTakingQuantity(Long taskId,
                                                                    List<MesWmStockTakingTaskLineImportExcelVO> list) {
        MesWmStockTakingTaskLineImportRespVO respVO = new MesWmStockTakingTaskLineImportRespVO();
        respVO.setSuccessCount(0);
        respVO.setFailureCount(0);
        respVO.setFailureMessages(new java.util.ArrayList<>());
        if (CollUtil.isEmpty(list)) {
            return respVO;
        }
        // 0. 校验盘点任务处于盘点中状态(与人工录入盘点结果口径一致,仅盘点中可导入)
        stockTakingTaskService.validateStockTakingTaskExistsAndApproving(taskId);
        // 1. 获取盘点任务行
        List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineMapper.selectListByTaskId(taskId);
        if (CollUtil.isEmpty(lines)) {
            throw exception(cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_LINE_NOT_EXISTS);
        }
        // 2. 构建 物料编码 -> 物料ID 映射
        java.util.Set<Long> itemIds = lines.stream().map(MesWmStockTakingTaskLineDO::getItemId)
                .filter(Objects::nonNull).collect(java.util.stream.Collectors.toSet());
        java.util.Map<Long, cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO> itemMap =
                mdmItemApi.getItemMap(itemIds);
        java.util.Map<String, Long> codeToItemIdMap = new java.util.HashMap<>();
        itemMap.values().forEach(item -> {
            if (item.getCode() != null) {
                codeToItemIdMap.put(item.getCode(), item.getId());
            }
        });
        // 3. 逐行匹配并写入实盘数量
        for (MesWmStockTakingTaskLineImportExcelVO row : list) {
            Long itemId = codeToItemIdMap.get(row.getItemCode());
            if (itemId == null) {
                respVO.setFailureCount(respVO.getFailureCount() + 1);
                respVO.getFailureMessages().add("物料编码不存在: " + row.getItemCode());
                continue;
            }
            MesWmStockTakingTaskLineDO matched = lines.stream()
                    .filter(line -> Objects.equals(line.getItemId(), itemId)
                            && Objects.equals(line.getBatchCode(), row.getBatchCode()))
                    .findFirst().orElse(null);
            if (matched == null) {
                respVO.setFailureCount(respVO.getFailureCount() + 1);
                respVO.getFailureMessages().add("未找到对应盘点行: 物料=" + row.getItemCode() + " 批次=" + row.getBatchCode());
                continue;
            }
            if (row.getTakingQuantity() == null) {
                respVO.setFailureCount(respVO.getFailureCount() + 1);
                respVO.getFailureMessages().add("实盘数量为空: 物料=" + row.getItemCode());
                continue;
            }
            updateStockTakingTaskLineTakingQuantity(matched.getId(), row.getTakingQuantity());
            // 同步写盘点结果,保证差异核销来源(task_result)一致
            stockTakingTaskResultService.upsertResultForImport(matched, row.getTakingQuantity());
            respVO.setSuccessCount(respVO.getSuccessCount() + 1);
        }
        return respVO;
    }
}