src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -1,8 +1,10 @@
package com.ruoyi.production.service.impl;
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.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;
@@ -12,12 +14,12 @@
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.dto.DrawMaterialDto;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
@@ -30,7 +32,6 @@
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -39,6 +40,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@@ -138,25 +140,70 @@
        productionProductMain.setProductProcessRouteItemId(dto.getProductProcessRouteItemId());
        productionProductMain.setWorkOrderId(dto.getWorkOrderId());
        productionProductMain.setStatus(0);
        productionProductMain.setDeviceId(dto.getDeviceId());
        productionProductMainMapper.insert(productionProductMain);
        /*新增报工投入表*/
        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomAndProcess(productProcessRoute.getBomId(), productProcess.getId());
        if (productStructureDtos.size() == 0) {
            //如果该工序没有产品结构的投入品,那这个投入品和产出品是同一个
            ProductStructureDto productStructureDto = new ProductStructureDto();
            productStructureDto.setProductModelId(productProcessRouteItem.getProductModelId());
            productStructureDto.setUnitQuantity(BigDecimal.ONE);
            productStructureDtos.add(productStructureDto);
        }
        for (ProductStructureDto productStructureDto : productStructureDtos) {
        /* 新增报工投入表 */
        List<DrawMaterialDto> drawMaterialList = dto.getDrawMaterialList();
        if (!CollectionUtils.isEmpty(drawMaterialList)) {
            // 1. 批量查询数据
            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
            if (productWorkOrder == null) {
                throw new RuntimeException("工单不存在");
            }
            ProductionProductInput productionProductInput = new ProductionProductInput();
            productionProductInput.setProductModelId(productStructureDto.getProductModelId());
            productionProductInput.setQuantity(productStructureDto.getUnitQuantity().multiply(dto.getQuantity()));
            productionProductInput.setProductMainId(productionProductMain.getId());
            productionProductInputMapper.insert(productionProductInput);
            stockUtils.substractStock(productStructureDto.getProductModelId(), productionProductInput.getQuantity(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode(), productionProductMain.getId());
            ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
            if (productOrder == null) {
                throw new RuntimeException("产品订单不存在");
            }
            // 2. 解析并构建物料Map
            List<DrawMaterialDto> existingMaterialList = JSON.parseArray(productOrder.getDrawMaterials(), DrawMaterialDto.class);
            if (CollectionUtils.isEmpty(existingMaterialList)) {
                throw new RuntimeException("可领用物料列表为空");
            }
            Map<Long, DrawMaterialDto> materialMap = existingMaterialList.stream()
                    .collect(Collectors.toMap(DrawMaterialDto::getProductModelId,
                            Function.identity()));
            // 处理报工物料
            List<ProductionProductInput> inputList = new ArrayList<>();
            for (DrawMaterialDto drawMaterial : drawMaterialList) {
                Long modelId = drawMaterial.getProductModelId();
                BigDecimal reportQty = drawMaterial.getReportQty();
                DrawMaterialDto material = materialMap.get(modelId);
                if (material == null) {
                    throw new RuntimeException("物料不存在: " + modelId);
                }
                // 验证库存
                BigDecimal availableQty = material.getRequisitionQty().subtract(reportQty);
                if (availableQty.compareTo(BigDecimal.valueOf(0)) < 0) {
                    throw new RuntimeException(String.format("物料%s库存不足,可用:%s,需领:%s",
                            modelId, availableQty, reportQty));
                }
                // 更新可领用
                material.setRequisitionQty(availableQty);
                // 构建投入记录
                ProductionProductInput input = new ProductionProductInput();
                input.setProductModelId(modelId);
                input.setQuantity(reportQty);
                input.setProductMainId(productionProductMain.getId());
                input.setRemark(drawMaterial.getRemark());
                inputList.add(input);
            }
            if (!inputList.isEmpty()) {
                for (ProductionProductInput productionProductInput : inputList) {
                    productionProductInputMapper.insert(productionProductInput);
                }
                productOrder.setDrawMaterials(JSON.toJSONString(existingMaterialList));
                productOrderMapper.updateById(productOrder);
            }
        }
        /*新增报工产出表*/
        ProductionProductOutput productionProductOutput = new ProductionProductOutput();
@@ -164,9 +211,10 @@
        productionProductOutput.setProductModelId(productProcessRouteItem.getProductModelId());
        productionProductOutput.setQuantity(dto.getQuantity() != null ? dto.getQuantity() : BigDecimal.ZERO);
        productionProductOutput.setScrapQty(dto.getScrapQty() != null ? dto.getScrapQty() : BigDecimal.ZERO);
        productionProductOutput.setOtherData(dto.getOtherData() != null ? dto.getOtherData() : "");
        productionProductOutputMapper.insert(productionProductOutput);
        //合格数量=报工数量-报废数量
        BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty());
        //合格数量=报工数量
        BigDecimal productQty = productionProductOutput.getQuantity();
        //只有合格数量>0才能增加相应数据
        if (productQty.compareTo(BigDecimal.ZERO) > 0) {
            /*新增质检*/
@@ -180,6 +228,13 @@
                    inspectType = 2;
                    process = null;
                }
                ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId());
                ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
                if (productOrder == null) {
                    throw new RuntimeException("生产订单不存在");
                }
                Product product = productMapper.selectById(productModel.getProductId());
                QualityInspect qualityInspect = new QualityInspect();
                qualityInspect.setProductId(product.getId());
@@ -192,6 +247,9 @@
                qualityInspect.setInspectType(inspectType);
                qualityInspect.setProductMainId(productionProductMain.getId());
                qualityInspect.setProductModelId(productModel.getId());
                qualityInspect.setBatchNo(productOrder.getBatchNo());
                qualityInspect.setInspectedQuantity(dto.getInspectedQuantity());
                qualityInspect.setManufacturingTeam(productOrder.getManufacturingTeam());
                qualityInspectMapper.insert(qualityInspect);
                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
                if (qualityTestStandard.size() > 0) {
@@ -207,7 +265,7 @@
                                qualityInspectParamMapper.insert(param);
                            });
                }
            }else {
            } else {
                //直接入库
                stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId());
            }
@@ -220,6 +278,7 @@
            if (productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) == 0) {
                productWorkOrder.setActualEndTime(LocalDate.now());//实际结束时间
            }
            productWorkOrder.setTotalInvestment(dto.getTotalInvestment());
            productWorkOrderMapper.updateById(productWorkOrder);
            //生产订单
            ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
@@ -264,10 +323,10 @@
    public Boolean removeProductMain(Long id) {
        //判断该条报工是否不合格处理,如果不合格处理了,则不允许删除
        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, id));
        if (qualityInspects.size() > 0){
        if (qualityInspects.size() > 0) {
            List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(Wrappers.<QualityUnqualified>lambdaQuery()
                    .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState()==1) {
            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) {
                throw new ServiceException("该条报工已经不合格处理了,不允许删除");
            }
        }
@@ -321,9 +380,37 @@
                    new LambdaQueryWrapper<QualityInspectParam>()
                            .eq(QualityInspectParam::getInspectId, q.getId()));
            qualityInspectMapper.deleteById(q.getId());
                stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
            stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
        });
        ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
        List<DrawMaterialDto> materialDtoList = JSON.parseArray(productOrder.getDrawMaterials(), DrawMaterialDto.class);
        // 批量查询并构建Map
        Map<Long, BigDecimal> usedQuantityMap = productionProductInputMapper.selectList(
                        new LambdaQueryWrapper<ProductionProductInput>()
                                .eq(ProductionProductInput::getProductMainId, productionProductMain.getId())
                                .in(ProductionProductInput::getProductModelId,
                                        materialDtoList.stream()
                                                .map(DrawMaterialDto::getProductModelId)
                                                .collect(Collectors.toList()))
                ).stream()
                .collect(Collectors.groupingBy(
                        ProductionProductInput::getProductModelId,
                        Collectors.reducing(BigDecimal.ZERO, ProductionProductInput::getQuantity, BigDecimal::add)
                ));
        // 更新所有物料
        materialDtoList.forEach(dto -> {
            BigDecimal usedQty = usedQuantityMap.getOrDefault(dto.getProductModelId(), BigDecimal.ZERO);
            dto.setRequisitionQty(dto.getRequisitionQty().add(usedQty));
        });
        // 更新订单
        productOrder.setDrawMaterials(JSON.toJSONString(materialDtoList));
        productOrderMapper.updateById(productOrder);
        // 删除产出记录
        productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                .eq(ProductionProductOutput::getProductMainId, productionProductMain.getId()));