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>