liu
2026-10-27 17ce55a3b038ed61d332bb54916de4fa55ba19c6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
@@ -32,6 +32,8 @@
import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService;
import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService;
import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrSaveReqVO;
import cn.iocoder.yudao.module.mes.service.qc.ncr.MesQcNcrService;
import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
@@ -48,16 +50,30 @@
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcImportExcelVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcImportRespVO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.date.DateUtil;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * MES 过程检验单(IPQC) Service 实现类
 *
 * @author 芋道源码
 * @author 超级管理员
 */
@Service
@Validated
@Slf4j
public class MesQcIpqcServiceImpl implements MesQcIpqcService {
    @Resource
    private MesMdWorkstationMapper workstationMapper;
    /**
     * IPQC 保存数据校验上下文
@@ -104,6 +120,10 @@
    @Resource
    @Lazy
    private MesWmProductProduceLineService productProduceLineService;
    @Resource
    @Lazy
    private MesQcNcrService ncrService;
    @Resource
    private AdminUserApi adminUserApi;
@@ -216,8 +236,32 @@
        ipqcMapper.updateById(new MesQcIpqcDO()
                .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()));
        // 3. 回写来源单据
        // 3. 不合格时自动创建 NCR
        generateNcrIfNeeded(ipqc);
        // 4. 回写来源单据
        writeBackSourceDoc(ipqc);
    }
    /**
     * 不合格时自动创建 NCR(不合格品处理单)
     *
     * @param ipqc 过程检验单
     */
    private void generateNcrIfNeeded(MesQcIpqcDO ipqc) {
        BigDecimal unqualifiedQty = ipqc.getUnqualifiedQuantity();
        if (unqualifiedQty == null || unqualifiedQty.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        MesQcNcrSaveReqVO saveReqVO = new MesQcNcrSaveReqVO();
        saveReqVO.setName("不合格品处理单");
        saveReqVO.setQcType(MesQcTypeEnum.IPQC.getType());
        saveReqVO.setQcId(ipqc.getId());
        saveReqVO.setItemId(ipqc.getItemId());
        saveReqVO.setUnqualifiedQuantity(unqualifiedQty);
        saveReqVO.setDefectDescription("由过程检验(" + ipqc.getCode() + ")自动生成");
        ncrService.createNcr(saveReqVO);
        log.info("[generateNcrIfNeeded] IPQC({}) 不合格,自动创建 NCR", ipqc.getId());
    }
    /**
@@ -410,4 +454,75 @@
        ipqcMapper.updateById(updateIpqc);
    }
    @Override
    public MesQcIpqcImportRespVO importIpqcList(List<MesQcIpqcImportExcelVO> importList, boolean updateSupport) {
        if (CollUtil.isEmpty(importList)) {
            throw exception(QC_IPQC_IMPORT_LIST_IS_EMPTY);
        }
        MesQcIpqcImportRespVO respVO = MesQcIpqcImportRespVO.builder()
                .createCodes(new ArrayList<>()).updateCodes(new ArrayList<>())
                .failureCodes(new LinkedHashMap<>()).build();
        AtomicInteger index = new AtomicInteger(1);
        importList.forEach(importItem -> {
            int currentIndex = index.getAndIncrement();
            String key = "第 " + currentIndex + " 行";
            if (StrUtil.isBlank(importItem.getWorkOrderCode())) {
                respVO.getFailureCodes().put(key, "生产工单编码不能为空");
                return;
            }
            if (StrUtil.isBlank(importItem.getWorkstationCode())) {
                respVO.getFailureCodes().put(key, "工位编码不能为空");
                return;
            }
            MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(importItem.getWorkOrderCode());
            if (workOrder == null) {
                respVO.getFailureCodes().put(key, "生产工单不存在:" + importItem.getWorkOrderCode());
                return;
            }
            MesMdWorkstationDO workstation = workstationMapper.selectByCode(importItem.getWorkstationCode());
            if (workstation == null) {
                respVO.getFailureCodes().put(key, "工位不存在:" + importItem.getWorkstationCode());
                return;
            }
            if (importItem.getCheckQuantity() == null || importItem.getQualifiedQuantity() == null || importItem.getUnqualifiedQuantity() == null) {
                respVO.getFailureCodes().put(key, "检测数量、合格品数量、不合格品数量均不能为空");
                return;
            }
            if (importItem.getCheckQuantity().compareTo(importItem.getQualifiedQuantity().add(importItem.getUnqualifiedQuantity())) != 0) {
                respVO.getFailureCodes().put(key, "检测数量必须等于合格品数量与不合格品数量之和");
                return;
            }
            BigDecimal scrapSum = ObjUtil.defaultIfNull(importItem.getLaborScrapQuantity(), BigDecimal.ZERO)
                    .add(ObjUtil.defaultIfNull(importItem.getMaterialScrapQuantity(), BigDecimal.ZERO))
                    .add(ObjUtil.defaultIfNull(importItem.getOtherScrapQuantity(), BigDecimal.ZERO));
            if (scrapSum.compareTo(importItem.getUnqualifiedQuantity()) > 0) {
                respVO.getFailureCodes().put(key, "工废、料废、其他废品数量之和不能超过不合格品数量");
                return;
            }
            try {
                MesQcIpqcSaveReqVO createReqVO = BeanUtils.toBean(importItem, MesQcIpqcSaveReqVO.class);
                createReqVO.setCode(generateImportCode("IPQC", index));
                createReqVO.setName(StrUtil.blankToDefault(importItem.getName(), "过程检验单"));
                createReqVO.setWorkOrderId(workOrder.getId());
                createReqVO.setWorkstationId(workstation.getId());
                createReqVO.setType(ObjUtil.defaultIfNull(importItem.getType(), 1));
                createReqVO.setLaborScrapQuantity(ObjUtil.defaultIfNull(importItem.getLaborScrapQuantity(), BigDecimal.ZERO));
                createReqVO.setMaterialScrapQuantity(ObjUtil.defaultIfNull(importItem.getMaterialScrapQuantity(), BigDecimal.ZERO));
                createReqVO.setOtherScrapQuantity(ObjUtil.defaultIfNull(importItem.getOtherScrapQuantity(), BigDecimal.ZERO));
                Long id = createIpqc(createReqVO);
                MesQcIpqcDO created = ipqcMapper.selectById(id);
                respVO.getCreateCodes().add(created != null && StrUtil.isNotBlank(created.getCode()) ? created.getCode() : key);
            } catch (ServiceException e) {
                respVO.getFailureCodes().put(key, e.getMessage());
            }
        });
        return respVO;
    }
    private String generateImportCode(String prefix, AtomicInteger seq) {
        return prefix + DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss")
                + String.format("%03d", seq.incrementAndGet());
    }
}