package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.framework.web.domain.R; import com.ruoyi.production.mapper.*; import com.ruoyi.production.util.TaskPlanQuantityUtil; import com.ruoyi.technology.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductionOrderRoutingOperationService; import com.ruoyi.production.service.ProductionProductMainService; import com.ruoyi.technology.pojo.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; @Service @Transactional(rollbackFor = Exception.class) @RequiredArgsConstructor public class ProductionOrderRoutingOperationServiceImpl extends ServiceImpl implements ProductionOrderRoutingOperationService { private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper; private final ProductionOperationTaskMapper productionOperationTaskMapper; private final ProductionProductMainMapper productionProductMainMapper; private final ProductionProductMainService productionProductMainService; private final TechnologyOperationParamMapper technologyOperationParamMapper; private final TechnologyParamMapper technologyParamMapper; private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper; private final ProductionOrderMapper productionOrderMapper; private final ProductionOrderRoutingMapper productionOrderRoutingMapper; private final ProductionOrderBomMapper productionOrderBomMapper; private final ProductionBomStructureMapper productionBomStructureMapper; private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper; @Override public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) { // 新增工艺路线 int insert = productionOrderRoutingOperationMapper.insert(productionOrderRoutingOperation); //工序关联的参数需要同步新增 List technologyOperationParams = technologyOperationParamMapper.selectList(Wrappers.lambdaQuery() .eq(TechnologyOperationParam::getTechnologyOperationId, productionOrderRoutingOperation.getTechnologyOperationId())); // 参数与前置条件校验 if (CollectionUtils.isNotEmpty(technologyOperationParams)){ ArrayList productionOrderRoutingOperationParams = new ArrayList<>(); // 遍历处理数据并组装结果 for (TechnologyOperationParam technologyOperationParam : technologyOperationParams) { TechnologyParam technologyParam = technologyParamMapper.selectById(technologyOperationParam.getTechnologyParamId()); ProductionOrderRoutingOperationParam productionOrderRoutingOperationParam = new ProductionOrderRoutingOperationParam(); productionOrderRoutingOperationParam.setProductionOrderId(productionOrderRoutingOperation.getProductionOrderId()); productionOrderRoutingOperationParam.setProductionOrderRoutingOperationId(productionOrderRoutingOperation.getId()); productionOrderRoutingOperationParam.setParamCode(technologyParam.getParamCode()); productionOrderRoutingOperationParam.setParamName(technologyParam.getParamName()); productionOrderRoutingOperationParam.setParamType(technologyParam.getParamType()); productionOrderRoutingOperationParam.setParamFormat(technologyParam.getParamFormat()); productionOrderRoutingOperationParam.setUnit(technologyParam.getUnit()); productionOrderRoutingOperationParam.setIsRequired(technologyParam.getIsRequired()); productionOrderRoutingOperationParam.setRemark(technologyParam.getRemark()); productionOrderRoutingOperationParam.setParamId(technologyParam.getId()); productionOrderRoutingOperationParam.setTechnologyOperationId(productionOrderRoutingOperation.getTechnologyOperationId()); productionOrderRoutingOperationParams.add(productionOrderRoutingOperationParam); } productionOrderRoutingOperationParamMapper.insert(productionOrderRoutingOperationParams); } String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); if (insert > 0) { ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne( Wrappers.lambdaQuery() .likeRight(ProductionOperationTask::getWorkOrderNo, "GD" + datePrefix) .orderByDesc(ProductionOperationTask::getWorkOrderNo) .last("limit 1")); int sequenceNumber = 1; if (lastTask != null && lastTask.getWorkOrderNo() != null) { String lastNo = lastTask.getWorkOrderNo(); if (lastNo.startsWith("GD" + datePrefix)) { String seqStr = lastNo.substring(("GD" + datePrefix).length()); try { sequenceNumber = Integer.parseInt(seqStr) + 1; } catch (NumberFormatException e) { sequenceNumber = 1; } } } String workOrderNoStr = "GD" + String.format("%s%03d", datePrefix, sequenceNumber); ProductionOperationTask productionOperationTask = new ProductionOperationTask(); productionOperationTask.setProductionOrderRoutingOperationId(productionOrderRoutingOperation.getId()); productionOperationTask.setProductionOrderId(productionOrderRoutingOperation.getProductionOrderId()); productionOperationTask.setPlanQuantity(BigDecimal.ZERO); productionOperationTask.setCompleteQuantity(BigDecimal.ZERO); productionOperationTask.setWorkOrderNo(workOrderNoStr); productionOperationTask.setStatus(1); productionOperationTaskMapper.insert(productionOperationTask); } return R.ok(); } @Override @Transactional(rollbackFor = Exception.class) public R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) { Long operationId = productionOrderRoutingOperation.getId(); // 更新工艺路线工序 productionOrderRoutingOperationMapper.updateById(productionOrderRoutingOperation); // 重新查询完整记录(前端可能没有传递所有字段,如 productionOrderId) ProductionOrderRoutingOperation updatedOperation = productionOrderRoutingOperationMapper.selectById(operationId); if (updatedOperation == null) { throw new ServiceException("工艺路线工序不存在"); } // 查询是否存在工单 ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne( new LambdaQueryWrapper() .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, operationId) .last("limit 1")); // 根据是否需要生产进行处理 Boolean isProduction = updatedOperation.getIsProduction(); if (Boolean.TRUE.equals(isProduction)) { // 需要生产:检查工单是否存在,不存在则生成 if (productionOperationTask == null) { ProductionOperationTask task = new ProductionOperationTask(); task.setProductionOrderRoutingOperationId(updatedOperation.getId()); task.setProductionOrderId(updatedOperation.getProductionOrderId()); // 获取生产订单 ProductionOrder productionOrder = productionOrderMapper.selectById(updatedOperation.getProductionOrderId()); if (productionOrder == null) { throw new ServiceException("生产订单不存在"); } // 获取订单BOM ProductionOrderBom orderBom = productionOrderBomMapper.selectOne( Wrappers.lambdaQuery() .eq(ProductionOrderBom::getProductionOrderId, productionOrder.getId())); // 确定根产品规格ID Long rootProductModelId = orderBom != null && orderBom.getProductModelId() != null ? orderBom.getProductModelId() : productionOrder.getProductModelId(); // 获取BOM结构列表 List orderBomStructureList = orderBom == null || orderBom.getId() == null ? Collections.emptyList() : productionBomStructureMapper.selectList( Wrappers.lambdaQuery() .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId()) .orderByAsc(ProductionBomStructure::getId)); // 构建工序需求量映射 Map operationDemandedQuantityMap = TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(orderBomStructureList, rootProductModelId); // 获取工艺路线工序(用于计算计划数量) TechnologyRoutingOperation sourceOperation = technologyRoutingOperationMapper.selectById( updatedOperation.getTechnologyRoutingOperationId()); // 将原来的私有方法替换为调用工具类 BigDecimal planQuantity = TaskPlanQuantityUtil.resolveTaskPlanQuantity( sourceOperation, operationDemandedQuantityMap, productionOrder, rootProductModelId); task.setPlanQuantity(planQuantity); task.setCompleteQuantity(BigDecimal.ZERO); task.setWorkOrderNo(generateNextTaskNo()); task.setStatus(2); productionOperationTaskMapper.insert(task); } } else { // 不需要生产:检查工单是否存在 if (productionOperationTask != null) { validateTaskCanRemove(productionOperationTask); // 没有报工,则删除工单 productionOperationTaskMapper.deleteById(productionOperationTask.getId()); } } return R.ok(); } private void validateTaskCanRemove(ProductionOperationTask task) { if (task == null || task.getId() == null) { return; } if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) { throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工序快照"); } long reportCount = productionProductMainMapper.selectCount( Wrappers.lambdaQuery() .eq(ProductionProductMain::getProductionOperationTaskId, task.getId())); if (reportCount > 0) { throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工单"); } } private BigDecimal defaultDecimal(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; } @Override public R deleteRouteItem(Long id) { // 删除工艺路线 try { // 查询并准备业务数据 ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne( new LambdaQueryWrapper() .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id) .last("limit 1")); // 参数与前置条件校验 if (productionOperationTask == null) { throw new RuntimeException("删除失败:未找到关联的生产工单"); } if (productionOperationTask.getCompleteQuantity() != null && BigDecimal.ZERO.compareTo(productionOperationTask.getCompleteQuantity()) < 0) { throw new RuntimeException("删除失败:该工单已开始生产,请先删除生产报工"); } List productionProductMains = productionProductMainMapper.selectList( new LambdaQueryWrapper() .eq(ProductionProductMain::getProductionOperationTaskId, productionOperationTask.getId())); // 遍历处理数据并组装结果 for (ProductionProductMain main : productionProductMains) { productionProductMainService.removeProductMain(main.getId()); } Long productionOrderId = productionOperationTask.getProductionOrderId(); Long routingId = null; ProductionOrderRoutingOperation deleteItem = productionOrderRoutingOperationMapper.selectById(id); if (deleteItem != null) { routingId = deleteItem.getOrderRoutingId(); } productionOperationTaskMapper.delete(new LambdaQueryWrapper() .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id)); productionOrderRoutingOperationMapper.deleteById(id); if (routingId != null) { List operationList = productionOrderRoutingOperationMapper.selectList( Wrappers.lambdaQuery() .eq(ProductionOrderRoutingOperation::getOrderRoutingId, routingId) .eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId) .orderByAsc(ProductionOrderRoutingOperation::getDragSort)); for (int i = 0; i < operationList.size(); i++) { ProductionOrderRoutingOperation item = operationList.get(i); if (!Integer.valueOf(i + 1).equals(item.getDragSort())) { item.setDragSort(i + 1); // 持久化或输出处理结果 productionOrderRoutingOperationMapper.updateById(item); } } } return R.ok(); } catch (Exception e) { throw new RuntimeException("删除生产工艺路线失败:" + e.getMessage()); } } @Override public int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) { // 排序工艺路线 ProductionOrderRoutingOperation oldItem = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperation.getId()); List operationList = productionOrderRoutingOperationMapper.selectList( Wrappers.lambdaQuery() .eq(ProductionOrderRoutingOperation::getOrderRoutingId, oldItem.getOrderRoutingId()) .orderByAsc(ProductionOrderRoutingOperation::getDragSort)); Integer targetPosition = productionOrderRoutingOperation.getDragSort(); if (targetPosition != null && targetPosition >= 1) { operationList.removeIf(item -> item.getId().equals(oldItem.getId())); operationList.add(targetPosition - 1, oldItem); for (int i = 0; i < operationList.size(); i++) { ProductionOrderRoutingOperation item = operationList.get(i); int dragSort = i + 1; if (!Integer.valueOf(dragSort).equals(item.getDragSort())) { item.setDragSort(dragSort); productionOrderRoutingOperationMapper.updateById(item); } } return 1; } return 0; } private String generateNextTaskNo() { // 生成下一个生产工单号 String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); String prefix = "GD" + datePrefix; ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne( Wrappers.lambdaQuery() .likeRight(ProductionOperationTask::getWorkOrderNo, prefix) .orderByDesc(ProductionOperationTask::getWorkOrderNo) .last("limit 1")); int sequence = 1; if (lastTask != null && lastTask.getWorkOrderNo() != null && lastTask.getWorkOrderNo().startsWith(prefix)) { try { sequence = Integer.parseInt(lastTask.getWorkOrderNo().substring(prefix.length())) + 1; } catch (NumberFormatException ignored) { sequence = 1; } } return prefix + String.format("%03d", sequence); } }