| | |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.procurementrecord.service.ProcurementRecordService; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.quality.dto.BatchQuickInspectRequest; |
| | | import com.ruoyi.quality.dto.QualityInspectDto; |
| | | import com.ruoyi.quality.mapper.QualityInspectMapper; |
| | | import com.ruoyi.quality.mapper.QualityTestStandardMapper; |
| | |
| | | import com.ruoyi.quality.pojo.QualityInspect; |
| | | import com.ruoyi.quality.pojo.QualityInspectParam; |
| | | import com.ruoyi.quality.pojo.QualityUnqualified; |
| | | import com.ruoyi.quality.utils.QualityInspectTemplateExportHelper; |
| | | import com.ruoyi.stock.pojo.StockInRecord; |
| | | import com.ruoyi.stock.service.StockInRecordService; |
| | | import com.ruoyi.quality.service.IQualityInspectParamService; |
| | |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Propagation; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.math.BigDecimal; |
| | | import java.net.URLEncoder; |
| | | import java.sql.Date; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | |
| | | |
| | | private ProcurementRecordService procurementRecordService; |
| | | |
| | | private final QualityInspectTemplateExportHelper qualityInspectTemplateExportHelper; |
| | | |
| | | @Override |
| | | public int add(QualityInspectDto qualityInspectDto) { |
| | | QualityInspect qualityInspect = new QualityInspect(); |
| | | BeanUtils.copyProperties(qualityInspectDto, qualityInspect); |
| | | qualityInspect.setInspectState(0);//默认未提交 |
| | | // 根据 inspectRule 补全抽检比例和抽检数量默认值 |
| | | applyInspectRuleDefaults(qualityInspect); |
| | | qualityInspectMapper.insert(qualityInspect); |
| | | for (QualityInspectParam qualityInspectParam : qualityInspectDto.getQualityInspectParams()) { |
| | | qualityInspectParam.setInspectId(qualityInspect.getId()); |
| | | } |
| | | qualityInspectParamService.saveBatch(qualityInspectDto.getQualityInspectParams()); |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * 根据 inspectRule 设置抽检比例和抽检数量默认值 |
| | | * - inspectRule=0 (全检): sampleRatio=100, sampleQuantity=全部数量 |
| | | * - inspectRule=1 (抽检): sampleRatio 取传入值或0, sampleQuantity=数量×比例/100 |
| | | */ |
| | | private void applyInspectRuleDefaults(QualityInspect inspect) { |
| | | Integer rule = inspect.getInspectRule(); |
| | | java.math.BigDecimal quantity = inspect.getQuantity(); |
| | | if (rule == null || rule == 0) { |
| | | // 全检 |
| | | inspect.setSampleRatio(java.math.BigDecimal.valueOf(100)); |
| | | inspect.setSampleQuantity(quantity != null ? quantity : java.math.BigDecimal.ZERO); |
| | | } else { |
| | | // 抽检 |
| | | java.math.BigDecimal ratio = inspect.getSampleRatio() != null ? inspect.getSampleRatio() : java.math.BigDecimal.ZERO; |
| | | inspect.setSampleRatio(ratio); |
| | | if (quantity != null && ratio.compareTo(java.math.BigDecimal.ZERO) > 0) { |
| | | inspect.setSampleQuantity(quantity.multiply(ratio) |
| | | .divide(java.math.BigDecimal.valueOf(100), 0, java.math.RoundingMode.CEILING)); |
| | | } else { |
| | | inspect.setSampleQuantity(java.math.BigDecimal.ZERO); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | stockInventoryDto.setRecordId(qualityInspect.getId()); |
| | | stockInventoryDto.setProductModelId(qualityInspect.getProductModelId()); |
| | | stockInventoryDto.setQualitity(qualityInspect.getQualifiedQuantity()); |
| | | // 入库数量 = 合格数量 * 入库比例 / 100,入库比例默认100% |
| | | BigDecimal stockInRatio = qualityInspect.getStockInRatio(); |
| | | if (stockInRatio == null || stockInRatio.compareTo(BigDecimal.ZERO) <= 0) { |
| | | stockInRatio = new BigDecimal("100.00"); |
| | | } |
| | | BigDecimal actualStockInQuantity = qualityInspect.getQualifiedQuantity() |
| | | .multiply(stockInRatio) |
| | | .divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP); |
| | | stockInventoryDto.setQualitity(actualStockInQuantity); |
| | | if (qualityInspect.getCheckTime() != null) { |
| | | LocalDate stockCreateDate = DateUtils.toLocalDate(qualityInspect.getCheckTime()).plusDays(1); |
| | | stockInventoryDto.setCreateTime(LocalDateTime.of(stockCreateDate, java.time.LocalTime.MIDNIGHT)); |
| | |
| | | qualityInspectMapper.updateById(qualityInspect); |
| | | int rows = submit(qualityInspect); |
| | | return rows > 0 ? R.ok("检验单提交成功") : R.fail("检验单提交失败"); |
| | | } |
| | | |
| | | @Override |
| | | public R batchQuickInspect(BatchQuickInspectRequest request) { |
| | | // 1. 数据校验 |
| | | if (request.getIds() == null || request.getIds().isEmpty()) { |
| | | return R.fail("请选择至少一条检验单"); |
| | | } |
| | | List<String> validResults = Arrays.asList("合格", "不合格", "部分合格"); |
| | | if (!validResults.contains(request.getCheckResult())) { |
| | | return R.fail("检测结果必须为:合格、不合格、部分合格"); |
| | | } |
| | | if (request.getTestStandardId() == null) { |
| | | return R.fail("指标标准ID不能为空"); |
| | | } |
| | | |
| | | String checkResult = request.getCheckResult(); |
| | | |
| | | // 解析检测日期 |
| | | Date checkTimeDate = null; |
| | | if (request.getCheckTime() != null && !request.getCheckTime().isEmpty()) { |
| | | checkTimeDate = Date.valueOf(LocalDate.parse(request.getCheckTime())); |
| | | } |
| | | |
| | | int success = 0; |
| | | List<String> errors = new ArrayList<>(); |
| | | |
| | | for (Long id : request.getIds()) { |
| | | try { |
| | | processSingleInspect(id, request, checkResult, checkTimeDate); |
| | | success++; |
| | | } catch (Exception e) { |
| | | errors.add("检验单 " + id + " 处理失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | if (!errors.isEmpty()) { |
| | | return R.ok(String.format("快速检验完成:成功 %d 条,失败 %d 条。失败原因:%s", |
| | | success, errors.size(), String.join(";", errors))); |
| | | } |
| | | return R.ok(String.format("快速检验完成:成功 %d 条", success)); |
| | | } |
| | | |
| | | /** |
| | | * 在独立事务中处理单个检验单 |
| | | * 支持全检和抽检模式: |
| | | * - 全检:数量、合格数量默认使用检验单自身的数量,不合格数量为0 |
| | | * - 抽检:使用前端传入的 sampleQuantity/qualifiedQuantity/unqualifiedQuantity |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) |
| | | public void processSingleInspect(Long id, BatchQuickInspectRequest request, |
| | | String checkResult, Date checkTimeDate) { |
| | | QualityInspect qualityInspect = qualityInspectMapper.selectById(id); |
| | | if (qualityInspect == null) { |
| | | throw new RuntimeException("检验单不存在"); |
| | | } |
| | | if (Integer.valueOf(1).equals(qualityInspect.getInspectState())) { |
| | | throw new RuntimeException("检验单已提交"); |
| | | } |
| | | |
| | | // 判断检验规则:全检(0/null) 或 抽检(1) |
| | | Integer inspectRule = qualityInspect.getInspectRule(); |
| | | boolean isFullInspect = inspectRule == null || inspectRule == 0; |
| | | |
| | | BigDecimal totalQty = qualityInspect.getQuantity() != null ? qualityInspect.getQuantity() : BigDecimal.ZERO; |
| | | BigDecimal sampleQty; |
| | | BigDecimal qualified; |
| | | BigDecimal unqualified; |
| | | |
| | | if (isFullInspect) { |
| | | // 全检模式:检验数量 = 总数量 |
| | | sampleQty = totalQty; |
| | | // 如果前端传入了合格/不合格数量则使用,否则默认全部合格 |
| | | if (request.getQualifiedQuantity() != null && request.getUnqualifiedQuantity() != null) { |
| | | qualified = request.getQualifiedQuantity(); |
| | | unqualified = request.getUnqualifiedQuantity(); |
| | | } else { |
| | | qualified = totalQty; |
| | | unqualified = BigDecimal.ZERO; |
| | | } |
| | | } else { |
| | | // 抽检模式 |
| | | // 抽检数量:优先使用前端传入值,其次使用检验单已有的 sampleQuantity,最后按比例计算 |
| | | if (request.getSampleQuantity() != null && request.getSampleQuantity().compareTo(BigDecimal.ZERO) > 0) { |
| | | sampleQty = request.getSampleQuantity(); |
| | | } else if (qualityInspect.getSampleQuantity() != null && qualityInspect.getSampleQuantity().compareTo(BigDecimal.ZERO) > 0) { |
| | | sampleQty = qualityInspect.getSampleQuantity(); |
| | | } else { |
| | | // 按抽检比例计算 |
| | | BigDecimal ratio = qualityInspect.getSampleRatio() != null ? qualityInspect.getSampleRatio() : BigDecimal.ZERO; |
| | | sampleQty = totalQty.multiply(ratio) |
| | | .divide(BigDecimal.valueOf(100), 0, BigDecimal.ROUND_CEILING); |
| | | } |
| | | // 校验抽检数量不能超过总数量 |
| | | if (sampleQty.compareTo(totalQty) > 0) { |
| | | sampleQty = totalQty; |
| | | } |
| | | |
| | | // 合格/不合格数量:优先使用前端传入值 |
| | | if (request.getQualifiedQuantity() != null || request.getUnqualifiedQuantity() != null) { |
| | | qualified = request.getQualifiedQuantity() != null ? request.getQualifiedQuantity() : BigDecimal.ZERO; |
| | | unqualified = request.getUnqualifiedQuantity() != null ? request.getUnqualifiedQuantity() : BigDecimal.ZERO; |
| | | } else { |
| | | // 默认抽检样本全部合格 |
| | | qualified = sampleQty; |
| | | unqualified = BigDecimal.ZERO; |
| | | } |
| | | } |
| | | |
| | | // 2. 更新检验单字段 |
| | | qualityInspect.setCheckResult(checkResult); |
| | | qualityInspect.setTestStandardId(request.getTestStandardId()); |
| | | // 记录实际检验数量(抽检时为样本数量,全检时为总数量) |
| | | qualityInspect.setQuantity(sampleQty); |
| | | qualityInspect.setQualifiedQuantity(qualified); |
| | | qualityInspect.setUnqualifiedQuantity(unqualified); |
| | | // 更新抽检数量字段 |
| | | if (!isFullInspect) { |
| | | qualityInspect.setSampleQuantity(sampleQty); |
| | | } |
| | | if (request.getCheckCompany() != null) { |
| | | qualityInspect.setCheckCompany(request.getCheckCompany()); |
| | | } |
| | | if (request.getCheckName() != null) { |
| | | qualityInspect.setCheckName(request.getCheckName()); |
| | | } |
| | | if (checkTimeDate != null) { |
| | | qualityInspect.setCheckTime(checkTimeDate); |
| | | } |
| | | qualityInspect.setInspectState(1); |
| | | |
| | | // 3. 保存检验参数 |
| | | if (request.getParamList() != null && !request.getParamList().isEmpty()) { |
| | | qualityInspectParamService.remove(Wrappers.<QualityInspectParam>lambdaQuery() |
| | | .eq(QualityInspectParam::getInspectId, id)); |
| | | for (QualityInspectParam param : request.getParamList()) { |
| | | param.setInspectId(id); |
| | | param.setId(null); |
| | | } |
| | | qualityInspectParamService.saveBatch(request.getParamList()); |
| | | } |
| | | |
| | | // 4. 更新检验单 |
| | | qualityInspectMapper.updateById(qualityInspect); |
| | | |
| | | // 5. 合格入库处理 |
| | | if (qualified.compareTo(BigDecimal.ZERO) > 0) { |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode())); |
| | | if (ObjectUtils.isNotEmpty(qualityInspect.getPurchaseLedgerId())) { |
| | | stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode())); |
| | | } |
| | | stockInventoryDto.setRecordId(qualityInspect.getId()); |
| | | stockInventoryDto.setProductModelId(qualityInspect.getProductModelId()); |
| | | // 入库数量 = 合格数量 * 入库比例 / 100,入库比例默认100% |
| | | BigDecimal stockInRatio = qualityInspect.getStockInRatio(); |
| | | if (stockInRatio == null || stockInRatio.compareTo(BigDecimal.ZERO) <= 0) { |
| | | stockInRatio = new BigDecimal("100.00"); |
| | | } |
| | | BigDecimal actualStockInQuantity = qualified |
| | | .multiply(stockInRatio) |
| | | .divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP); |
| | | stockInventoryDto.setQualitity(actualStockInQuantity); |
| | | if (qualityInspect.getCheckTime() != null) { |
| | | LocalDate stockCreateDate = DateUtils.toLocalDate(qualityInspect.getCheckTime()).plusDays(1); |
| | | stockInventoryDto.setCreateTime(LocalDateTime.of(stockCreateDate, java.time.LocalTime.MIDNIGHT)); |
| | | } |
| | | stockInventoryDto.setBatchNo(resolveProductionBatchNo( |
| | | qualityInspect.getProductMainId(), |
| | | qualityInspect.getId(), |
| | | qualityInspect.getProductModelId())); |
| | | stockInventoryService.addStockInRecordOnly(stockInventoryDto); |
| | | } |
| | | |
| | | // 6. 不合格处理 |
| | | if (unqualified.compareTo(BigDecimal.ZERO) > 0) { |
| | | QualityUnqualified qualityUnqualified = new QualityUnqualified(); |
| | | BeanUtils.copyProperties(qualityInspect, qualityUnqualified); |
| | | qualityUnqualified.setInspectState(0); |
| | | qualityUnqualified.setQuantity(unqualified); |
| | | List<QualityInspectParam> inspectParams = qualityInspectParamService.list( |
| | | Wrappers.<QualityInspectParam>lambdaQuery().eq(QualityInspectParam::getInspectId, id)); |
| | | String text = inspectParams.stream().map(QualityInspectParam::getParameterItem).collect(Collectors.joining(",")); |
| | | qualityUnqualified.setDefectivePhenomena(text + "这些指标中存在不合格"); |
| | | qualityUnqualified.setInspectId(id); |
| | | qualityUnqualifiedMapper.insert(qualityUnqualified); |
| | | } |
| | | } |
| | | |
| | | private String resolveProductionBatchNo(Long productionProductMainId, |
| | |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void exportWeiLong(HttpServletResponse response, Long id) { |
| | | qualityInspectTemplateExportHelper.exportWeiLong(response, id); |
| | | } |
| | | |
| | | @Override |
| | | public void exportBaiShi(HttpServletResponse response, Long id) { |
| | | qualityInspectTemplateExportHelper.exportBaiShi(response, id); |
| | | } |
| | | |
| | | @Override |
| | | public void exportDaLi(HttpServletResponse response, Long id) { |
| | | qualityInspectTemplateExportHelper.exportDaLi(response, id); |
| | | } |
| | | |
| | | @Override |
| | | public String analyzeTemplate(String templatePath) { |
| | | return qualityInspectTemplateExportHelper.analyzeTemplate(templatePath); |
| | | } |
| | | |
| | | } |