src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -1,30 +1,38 @@
package com.ruoyi.production.service.impl;
import cn.hutool.core.util.BooleanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockUnQualifiedRecordTypeEnum;
import com.ruoyi.basic.dto.SelectOptionDTO;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.DrawMaterialDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.service.ProductOrderService;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import org.springframework.beans.factory.annotation.Autowired;
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.List;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -66,9 +74,26 @@
    @Autowired
    private StockUtils stockUtils;
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private StockInventoryMapper stockInventoryMapper;
    @Override
    public IPage<ProductOrderDto> pageProductOrder(Page page, ProductOrderDto productOrder) {
        return productOrderMapper.pageProductOrder(page, productOrder);
        IPage<ProductOrderDto> productOrderDtoIPage = productOrderMapper.pageProductOrder(page, productOrder);
        List<ProductOrderDto> productOrderDtos = productOrderDtoIPage.getRecords();
        for (int i = 0; i < productOrderDtos.size(); i++) {
            ProductOrderDto productOrderDto = productOrderDtos.get(i);
            if (BooleanUtil.isTrue(productOrderDto.getIsEnd())) {
                // 如果生产订单被结束,则将完成进度设置为100%
                productOrderDto.setCompletionStatus(BigDecimal.valueOf(100));
            }
        }
        return productOrderDtoIPage;
    }
    @Override
@@ -147,92 +172,27 @@
    @Override
    public Boolean delete(Long[] ids) {
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getId, ids)
        );
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            // 批量查询processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getProductOrderId, ids)
            );
            if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(allRouteItems)) {
                // 获取要删除的工序项ID
                List<Long> routeItemIds = allRouteItems.stream()
                        .map(ProductProcessRouteItem::getId)
                        .collect(Collectors.toList());
                // 查询关联的工单ID
                List<ProductWorkOrder> workOrders = productWorkOrderMapper.selectList(
                        new LambdaQueryWrapper<ProductWorkOrder>()
                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds)
                );
                if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(workOrders)) {
                    List<Long> workOrderIds = workOrders.stream()
                            .map(ProductWorkOrder::getId)
                            .collect(Collectors.toList());
                    // 查询关联的生产主表ID
                    List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                            new LambdaQueryWrapper<ProductionProductMain>()
                                    .in(ProductionProductMain::getWorkOrderId, workOrderIds)
                    );
                    List<Long> productMainIds = productMains.stream()
                            .map(ProductionProductMain::getId)
                            .collect(Collectors.toList());
                    // 删除产出表、投入表数据
                    if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(productMainIds)) {
                        productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                        productionProductInputMapper.deleteByProductMainIds(productMainIds);
                        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                                new LambdaQueryWrapper<QualityInspect>()
                                        .in(QualityInspect::getProductMainId, productMainIds)
                        );
                        //删除出库记录
                        for (Long productMainId : productMainIds) {
                            //删除生产出库记录
                            stockUtils.deleteStockOutRecord(productMainId, StockQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
                            //删除报废的入库记录
                            stockUtils.deleteStockInRecord(productMainId, StockUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
                        }
                        qualityInspects.forEach(qualityInspect -> {
                            //inspectState=1 已提交 不能删除
                            if (qualityInspect.getInspectState() == 1) {
                                throw new RuntimeException("已提交的检验单不能删除");
                            }
                        });
                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
                        salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                                .in(SalesLedgerProductionAccounting::getProductMainId, productMainIds));
                    }
                    // 删除生产主表数据
                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
                    // 删除工单数据
                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
                }
        //如果已经开始生产,不能删除
        //查询生产订单下的工单
        List<ProductWorkOrder> productWorkOrders = productWorkOrderMapper.selectList(Wrappers.<ProductWorkOrder>lambdaQuery().in(ProductWorkOrder::getProductOrderId, ids));
        if (productWorkOrders.size() > 0) {
            //判断是否有报工数据
            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(Wrappers.<ProductionProductMain>lambdaQuery()
                    .in(ProductionProductMain::getWorkOrderId, productWorkOrders.stream().map(ProductWorkOrder::getId).collect(Collectors.toList())));
            if (productionProductMains.size() > 0) {
                throw new RuntimeException("生产订单已经开始生产,不能删除");
            }
            // 批量删除processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getProductOrderId, ids));
            // 批量删除productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, ids));
            // 批量删除productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getId, ids));
            //删除工单
            productWorkOrderMapper.delete(Wrappers.<ProductWorkOrder>lambdaQuery().in(ProductWorkOrder::getProductOrderId, ids));
        }
        //删除工艺路线
        productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                .in(ProductProcessRouteItem::getProductOrderId, ids));
        productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                .in(ProductProcessRoute::getProductOrderId, ids));
        //删除生产订单
        productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                .in(ProductOrder::getId, ids));
        return true;
    }
@@ -267,4 +227,112 @@
    }
    @Override
    public int finishOrder(Long orderId) {
        ProductOrder productOrder = new ProductOrder();
        productOrder.setId(orderId);
        productOrder.setIsEnd(true);
        return productOrderMapper.updateById(productOrder);
    }
    @Override
    public int cleanRecord(Long id, Map<String, Object> cleanRecord) {
        ProductOrder productOrder = productOrderMapper.selectById(id);
        if (productOrder == null) {
            throw new BaseException("订单不存在");
        }
        productOrder.setCleanRecord(JSON.toJSONString(cleanRecord));
        return productOrderMapper.updateById(productOrder);
    }
    @Override
    public List<SelectOptionDTO<String>> getProductOrderBatchNo() {
        List<ProductOrder> productOrders = productOrderMapper.selectList(null);
        return productOrders.stream().map(productOrder -> new SelectOptionDTO<>(productOrder.getBatchNo(), productOrder.getBatchNo())).collect(Collectors.toList());
    }
    @Override
    public List<StockInventoryDto> getByBomId(Long bomId) {
        List<ProductStructureDto> structureList = productStructureMapper.listBybomId(bomId);
        if (CollectionUtils.isEmpty(structureList)) {
            return Collections.emptyList();
        }
        Set<Long> allNodeIds = structureList.stream()
                .map(ProductStructureDto::getId)
                .collect(Collectors.toSet());
        Set<Long> parentIds = structureList.stream()
                .filter(node -> node.getParentId() != null && node.getParentId() != 0)
                .map(ProductStructureDto::getParentId)
                .collect(Collectors.toSet());
        Set<Long> leafNodeIds = new HashSet<>(allNodeIds);
        leafNodeIds.removeAll(parentIds);
        //  获取叶子节点的 productModelId
        List<Long> productModelIds = structureList.stream()
                .filter(node -> leafNodeIds.contains(node.getId()))
                .map(ProductStructureDto::getProductModelId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (productModelIds.isEmpty()) {
            return Collections.emptyList();
        }
        return stockInventoryMapper.getStockInventory(productModelIds);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int drawMaterials(ProductOrderDto productOrderDto) {
        if (productOrderDto == null || productOrderDto.getId() == null) {
            throw new RuntimeException("参数错误");
        }
        String jsonString = productOrderDto.getDrawMaterials();
        if (StringUtils.isEmpty(jsonString)) {
            throw new RuntimeException("领料明细不能为空");
        }
        List<DrawMaterialDto> drawMaterialsList;
        try {
            drawMaterialsList = JSON.parseArray(jsonString, DrawMaterialDto.class);
        } catch (Exception e) {
            throw new RuntimeException("领料明细格式错误");
        }
        if (CollectionUtils.isEmpty(drawMaterialsList)) {
            throw new RuntimeException("领料明细不能为空");
        }
        // 处理领料(扣减库存)
        try {
            for (DrawMaterialDto drawMaterialDto : drawMaterialsList) {
                if (drawMaterialDto.getProductModelId() == null) {
                    throw new RuntimeException("产品型号ID不能为空");
                }
                stockUtils.substractStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), StockOutQualifiedRecordTypeEnum.DRAW_MATERIALS_STOCK_OUT.getCode(), productOrderDto.getId());
            }
        } catch (Exception e) {
            throw new RuntimeException("领料失败:" + e.getMessage());
        }
        // JSON字符串存储
        String newJsonString = JSON.toJSONString(drawMaterialsList);
        int update = productOrderMapper.update(null,
                new LambdaUpdateWrapper<ProductOrder>()
                        .eq(ProductOrder::getId, productOrderDto.getId())
                        .set(ProductOrder::getDrawMaterials, newJsonString));
        // 校验更新结果
        if (update == 0) {
            throw new RuntimeException("更新订单失败");
        }
        return update;
    }
}