| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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) |
| | |
| | | // 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); |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |