17 小时以前 61f1de60e6f58dd8e19f01c56f2e56e40885d65b
点击发货-》发货审核-》出厂质检-》出库审核-》出库通过
已修改7个文件
210 ■■■■■ 文件已修改
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/mapper/QualityInspectMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/quality/QualityInspectMapper.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -40,12 +40,15 @@
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.utils.QualityInspectHelper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.SalesQuotationMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.mapper.ShippingProductDetailMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.pojo.ShippingProductDetail;
import com.ruoyi.staff.mapper.HolidayApplicationMapper;
import com.ruoyi.staff.pojo.HolidayApplication;
import lombok.RequiredArgsConstructor;
@@ -94,6 +97,8 @@
    private final EnterpriseNewsMapper enterpriseNewsMapper;
    private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
    private final ShippingProductDetailMapper shippingProductDetailMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    @Override
    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
@@ -703,6 +708,9 @@
            shippingInfo.setStatus(ShippingStatusEnum.APPROVED.getCode());
            shippingInfo.setShippingDate(new Date());
            stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
            // 发货审批通过后,自动生成出厂检验单
            createFactoryInspectForShipping(shippingInfo);
        } else if ("REJECTED".equals(status)) {
            stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
            shippingInfo.setStatus(ShippingStatusEnum.REJECTED.getCode());
@@ -712,6 +720,40 @@
        shippingInfoMapper.updateById(shippingInfo);
    }
    /**
     * 发货审批通过后,自动生成出厂检验单
     */
    private void createFactoryInspectForShipping(ShippingInfo shippingInfo) {
        // 查询发货产品明细
        List<ShippingProductDetail> detailList = shippingProductDetailMapper.selectList(
                new LambdaQueryWrapper<ShippingProductDetail>()
                        .eq(ShippingProductDetail::getShippingInfoId, shippingInfo.getId())
        );
        if (detailList == null || detailList.isEmpty()) {
            return;
        }
        // 获取客户名称
        String customerName = null;
        if (shippingInfo.getSalesLedgerId() != null) {
            com.ruoyi.sales.pojo.SalesLedger salesLedger = salesLedgerMapper.selectById(shippingInfo.getSalesLedgerId());
            if (salesLedger != null) {
                customerName = salesLedger.getCustomerName();
            }
        }
        // 为每个发货产品创建出厂检验单
        for (ShippingProductDetail detail : detailList) {
            qualityInspectHelper.addFactoryInspect(
                    shippingInfo,
                    detail,
                    customerName,
                    shippingInfo.getSalesLedgerId()
            );
        }
    }
    private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
src/main/java/com/ruoyi/quality/mapper/QualityInspectMapper.java
@@ -52,4 +52,14 @@
     * 获取热点检测指标 Top 4 + 其他
     */
    List<QualityParameterStatDto> getTopParameters(@Param("modelType") Integer modelType);
    /**
     * 根据ID查询产品规格
     */
    com.ruoyi.basic.pojo.ProductModel selectProductModelById(@Param("id") Long id);
    /**
     * 根据ID查询产品
     */
    com.ruoyi.basic.pojo.Product selectProductById(@Param("id") Long id);
}
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -153,6 +153,11 @@
    private Long salesLedgerId;
    /**
     * 发货信息id(出厂检验关联发货)
     */
    private Long shippingInfoId;
    /**
     * 报工id
     */
    private Long productMainId;
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -157,14 +157,24 @@
            qualityInspect.setUnqualifiedQuantity(BigDecimal.ZERO);
        }
        // 合格直接入库
        if(qualityInspect.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0){
        // 合格入库处理(根据检验类型区分)
        // 过程检验(inspectType=1):入库到成品库
        // 出厂检验(inspectType=2):不做任何业务处理
        // 原材料检验(inspectType=0):正常质检入库
        Integer inspectType = qualityInspect.getInspectType();
        boolean shouldStockIn = inspectType == null || inspectType == 0 || inspectType == 1;
        if (shouldStockIn && qualityInspect.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0) {
            //仅添加入库记录
            StockInventoryDto stockInventoryDto = new StockInventoryDto();
            //如果是采购质检合格入库选用CUSTOMIZATION_UNSTOCK_OUT,其余合格入库选用QUALITYINSPECT_STOCK_IN
            stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()));
            if (ObjectUtils.isNotEmpty(qualityInspect.getPurchaseLedgerId())){
            //过程检验使用生产报工入库类型,其他质检使用质检入库类型
            if (inspectType != null && inspectType == 1) {
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()));
            } else if (ObjectUtils.isNotEmpty(qualityInspect.getPurchaseLedgerId())) {
                //采购质检合格入库
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
            } else {
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()));
            }
            stockInventoryDto.setRecordId(qualityInspect.getId());
            stockInventoryDto.setProductModelId(qualityInspect.getProductModelId());
@@ -375,12 +385,22 @@
        // 4. 更新检验单
        qualityInspectMapper.updateById(qualityInspect);
        // 5. 合格入库处理
        if (qualified.compareTo(BigDecimal.ZERO) > 0) {
        // 5. 合格入库处理(根据检验类型区分)
        // 过程检验(inspectType=1):入库到成品库
        // 出厂检验(inspectType=2):不做任何业务处理
        // 原材料检验(inspectType=0):正常质检入库
        Integer inspectType = qualityInspect.getInspectType();
        boolean shouldStockIn = inspectType == null || inspectType == 0 || inspectType == 1;
        if (shouldStockIn && qualified.compareTo(BigDecimal.ZERO) > 0) {
            StockInventoryDto stockInventoryDto = new StockInventoryDto();
            stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()));
            if (ObjectUtils.isNotEmpty(qualityInspect.getPurchaseLedgerId())) {
            //过程检验使用生产报工入库类型,其他质检使用质检入库类型
            if (inspectType != null && inspectType == 1) {
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()));
            } else if (ObjectUtils.isNotEmpty(qualityInspect.getPurchaseLedgerId())) {
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
            } else {
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()));
            }
            stockInventoryDto.setRecordId(qualityInspect.getId());
            stockInventoryDto.setProductModelId(qualityInspect.getProductModelId());
src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
@@ -12,6 +12,8 @@
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.pojo.ShippingProductDetail;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@@ -104,4 +106,67 @@
            }
        }
    }
    /**
     * 创建出厂检验单(发货审批通过后自动生成)
     * @param shippingInfo 发货信息
     * @param detail 发货产品明细
     * @param customerName 客户名称
     * @param salesLedgerId 销售台账ID
     */
    public void addFactoryInspect(ShippingInfo shippingInfo, ShippingProductDetail detail,
                                   String customerName, Long salesLedgerId) {
        QualityInspect qualityInspect = new QualityInspect();
        qualityInspect.setInspectType(2); // 出厂检验
        qualityInspect.setCustomer(customerName);
        qualityInspect.setSalesLedgerId(salesLedgerId);
        qualityInspect.setShippingInfoId(shippingInfo.getId()); // 关联发货信息
        qualityInspect.setProductModelId(detail.getProductModelId());
        qualityInspect.setQuantity(detail.getQuantity());
        qualityInspect.setInspectState(0); // 未提交
        // 通过 productModelId 查询产品信息
        if (detail.getProductModelId() != null) {
            com.ruoyi.basic.pojo.ProductModel productModel = qualityInspectMapper.selectProductModelById(detail.getProductModelId());
            if (productModel != null) {
                qualityInspect.setProductId(productModel.getProductId());
                qualityInspect.setModel(productModel.getModel());
                qualityInspect.setUnit(productModel.getUnit());
                // 查询产品名称
                if (productModel.getProductId() != null) {
                    com.ruoyi.basic.pojo.Product product = qualityInspectMapper.selectProductById(productModel.getProductId());
                    if (product != null) {
                        qualityInspect.setProductName(product.getProductName());
                    }
                }
            }
        }
        qualityInspectMapper.insert(qualityInspect);
        // 查询出厂检验标准,初始化检验参数
        if (qualityInspect.getProductId() != null) {
            List<QualityTestStandard> qualityTestStandardList = qualityTestStandardMapper
                    .getQualityTestStandardByProductId(qualityInspect.getProductId(), 2, null);
            if (!qualityTestStandardList.isEmpty()) {
                QualityTestStandard firstStandard = qualityTestStandardList.get(0);
                qualityInspect.setTestStandardId(firstStandard.getId());
                applyInspectRuleDefaults(qualityInspect, firstStandard, detail.getQuantity());
                qualityInspectMapper.updateById(qualityInspect);
                List<QualityTestStandardParam> standardParams = qualityTestStandardParamMapper.selectList(
                        Wrappers.<QualityTestStandardParam>lambdaQuery()
                                .eq(QualityTestStandardParam::getTestStandardId, firstStandard.getId()));
                for (QualityTestStandardParam standardParam : standardParams) {
                    QualityInspectParam param = new QualityInspectParam();
                    BeanUtils.copyProperties(standardParam, param);
                    param.setId(null);
                    param.setInspectId(qualityInspect.getId());
                    qualityInspectParamMapper.insert(param);
                }
            }
        }
    }
}
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -15,6 +15,8 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import java.time.LocalDateTime;
import com.ruoyi.stock.dto.StockInventoryDto;
@@ -52,6 +54,7 @@
    private final StockUninventoryMapper stockUninventoryMapper;
    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
    private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper;
    private final QualityInspectMapper qualityInspectMapper;
    @Override
    public IPage<StockOutRecordDto> listPage(Page page, StockOutRecordDto stockOutRecordDto) {
@@ -183,6 +186,12 @@
            if (stockOutRecord.getApprovalStatus() != null && !ReviewStatusEnum.PENDING_REVIEW.getCode().equals(stockOutRecord.getApprovalStatus())) {
                throw new BaseException("只有待审批状态的记录才能审批,出库批次:" + stockOutRecord.getOutboundBatches());
            }
            // 出库审批通过前,检查是否需要出厂质检以及质检是否完成
            if (ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus) && StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode().equals(stockOutRecord.getRecordType())) {
                checkFactoryInspectCompleted(stockOutRecord);
            }
            stockOutRecord.setApprovalStatus(approvalStatus);
            stockOutRecordMapper.updateById(stockOutRecord);
            // 审批通过时,扣减库存
@@ -215,6 +224,36 @@
        return ids.size();
    }
    /**
     * 检查销售出库是否已完成出厂质检
     */
    private void checkFactoryInspectCompleted(StockOutRecord stockOutRecord) {
        // 查询该出库记录对应的出厂检验单是否已完成
        Long recordId = stockOutRecord.getRecordId();
        Long productModelId = stockOutRecord.getProductModelId();
        if (recordId == null || productModelId == null) {
            return;
        }
        // 查询关联的出厂检验单(inspectType=2, shippingInfoId=recordId, productModelId)
        QualityInspect qualityInspect = qualityInspectMapper.selectOne(
                new LambdaQueryWrapper<QualityInspect>()
                        .eq(QualityInspect::getInspectType, 2)
                        .eq(QualityInspect::getShippingInfoId, recordId)
                        .eq(QualityInspect::getProductModelId, productModelId)
                        .last("limit 1")
        );
        if (qualityInspect == null) {
            throw new BaseException("该出库记录未生成出厂检验单,请先完成发货审批");
        }
        if (qualityInspect.getInspectState() == null || qualityInspect.getInspectState() != 1) {
            throw new BaseException("出厂检验单尚未提交完成,请先完成出厂质检后再进行出库审批");
        }
    }
    private StockInventory getStockInventory(Long productModelId, String batchNo) {
        LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>();
        eq.eq(StockInventory::getProductModelId, productModelId);
src/main/resources/mapper/quality/QualityInspectMapper.xml
@@ -471,5 +471,16 @@
    </select>
    <select id="selectProductModelById" resultType="com.ruoyi.basic.pojo.ProductModel">
        SELECT id, product_id, model, unit
        FROM product_model
        WHERE id = #{id}
    </select>
    <select id="selectProductById" resultType="com.ruoyi.basic.pojo.Product">
        SELECT id, product_name
        FROM product
        WHERE id = #{id}
    </select>
</mapper>