| | |
| | | package com.ruoyi.quality.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | 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.ruoyi.basic.enums.RecordTypeEnum; |
| | | import com.ruoyi.basic.utils.FileUtil; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.production.mapper.ProductionOperationTaskMapper; |
| | | import com.ruoyi.production.mapper.ProductionOrderMapper; |
| | | import com.ruoyi.production.mapper.ProductionOrderRoutingMapper; |
| | | import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper; |
| | | import com.ruoyi.production.mapper.ProductionProductMainMapper; |
| | | import com.ruoyi.production.pojo.ProductionOperationTask; |
| | | import com.ruoyi.production.pojo.ProductionOrder; |
| | | import com.ruoyi.production.pojo.ProductionOrderRouting; |
| | | import com.ruoyi.production.pojo.ProductionOrderRoutingOperation; |
| | | import com.ruoyi.production.pojo.ProductionProductMain; |
| | | import com.ruoyi.quality.mapper.QualityUnqualifiedMapper; |
| | | import com.ruoyi.quality.mapper.QualityUnqualifiedOrderMapper; |
| | | import com.ruoyi.quality.pojo.QualityInspect; |
| | | import com.ruoyi.quality.pojo.QualityUnqualified; |
| | | import com.ruoyi.quality.pojo.QualityUnqualifiedOrder; |
| | | import com.ruoyi.quality.service.IQualityInspectService; |
| | | import com.ruoyi.quality.service.IQualityUnqualifiedOrderService; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.AllArgsConstructor; |
| | | import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| | | import org.apache.poi.poifs.filesystem.POIFSFileSystem; |
| | | import org.apache.poi.ss.usermodel.*; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.math.BigDecimal; |
| | | import java.net.URLEncoder; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | @AllArgsConstructor |
| | | @Service |
| | |
| | | |
| | | private final QualityUnqualifiedOrderMapper orderMapper; |
| | | private final FileUtil fileUtil; |
| | | private final QualityUnqualifiedMapper qualityUnqualifiedMapper; |
| | | private final IQualityInspectService qualityInspectService; |
| | | private final ProductionProductMainMapper productionProductMainMapper; |
| | | private final ProductionOrderMapper productionOrderMapper; |
| | | private final ProductionOrderRoutingMapper productionOrderRoutingMapper; |
| | | private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper; |
| | | private final ProductionOperationTaskMapper productionOperationTaskMapper; |
| | | |
| | | @Override |
| | | public IPage<QualityUnqualifiedOrder> listPage(Page page, QualityUnqualifiedOrder query) { |
| | |
| | | } |
| | | return order; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public boolean save(QualityUnqualifiedOrder order) { |
| | | boolean result = super.save(order); |
| | | // 处置方式包含"维修"(2=厂内维修, 3=返厂维修)时,自动创建返修生产订单 |
| | | if (order.getDisposalMethod() != null && (order.getDisposalMethod() == 2 || order.getDisposalMethod() == 3)) { |
| | | createReworkProductionOrder(order); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public boolean deal(QualityUnqualifiedOrder order) { |
| | | QualityUnqualifiedOrder existing = orderMapper.selectById(order.getId()); |
| | | if (existing == null) { |
| | | return false; |
| | | } |
| | | existing.setDisposalMethod(order.getDisposalMethod()); |
| | | existing.setRepairEvaluation(order.getRepairEvaluation()); |
| | | existing.setReasonAnalysis(order.getReasonAnalysis()); |
| | | existing.setCorrectionAction(order.getCorrectionAction()); |
| | | existing.setPreventiveAction(order.getPreventiveAction()); |
| | | existing.setRemark(order.getRemark()); |
| | | existing.setDeptOpinion(order.getDeptOpinion()); |
| | | existing.setCompanyDecision(order.getCompanyDecision()); |
| | | existing.setGeneralManagerOpinion(order.getGeneralManagerOpinion()); |
| | | existing.setStatus(3); |
| | | boolean result = updateById(existing); |
| | | if (result && existing.getDisposalMethod() != null |
| | | && (existing.getDisposalMethod() == 2 || existing.getDisposalMethod() == 3)) { |
| | | createReworkProductionOrder(existing); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public boolean updateWithRework(QualityUnqualifiedOrder order) { |
| | | boolean result = updateById(order); |
| | | if (result && order.getDisposalMethod() != null |
| | | && (order.getDisposalMethod() == 2 || order.getDisposalMethod() == 3)) { |
| | | createReworkProductionOrder(order); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public void export(Long id, HttpServletResponse response) { |
| | | QualityUnqualifiedOrder order = getDetail(id); |
| | | if (order == null) { |
| | | throw new ServiceException("处理单不存在"); |
| | | } |
| | | try (InputStream is = this.getClass().getResourceAsStream("/static/不合格品处理单.xls"); |
| | | POIFSFileSystem fs = new POIFSFileSystem(is); |
| | | HSSFWorkbook wb = new HSSFWorkbook(fs)) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | |
| | | setCellValue(sheet, 2, 1, order.getProjectName()); |
| | | setCellValue(sheet, 2, 5, order.getProjectNo()); |
| | | setCellValue(sheet, 3, 1, order.getEquipmentName()); |
| | | setCellValue(sheet, 3, 5, order.getEquipmentDrawingNo()); |
| | | setCellValue(sheet, 4, 1, order.getMaterialName()); |
| | | setCellValue(sheet, 4, 5, order.getMaterialDrawingNo()); |
| | | setCellValue(sheet, 5, 1, order.getSpecificationModel()); |
| | | setCellValue(sheet, 5, 3, order.getMaterialQuality()); |
| | | setCellValue(sheet, 5, 5, order.getQuantity()); |
| | | setCellValue(sheet, 5, 7, order.getUnqualifiedQuantity()); |
| | | |
| | | // 不合格工序 - 只替换对应的□为√ |
| | | if (order.getUnqualifiedProcess() != null) { |
| | | String origin = "□来料 □制程 □成品"; |
| | | int idx = order.getUnqualifiedProcess() - 1; |
| | | if (idx >= 0 && idx < 3) { |
| | | origin = origin.replaceFirst("□", "√"); |
| | | if (idx >= 1) origin = origin.replaceFirst("□", idx == 1 ? "√" : "□"); |
| | | if (idx >= 2) origin = origin.replaceFirst("□", "√"); |
| | | } |
| | | // 按索引依次替换 |
| | | StringBuilder sb = new StringBuilder(); |
| | | int found = 0; |
| | | for (char c : "□来料 □制程 □成品".toCharArray()) { |
| | | if (c == '□') { |
| | | sb.append(found == idx ? '☑' : '□'); |
| | | found++; |
| | | } else { |
| | | sb.append(c); |
| | | } |
| | | } |
| | | setCellValue(sheet, 6, 1, sb.toString()); |
| | | } |
| | | setCellValue(sheet, 6, 5, order.getSupplierName()); |
| | | |
| | | setCellValue(sheet, 7, 1, order.getInspectorName()); |
| | | setCellValue(sheet, 7, 3, order.getInspectDate()); |
| | | setCellValue(sheet, 7, 5, order.getResponsiblePerson()); |
| | | setCellValue(sheet, 7, 7, order.getResponsibleDept()); |
| | | |
| | | setCellValue(sheet, 8, 1, order.getProblemDescription()); |
| | | setCellValue(sheet, 9, 1, order.getReasonAnalysis()); |
| | | setCellValue(sheet, 10, 1, order.getCorrectionAction()); |
| | | |
| | | // 处置方式 - 只替换对应的□为√ |
| | | if (order.getDisposalMethod() != null) { |
| | | String template = "□让步接收 □厂内维修 □返厂维修 □换货 □退货 □报废"; |
| | | int idx = order.getDisposalMethod() - 1; |
| | | StringBuilder sb = new StringBuilder(); |
| | | int found = 0; |
| | | for (char c : template.toCharArray()) { |
| | | if (c == '□') { |
| | | sb.append(found == idx ? '☑' : '□'); |
| | | found++; |
| | | } else { |
| | | sb.append(c); |
| | | } |
| | | } |
| | | setCellValue(sheet, 11, 1, sb.toString()); |
| | | } |
| | | setCellValue(sheet, 12, 1, order.getRepairEvaluation()); |
| | | setCellValue(sheet, 13, 1, order.getPreventiveAction()); |
| | | setCellValue(sheet, 14, 1, order.getDeptOpinion()); |
| | | setCellValue(sheet, 15, 1, order.getCompanyDecision()); |
| | | setCellValue(sheet, 16, 1, order.getGeneralManagerOpinion()); |
| | | |
| | | response.setContentType("application/vnd.ms-excel"); |
| | | String fileName = URLEncoder.encode("不合格品处理单_" + order.getOrderNo(), "UTF-8"); |
| | | response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); |
| | | response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xls"); |
| | | OutputStream os = response.getOutputStream(); |
| | | wb.write(os); |
| | | os.flush(); |
| | | os.close(); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException("导出失败", e); |
| | | } |
| | | } |
| | | |
| | | private void setCellValue(Sheet sheet, int rowIdx, int colIdx, Object value) { |
| | | if (value == null) return; |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null) row = sheet.createRow(rowIdx); |
| | | Cell cell = row.getCell(colIdx); |
| | | if (cell == null) cell = row.createCell(colIdx); |
| | | if (value instanceof Date) { |
| | | cell.setCellValue((Date) value); |
| | | } else if (value instanceof Number) { |
| | | cell.setCellValue(((Number) value).doubleValue()); |
| | | } else { |
| | | cell.setCellValue(value.toString()); |
| | | } |
| | | } |
| | | |
| | | private void createReworkProductionOrder(QualityUnqualifiedOrder order) { |
| | | if (order.getUnqualifiedId() == null) { |
| | | return; |
| | | } |
| | | QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(order.getUnqualifiedId()); |
| | | if (unqualified == null || unqualified.getInspectId() == null) { |
| | | return; |
| | | } |
| | | QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId()); |
| | | if (qualityInspect == null || qualityInspect.getProductMainId() == null) { |
| | | return; |
| | | } |
| | | ProductionProductMain sourceMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId()); |
| | | if (sourceMain == null || sourceMain.getProductionOperationTaskId() == null) { |
| | | return; |
| | | } |
| | | ProductionOperationTask sourceTask = productionOperationTaskMapper.selectById(sourceMain.getProductionOperationTaskId()); |
| | | if (sourceTask == null) { |
| | | return; |
| | | } |
| | | ProductionOrder sourceOrder = productionOrderMapper.selectById(sourceTask.getProductionOrderId()); |
| | | if (sourceOrder == null) { |
| | | return; |
| | | } |
| | | |
| | | BigDecimal reworkQty = order.getUnqualifiedQuantity() != null ? order.getUnqualifiedQuantity() |
| | | : unqualified.getQuantity() != null ? unqualified.getQuantity() : BigDecimal.ONE; |
| | | |
| | | ProductionOrder newOrder = new ProductionOrder(); |
| | | BeanUtils.copyProperties(sourceOrder, newOrder); |
| | | newOrder.setId(null); |
| | | newOrder.setNpsNo(generateNextProductionOrderNo("FG")); |
| | | newOrder.setQuantity(reworkQty); |
| | | newOrder.setCompleteQuantity(BigDecimal.ZERO); |
| | | newOrder.setStartTime(null); |
| | | newOrder.setEndTime(null); |
| | | newOrder.setCreateTime(null); |
| | | newOrder.setUpdateTime(null); |
| | | newOrder.setDisposalMethod(order.getDisposalMethod()); |
| | | productionOrderMapper.insert(newOrder); |
| | | |
| | | Map<Long, Long> routingIdMap = new HashMap<>(); |
| | | List<ProductionOrderRouting> sourceRoutings = productionOrderRoutingMapper.selectList( |
| | | Wrappers.<ProductionOrderRouting>lambdaQuery() |
| | | .eq(ProductionOrderRouting::getProductionOrderId, sourceOrder.getId()) |
| | | .orderByAsc(ProductionOrderRouting::getId)); |
| | | for (ProductionOrderRouting sourceRouting : sourceRoutings) { |
| | | ProductionOrderRouting newRouting = new ProductionOrderRouting(); |
| | | BeanUtils.copyProperties(sourceRouting, newRouting); |
| | | newRouting.setId(null); |
| | | newRouting.setProductionOrderId(newOrder.getId()); |
| | | newRouting.setCreateTime(null); |
| | | newRouting.setUpdateTime(null); |
| | | productionOrderRoutingMapper.insert(newRouting); |
| | | routingIdMap.put(sourceRouting.getId(), newRouting.getId()); |
| | | } |
| | | |
| | | List<ProductionOrderRoutingOperation> sourceOperations = productionOrderRoutingOperationMapper.selectList( |
| | | Wrappers.<ProductionOrderRoutingOperation>lambdaQuery() |
| | | .eq(ProductionOrderRoutingOperation::getProductionOrderId, sourceOrder.getId()) |
| | | .orderByAsc(ProductionOrderRoutingOperation::getDragSort) |
| | | .orderByAsc(ProductionOrderRoutingOperation::getId)); |
| | | for (ProductionOrderRoutingOperation sourceOperation : sourceOperations) { |
| | | ProductionOrderRoutingOperation newOperation = new ProductionOrderRoutingOperation(); |
| | | BeanUtils.copyProperties(sourceOperation, newOperation); |
| | | newOperation.setId(null); |
| | | newOperation.setProductionOrderId(newOrder.getId()); |
| | | newOperation.setOrderRoutingId(routingIdMap.get(sourceOperation.getOrderRoutingId())); |
| | | newOperation.setCreateTime(null); |
| | | newOperation.setUpdateTime(null); |
| | | productionOrderRoutingOperationMapper.insert(newOperation); |
| | | |
| | | ProductionOperationTask newTask = new ProductionOperationTask(); |
| | | newTask.setProductionOrderRoutingOperationId(newOperation.getId()); |
| | | newTask.setProductionOrderId(newOrder.getId()); |
| | | newTask.setPlanQuantity(newOrder.getQuantity()); |
| | | newTask.setCompleteQuantity(BigDecimal.ZERO); |
| | | newTask.setWorkOrderNo(generateNextTaskNo("FG")); |
| | | newTask.setStatus(1); |
| | | productionOperationTaskMapper.insert(newTask); |
| | | } |
| | | } |
| | | |
| | | private String generateNextProductionOrderNo(String prefix) { |
| | | String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); |
| | | String orderPrefix = prefix + datePrefix; |
| | | ProductionOrder latestOrder = productionOrderMapper.selectOne( |
| | | Wrappers.<ProductionOrder>lambdaQuery() |
| | | .likeRight(ProductionOrder::getNpsNo, orderPrefix) |
| | | .orderByDesc(ProductionOrder::getNpsNo) |
| | | .last("limit 1")); |
| | | int sequence = 1; |
| | | if (latestOrder != null && latestOrder.getNpsNo() != null && latestOrder.getNpsNo().startsWith(orderPrefix)) { |
| | | try { |
| | | sequence = Integer.parseInt(latestOrder.getNpsNo().substring(orderPrefix.length())) + 1; |
| | | } catch (NumberFormatException ignored) { |
| | | sequence = 1; |
| | | } |
| | | } |
| | | return orderPrefix + String.format("%04d", sequence); |
| | | } |
| | | |
| | | private String generateNextTaskNo(String prefix) { |
| | | String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); |
| | | String taskPrefix = prefix + datePrefix; |
| | | ProductionOperationTask latestTask = productionOperationTaskMapper.selectOne( |
| | | Wrappers.<ProductionOperationTask>lambdaQuery() |
| | | .likeRight(ProductionOperationTask::getWorkOrderNo, taskPrefix) |
| | | .orderByDesc(ProductionOperationTask::getWorkOrderNo) |
| | | .last("limit 1")); |
| | | int sequence = 1; |
| | | if (latestTask != null && latestTask.getWorkOrderNo() != null && latestTask.getWorkOrderNo().startsWith(taskPrefix)) { |
| | | try { |
| | | sequence = Integer.parseInt(latestTask.getWorkOrderNo().substring(taskPrefix.length())) + 1; |
| | | } catch (NumberFormatException ignored) { |
| | | sequence = 1; |
| | | } |
| | | } |
| | | return taskPrefix + String.format("%03d", sequence); |
| | | } |
| | | } |