gaoluyang
5 天以前 6fa82a1ad7c3ae061ef499f0d0806a16846e122b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package cn.iocoder.yudao.module.mes.service.qc.ncr;
 
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ncr.MesQcNcrDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ncr.MesQcPurchaseReturnDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.ncr.MesQcPurchaseReturnMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.ncr.MesQcPurchaseConcessionMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnvendor.MesWmReturnVendorLineMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnvendor.MesWmReturnVendorMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnVendorStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Objects;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
@Service
public class MesQcPurchaseReturnService {
    /** 采购退货单编码规则(MesMdAutoCodeRule 中的 code) */
    private static final String RETURN_VENDOR_CODE_RULE = "WM_RETURN_VENDOR_CODE";
 
    @Resource private MesQcNcrPurchaseSourceValidator sourceValidator;
    @Resource private MesQcPurchaseReturnMapper mapper;
    @Resource private MesQcPurchaseConcessionMapper concessionMapper;
    @Resource private MesQcArrivalDispositionService arrivalDispositionService;
    @Resource private MesWmReturnVendorMapper returnVendorMapper;
    @Resource private MesWmReturnVendorLineMapper returnVendorLineMapper;
    @Resource private MesMdAutoCodeRecordService autoCodeRecordService;
 
    /** 必须由已锁定 NCR 的处置事务调用。 */
    @Transactional(rollbackFor = Exception.class)
    public MesQcPurchaseReturnDO createForNcr(MesQcNcrDO ncr) {
        if (mapper.selectByNcrId(ncr.getId()) != null)
            throw new ServiceException(400, "该不合格单已生成采购退货单");
        var source = sourceValidator.validate(ncr);
        if (concessionMapper.selectByIqcId(ncr.getQcId()) != null || mapper.selectByIqcId(ncr.getQcId()) != null)
            throw new ServiceException(400, "该来料检验已有采购处置单,不能重复处置");
        if (source.notice().getVendorId() == null || source.notice().getPurchaseOrderId() == null
                || source.line().getPurchaseOrderItemId() == null)
            throw new ServiceException(400, "到货单缺少供应商、采购订单或采购明细,无法生成可追溯退货单");
 
        // 1. 生成「供应商退货单」:不合格品从未入库,不产生库存出库,也无需拣货与审批,
        //    直接以已完成状态落到采购仓库-采购退货列表中,供仓库/采购追溯并按实物退回供应商。
        String code = autoCodeRecordService.generateAutoCode(RETURN_VENDOR_CODE_RULE, null);
        MesWmReturnVendorDO vendorReturn = new MesWmReturnVendorDO();
        vendorReturn.setCode(code);
        vendorReturn.setName("来料不合格退货-" + ncr.getCode());
        vendorReturn.setPurchaseOrderId(source.notice().getPurchaseOrderId());
        vendorReturn.setPurchaseOrderCode(source.notice().getPurchaseOrderCode());
        vendorReturn.setContractNo(source.notice().getContractNo());
        vendorReturn.setVendorId(source.notice().getVendorId());
        vendorReturn.setReturnDate(LocalDateTime.now());
        vendorReturn.setReturnReason("来料检验不合格");
        vendorReturn.setStatus(MesWmReturnVendorStatusEnum.FINISHED.getStatus());
        vendorReturn.setRemark("由来料不合格单 " + ncr.getCode() + "(来料检验 " + source.iqc().getCode()
                + ")退货处置自动生成;不合格品未入库,无需拣货,单据直接完成。");
        returnVendorMapper.insert(vendorReturn);
        MesWmReturnVendorLineDO vendorReturnLine = new MesWmReturnVendorLineDO();
        vendorReturnLine.setReturnId(vendorReturn.getId());
        vendorReturnLine.setItemId(ncr.getItemId());
        vendorReturnLine.setQuantity(ncr.getUnqualifiedQuantity());
        vendorReturnLine.setBatchCode(StrUtil.blankToDefault(source.iqc().getVendorBatch(), null));
        vendorReturnLine.setRemark("来料检验 " + source.iqc().getCode() + " 不合格数量");
        returnVendorLineMapper.insert(vendorReturnLine);
 
        // 2. 记录质量侧处置台账(与退货单同号),因退货单已直接完成,这里同步标记为已确认,
        //    不合格单关闭时校验的正是这条记录。
        MesQcPurchaseReturnDO doc = new MesQcPurchaseReturnDO();
        doc.setCode(code);
        doc.setNcrId(ncr.getId());
        doc.setIqcId(ncr.getQcId());
        doc.setNoticeId(source.notice().getId());
        doc.setNoticeLineId(source.line().getId());
        doc.setPurchaseOrderId(source.notice().getPurchaseOrderId());
        doc.setPurchaseOrderItemId(source.line().getPurchaseOrderItemId());
        doc.setVendorId(source.notice().getVendorId());
        doc.setItemId(ncr.getItemId());
        doc.setVendorBatch(source.iqc().getVendorBatch());
        doc.setQuantity(ncr.getUnqualifiedQuantity());
        doc.setStatus(1);
        doc.setConfirmedBy(getLoginUserId());
        doc.setConfirmedAt(LocalDateTime.now());
        doc.setConfirmationRemark("随不合格处置自动生成采购退货单 " + code + ",未发生库存出库");
        mapper.insert(doc);
        arrivalDispositionService.refresh(source.notice().getId());
        return doc;
    }
 
    public MesQcPurchaseReturnDO getByNcrId(Long ncrId) { return mapper.selectByNcrId(ncrId); }
 
    public PageResult<MesQcPurchaseReturnDO> getPage(PageParam page, Integer status) {
        if (status != null && status != 0 && status != 1) throw new ServiceException(400, "采购退货状态无效");
        return mapper.selectPage(page, status);
    }
 
    @Transactional(rollbackFor = Exception.class)
    public void confirm(Long id, String remark) {
        MesQcPurchaseReturnDO doc = mapper.selectByIdForUpdate(id);
        if (doc == null) throw new ServiceException(400, "采购退货单不存在");
        if (!Objects.equals(doc.getStatus(), 0)) throw new ServiceException(400, "采购退货单已确认退货");
        mapper.updateById(new MesQcPurchaseReturnDO().setId(id).setStatus(1)
                .setConfirmedBy(getLoginUserId()).setConfirmedAt(LocalDateTime.now()).setConfirmationRemark(remark));
        arrivalDispositionService.refresh(doc.getNoticeId());
    }
 
    public void validateConfirmed(Long ncrId) {
        MesQcPurchaseReturnDO doc = mapper.selectByNcrId(ncrId);
        if (doc == null || !Objects.equals(doc.getStatus(), 1))
            throw new ServiceException(400, "请先由采购仓库确认采购退货完成,再关闭不合格单");
    }
}