src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -2,21 +2,16 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.ruoyi.common.enums.StockRecordTypeEnum;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.procurementrecord.dto.Details;
import com.ruoyi.procurementrecord.dto.ProcurementAddDto;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.quality.dto.QualityInspectDto;
@@ -28,6 +23,8 @@
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.quality.service.IQualityInspectParamService;
import com.ruoyi.quality.service.IQualityInspectService;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.AllArgsConstructor;
@@ -40,10 +37,9 @@
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@AllArgsConstructor
@@ -61,6 +57,8 @@
    private QualityUnqualifiedMapper qualityUnqualifiedMapper;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private PurchaseLedgerMapper purchaseLedgerMapper;
    private ProcurementRecordService procurementRecordService;
@@ -91,8 +89,12 @@
    @Override
    public int submit(QualityInspect inspect) {
        QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId());
        //提交前必须判断是否合格
        if (ObjectUtils.isNull(qualityInspect.getCheckResult())) {
            throw new RuntimeException("请先判断是否合格");
        }
        /*判断不合格*/
        if (ObjectUtils.isNotNull(qualityInspect.getCheckResult()) && qualityInspect.getCheckResult().equals("不合格")) {
        if (qualityInspect.getCheckResult().equals("不合格")) {
            QualityUnqualified qualityUnqualified = new QualityUnqualified();
            BeanUtils.copyProperties(qualityInspect, qualityUnqualified);
            qualityUnqualified.setInspectState(0);//待处理
@@ -103,10 +105,14 @@
            qualityUnqualifiedMapper.insert(qualityUnqualified);
        } else {
            //合格直接入库
            stockUtils.addStock(inspect.getProductModelId(), inspect.getQuantity(), StockRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), inspect.getId());
            stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId());
            // 采购原材料检验:合格入库后同步到采购产品“已入库数量”,与扫码入库共用一份数据口径
            syncQualifiedInboundToPurchaseProducts(qualityInspect);
        }
        qualityInspect.setInspectState(1);//已提交
        return qualityInspectMapper.updateById(qualityInspect);
        int updated = qualityInspectMapper.updateById(qualityInspect);
        refreshPurchaseLedgerStockStatusByInspect(qualityInspect.getPurchaseLedgerId());
        return updated;
    }
    /*生成检验报告*/
@@ -198,5 +204,114 @@
    }
    private void refreshPurchaseLedgerStockStatusByInspect(Long purchaseLedgerId) {
        if (purchaseLedgerId == null) {
            return;
        }
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedgerId)
                .eq(SalesLedgerProduct::getType, 2));
        if (products == null || products.isEmpty()) {
            return;
        }
        boolean allInbound = true;
        boolean anyInbound = false;
        for (SalesLedgerProduct product : products) {
            BigDecimal orderQty = product.getQuantity() == null ? BigDecimal.ZERO : product.getQuantity();
            BigDecimal totalInboundQty = product.getStockedQuantity() == null ? BigDecimal.ZERO : product.getStockedQuantity();
            if (totalInboundQty.compareTo(BigDecimal.ZERO) > 0) {
                anyInbound = true;
            }
            if (totalInboundQty.compareTo(orderQty) < 0) {
                allInbound = false;
            }
        }
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseLedgerId);
        if (purchaseLedger == null) {
            return;
        }
        int targetStockStatus = allInbound ? 2 : (anyInbound ? 1 : 0);
        if (!Objects.equals(purchaseLedger.getStockStatus(), targetStockStatus)) {
            purchaseLedger.setStockStatus(targetStockStatus);
            purchaseLedgerMapper.updateById(purchaseLedger);
        }
    }
    private void syncQualifiedInboundToPurchaseProducts(QualityInspect qualityInspect) {
        if (qualityInspect == null) {
            return;
        }
        if (!Objects.equals(qualityInspect.getInspectType(), 0) || qualityInspect.getPurchaseLedgerId() == null) {
            return;
        }
        if (qualityInspect.getProductModelId() == null || qualityInspect.getQuantity() == null) {
            return;
        }
        BigDecimal inboundQty = qualityInspect.getQuantity();
        if (inboundQty.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        List<SalesLedgerProduct> lines = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getSalesLedgerId, qualityInspect.getPurchaseLedgerId())
                .eq(SalesLedgerProduct::getType, 2)
                .eq(SalesLedgerProduct::getProductModelId, qualityInspect.getProductModelId())
                .eq(SalesLedgerProduct::getIsChecked, true)
                .orderByAsc(SalesLedgerProduct::getId));
        if (lines == null || lines.isEmpty()) {
            return;
        }
        BigDecimal remaining = inboundQty;
        SalesLedgerProduct fallbackLine = null;
        for (SalesLedgerProduct line : lines) {
            if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
                break;
            }
            BigDecimal orderQty = line.getQuantity() == null ? BigDecimal.ZERO : line.getQuantity();
            BigDecimal stocked = line.getStockedQuantity() == null ? BigDecimal.ZERO : line.getStockedQuantity();
            BigDecimal canFill = orderQty.subtract(stocked);
            if (canFill.compareTo(BigDecimal.ZERO) <= 0) {
                fallbackLine = line;
                continue;
            }
            BigDecimal add = canFill.min(remaining);
            BigDecimal newStocked = stocked.add(add);
            int status;
            if (newStocked.compareTo(BigDecimal.ZERO) <= 0) {
                status = 0;
            } else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) {
                status = 1;
            } else {
                status = 2;
            }
            line.setStockedQuantity(newStocked);
            line.setProductStockStatus(status);
            line.fillRemainingQuantity();
            salesLedgerProductMapper.updateById(line);
            remaining = remaining.subtract(add);
            fallbackLine = line;
        }
        // 允许多入库:若仍有剩余,累计到最后一行,确保 remaining_shipped_quantity 能同步增长
        if (remaining.compareTo(BigDecimal.ZERO) > 0 && fallbackLine != null) {
            BigDecimal orderQty = fallbackLine.getQuantity() == null ? BigDecimal.ZERO : fallbackLine.getQuantity();
            BigDecimal stocked = fallbackLine.getStockedQuantity() == null ? BigDecimal.ZERO : fallbackLine.getStockedQuantity();
            BigDecimal newStocked = stocked.add(remaining);
            int status;
            if (newStocked.compareTo(BigDecimal.ZERO) <= 0) {
                status = 0;
            } else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) {
                status = 1;
            } else {
                status = 2;
            }
            fallbackLine.setStockedQuantity(newStocked);
            fallbackLine.setProductStockStatus(status);
            fallbackLine.fillRemainingQuantity();
            salesLedgerProductMapper.updateById(fallbackLine);
        }
    }
}