package cn.iocoder.yudao.module.mes.service.qc.ncr;
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrPageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ncr.MesQcNcrDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.qc.ncr.MesQcNcrMapper;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesNcrStatusEnum;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
|
import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService;
|
import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
|
import jakarta.annotation.Resource;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.time.LocalDateTime;
|
import java.util.Collection;
|
import java.util.Map;
|
import java.util.Objects;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
/**
|
* MES 不合格品处理单(NCR) Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesQcNcrServiceImpl implements MesQcNcrService {
|
|
@Resource
|
private MesQcNcrMapper ncrMapper;
|
|
@Resource
|
private MdmItemApi mdmItemApi;
|
|
@Resource
|
@Lazy
|
private MesQcIqcService iqcService;
|
@Resource
|
@Lazy
|
private MesQcIpqcService ipqcService;
|
@Resource
|
@Lazy
|
private MesQcOqcService oqcService;
|
@Resource
|
@Lazy
|
private MesQcRqcService rqcService;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Long createNcr(MesQcNcrSaveReqVO createReqVO) {
|
// 1. 校验数据
|
validateNcrCodeUnique(null, createReqVO.getCode());
|
validateItemExists(createReqVO.getItemId());
|
|
// 2. 插入主表
|
MesQcNcrDO ncr = BeanUtils.toBean(createReqVO, MesQcNcrDO.class)
|
.setStatus(MesNcrStatusEnum.PENDING_REVIEW.getStatus());
|
// 如果传入了 qcId 和 qcType,则查询来源检验单编号并冗余存储
|
if (createReqVO.getQcType() != null && createReqVO.getQcId() != null) {
|
ncr.setQcCode(lookupQcCode(createReqVO.getQcType(), createReqVO.getQcId()));
|
}
|
ncrMapper.insert(ncr);
|
return ncr.getId();
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void updateNcr(MesQcNcrSaveReqVO updateReqVO) {
|
// 1. 校验存在 + 只允许待评审状态编辑
|
MesQcNcrDO ncr = validateNcrStatusPendingReview(updateReqVO.getId());
|
validateNcrCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
|
validateItemExists(updateReqVO.getItemId());
|
|
// 2. 更新主表(仅允许更新部分字段)
|
MesQcNcrDO updateObj = BeanUtils.toBean(updateReqVO, MesQcNcrDO.class);
|
updateObj.setQcType(null); // 不允许修改检验类型
|
updateObj.setQcId(null); // 不允许修改检验单
|
updateObj.setStatus(null); // 不允许修改状态
|
ncrMapper.updateById(updateObj);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteNcr(Long id) {
|
// 校验存在 + 只允许删除待评审状态
|
validateNcrStatusPendingReview(id);
|
ncrMapper.deleteById(id);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void reviewNcr(Long id, Integer disposition, Long responsibleDeptId,
|
Integer defectLevel, String reviewOpinion) {
|
// 1. 校验存在 + 待评审状态
|
validateNcrStatusPendingReview(id);
|
|
// 2. 更新评审信息
|
MesQcNcrDO updateObj = new MesQcNcrDO()
|
.setId(id)
|
.setDisposition(disposition)
|
.setResponsibleDeptId(responsibleDeptId)
|
.setReviewOpinion(reviewOpinion)
|
.setReviewerUserId(getLoginUserId())
|
.setReviewDate(LocalDateTime.now())
|
.setStatus(MesNcrStatusEnum.REVIEWED.getStatus());
|
if (defectLevel != null) {
|
updateObj.setDefectLevel(defectLevel);
|
}
|
ncrMapper.updateById(updateObj);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void disposeNcr(Long id, Long handlerUserId, String handleResult) {
|
// 1. 校验存在 + 已评审状态
|
MesQcNcrDO ncr = validateNcrExists(id);
|
if (!MesNcrStatusEnum.REVIEWED.getStatus().equals(ncr.getStatus())) {
|
throw exception(QC_NCR_NOT_REVIEWED);
|
}
|
|
// 2. 更新处置信息
|
// TODO: WM 模块集成 — 处置为退货时触发供应商退货,处置为报废时触发杂项出库
|
ncrMapper.updateById(new MesQcNcrDO()
|
.setId(id)
|
.setHandlerUserId(handlerUserId)
|
.setHandleDate(LocalDateTime.now())
|
.setHandleResult(handleResult)
|
.setStatus(MesNcrStatusEnum.DISPOSED.getStatus()));
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void closeNcr(Long id, String closeOpinion) {
|
// 1. 校验存在 + 已处置状态
|
MesQcNcrDO ncr = validateNcrExists(id);
|
if (!MesNcrStatusEnum.DISPOSED.getStatus().equals(ncr.getStatus())) {
|
throw exception(QC_NCR_NOT_DISPOSED);
|
}
|
|
// 2. 更新关闭信息
|
ncrMapper.updateById(new MesQcNcrDO()
|
.setId(id)
|
.setCloseUserId(getLoginUserId())
|
.setCloseDate(LocalDateTime.now())
|
.setCloseOpinion(closeOpinion)
|
.setStatus(MesNcrStatusEnum.CLOSED.getStatus()));
|
}
|
|
// ==================== 校验方法 ====================
|
|
@Override
|
public MesQcNcrDO validateNcrExists(Long id) {
|
MesQcNcrDO ncr = ncrMapper.selectById(id);
|
if (ncr == null) {
|
throw exception(QC_NCR_NOT_EXISTS);
|
}
|
return ncr;
|
}
|
|
/**
|
* 校验 NCR 存在且为待评审状态
|
*/
|
private MesQcNcrDO validateNcrStatusPendingReview(Long id) {
|
MesQcNcrDO ncr = validateNcrExists(id);
|
if (!MesNcrStatusEnum.PENDING_REVIEW.getStatus().equals(ncr.getStatus())) {
|
throw exception(QC_NCR_NOT_PENDING_REVIEW);
|
}
|
return ncr;
|
}
|
|
/**
|
* 校验 NCR 编号唯一
|
*/
|
private void validateNcrCodeUnique(Long id, String code) {
|
MesQcNcrDO existing = ncrMapper.selectByCode(code);
|
if (existing != null && !existing.getId().equals(id)) {
|
throw exception(QC_NCR_CODE_DUPLICATE);
|
}
|
}
|
|
/**
|
* 校验物料存在
|
*/
|
private void validateItemExists(Long itemId) {
|
if (itemId != null) {
|
mdmItemApi.getItem(itemId).getCheckedData();
|
}
|
}
|
|
/**
|
* 根据检验类型和检验单 ID 查询来源检验单编号
|
*/
|
private String lookupQcCode(Integer qcType, Long qcId) {
|
if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
|
return iqcService.getIqc(qcId).getCode();
|
} else if (Objects.equals(qcType, MesQcTypeEnum.IPQC.getType())) {
|
return ipqcService.getIpqc(qcId).getCode();
|
} else if (Objects.equals(qcType, MesQcTypeEnum.OQC.getType())) {
|
return oqcService.getOqc(qcId).getCode();
|
} else if (Objects.equals(qcType, MesQcTypeEnum.RQC.getType())) {
|
return rqcService.getRqc(qcId).getCode();
|
}
|
return null;
|
}
|
|
// ==================== 查询方法 ====================
|
|
@Override
|
public MesQcNcrDO getNcr(Long id) {
|
return ncrMapper.selectById(id);
|
}
|
|
@Override
|
public PageResult<MesQcNcrDO> getNcrPage(MesQcNcrPageReqVO pageReqVO) {
|
return ncrMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public Map<Long, MesQcNcrDO> getNcrMap(Collection<Long> ids) {
|
return convertMap(ncrMapper.selectBatchIds(ids), MesQcNcrDO::getId);
|
}
|
|
}
|