4 天以前 741918a903e17b2ec7522556d2c043b8d35dd8a1
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedOrderServiceImpl.java
@@ -1,15 +1,48 @@
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
@@ -17,6 +50,13 @@
    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) {
@@ -31,4 +71,277 @@
        }
        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);
    }
}