5 天以前 0d7d874912d0147376826b55667a1deb6547ed91
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -4,21 +4,15 @@
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.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.pojo.ProductionProductMain;
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.mapper.TechnologyOperationParamMapper;
import com.ruoyi.technology.mapper.TechnologyParamMapper;
import com.ruoyi.technology.pojo.TechnologyOperationParam;
import com.ruoyi.technology.pojo.TechnologyParam;
import com.ruoyi.technology.pojo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -26,8 +20,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
@@ -42,15 +35,23 @@
    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<TechnologyOperationParam> technologyOperationParams = technologyOperationParamMapper.selectList(Wrappers.<TechnologyOperationParam>lambdaQuery()
                .eq(TechnologyOperationParam::getTechnologyOperationId, productionOrderRoutingOperation.getTechnologyOperationId()));
        // 参数与前置条件校验
        if (CollectionUtils.isNotEmpty(technologyOperationParams)){
            ArrayList<ProductionOrderRoutingOperationParam> productionOrderRoutingOperationParams = new ArrayList<>();
        // 遍历处理数据并组装结果
            for (TechnologyOperationParam technologyOperationParam : technologyOperationParams) {
                TechnologyParam technologyParam = technologyParamMapper.selectById(technologyOperationParam.getTechnologyParamId());
                ProductionOrderRoutingOperationParam productionOrderRoutingOperationParam = new ProductionOrderRoutingOperationParam();
@@ -90,7 +91,7 @@
            }
            String workOrderNoStr = "GD" + String.format("%s%03d", datePrefix, sequenceNumber);
            ProductionOperationTask productionOperationTask = new ProductionOperationTask();
            productionOperationTask.setTechnologyRoutingOperationId(productionOrderRoutingOperation.getId());
            productionOperationTask.setProductionOrderRoutingOperationId(productionOrderRoutingOperation.getId());
            productionOperationTask.setProductionOrderId(productionOrderRoutingOperation.getProductionOrderId());
            productionOperationTask.setPlanQuantity(BigDecimal.ZERO);
            productionOperationTask.setCompleteQuantity(BigDecimal.ZERO);
@@ -102,12 +103,118 @@
    }
    @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<ProductionOperationTask>()
                        .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.<ProductionOrderBom>lambdaQuery()
                                .eq(ProductionOrderBom::getProductionOrderId, productionOrder.getId()));
                // 确定根产品规格ID
                Long rootProductModelId = orderBom != null && orderBom.getProductModelId() != null
                        ? orderBom.getProductModelId()
                        : productionOrder.getProductModelId();
                // 获取BOM结构列表
                List<ProductionBomStructure> orderBomStructureList = orderBom == null || orderBom.getId() == null
                        ? Collections.emptyList()
                        : productionBomStructureMapper.selectList(
                        Wrappers.<ProductionBomStructure>lambdaQuery()
                                .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
                                .orderByAsc(ProductionBomStructure::getId));
                // 构建工序需求量映射
                Map<String, BigDecimal> 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.<ProductionProductMain>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<ProductionOperationTask>()
                            .eq(ProductionOperationTask::getTechnologyRoutingOperationId, id)
                            .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id)
                            .last("limit 1"));
        // 参数与前置条件校验
            if (productionOperationTask == null) {
                throw new RuntimeException("删除失败:未找到关联的生产工单");
            }
@@ -118,6 +225,7 @@
            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .eq(ProductionProductMain::getProductionOperationTaskId, productionOperationTask.getId()));
        // 遍历处理数据并组装结果
            for (ProductionProductMain main : productionProductMains) {
                productionProductMainService.removeProductMain(main.getId());
            }
@@ -128,7 +236,7 @@
                routingId = deleteItem.getOrderRoutingId();
            }
            productionOperationTaskMapper.delete(new LambdaQueryWrapper<ProductionOperationTask>()
                    .eq(ProductionOperationTask::getTechnologyRoutingOperationId, id));
                    .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id));
            productionOrderRoutingOperationMapper.deleteById(id);
            if (routingId != null) {
                List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
@@ -140,6 +248,7 @@
                    ProductionOrderRoutingOperation item = operationList.get(i);
                    if (!Integer.valueOf(i + 1).equals(item.getDragSort())) {
                        item.setDragSort(i + 1);
        // 持久化或输出处理结果
                        productionOrderRoutingOperationMapper.updateById(item);
                    }
                }
@@ -152,6 +261,7 @@
    @Override
    public int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        // 排序工艺路线
        ProductionOrderRoutingOperation oldItem = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperation.getId());
        List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
@@ -173,4 +283,24 @@
        }
        return 0;
    }
    private String generateNextTaskNo() {
        // 生成下一个生产工单号
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "GD" + datePrefix;
        ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
                Wrappers.<ProductionOperationTask>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);
    }
}