liyong
4 小时以前 e978a226c2c1b22c9172a58539d876b298e9e2da
物料删除校验
已添加2个文件
已修改9个文件
303 ■■■■ 文件已修改
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/resources/mapper/purchase/ErpSupplierMapper.xml 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/ErrorCodeConstants.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/resources/mapper/item/MdmItemMapper.xml 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptDO.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java
@@ -6,8 +6,10 @@
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * ERP ä¾›åº”商 Mapper
@@ -29,4 +31,12 @@
        return selectList(ErpSupplierDO::getStatus, status);
    }
    /**
     * æŸ¥è¯¢ä¾›åº”商被哪些业务表引用(未删除的记录)
     *
     * @param supplierId ä¾›åº”商编号
     * @return å¼•用来源列表,每项包含 source(来源名) å’Œ cnt(引用数量),仅返回 cnt > 0 çš„
     */
    List<Map<String, Object>> selectSupplierReferenceCount(@Param("supplierId") Long supplierId);
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -12,6 +12,7 @@
    // ========== ERP ä¾›åº”商(1-030-100-000) ==========
    ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_100_000, "供应商不存在");
    ErrorCode SUPPLIER_NOT_ENABLE = new ErrorCode(1_030_100_000, "供应商({})未启用");
    ErrorCode SUPPLIER_EXISTS_REFERENCE = new ErrorCode(1_030_100_001, "供应商已被业务引用,无法删除");
    // ========== ERP é‡‡è´­è®¢å•(1-030-101-000) ==========
    ErrorCode PURCHASE_ORDER_NOT_EXISTS = new ErrorCode(1_030_101_000, "采购订单不存在");
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java
@@ -14,6 +14,8 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
@@ -50,10 +52,27 @@
    public void deleteSupplier(Long id) {
        // æ ¡éªŒå­˜åœ¨
        validateSupplierExists(id);
        // æ ¡éªŒä¾›åº”商是否被业务引用
        validateSupplierNoReference(id);
        // åˆ é™¤
        supplierMapper.deleteById(id);
    }
    /**
     * æ ¡éªŒä¾›åº”商未被业务引用(采购、质检、生产、库存等)
     *
     * @param id ä¾›åº”商编号
     */
    private void validateSupplierNoReference(Long id) {
        List<Map<String, Object>> references = supplierMapper.selectSupplierReferenceCount(id);
        if (CollUtil.isNotEmpty(references)) {
            String refDesc = references.stream()
                    .map(r -> r.get("source") + "(" + r.get("cnt") + ")")
                    .collect(Collectors.joining("、"));
            throw exception(SUPPLIER_EXISTS_REFERENCE, refDesc);
        }
    }
    private void validateSupplierExists(Long id) {
        if (supplierMapper.selectById(id) == null) {
            throw exception(SUPPLIER_NOT_EXISTS);
yudao-module-erp/src/main/resources/mapper/purchase/ErpSupplierMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpSupplierMapper">
    <!--
        æŸ¥è¯¢ä¾›åº”商被哪些业务表引用(未删除的记录)
        ERP æ¨¡å—用 supplier_id,MES æ¨¡å—用 vendor_id
        è¿”回有引用的来源名和引用数量,用于删除校验
    -->
    <select id="selectSupplierReferenceCount" resultType="map">
        SELECT source, cnt FROM (
            <!-- ERP:采购订单 -->
            SELECT '采购-采购订单' AS source, COUNT(*) AS cnt FROM erp_purchase_order WHERE supplier_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- ERP:采购申请 -->
            SELECT '采购-采购申请' AS source, COUNT(*) AS cnt FROM erp_purchase_request WHERE supplier_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- ERP:付款单 -->
            SELECT '采购-付款单' AS source, COUNT(*) AS cnt FROM erp_finance_payment WHERE supplier_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- MES:到货通知 -->
            SELECT '采购-到货通知' AS source, COUNT(*) AS cnt FROM mes_wm_arrival_notice WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- MES:采购入库 -->
            SELECT '采购-采购入库' AS source, COUNT(*) AS cnt FROM mes_wm_item_receipt WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- MES:委外入库 -->
            SELECT '采购-委外入库' AS source, COUNT(*) AS cnt FROM mes_wm_outsource_receipt WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- MES:委外发料 -->
            SELECT '采购-委外发料' AS source, COUNT(*) AS cnt FROM mes_wm_outsource_issue WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- MES:采购退货 -->
            SELECT '采购-采购退货' AS source, COUNT(*) AS cnt FROM mes_wm_return_vendor WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- è´¨æ£€ï¼šIQC -->
            SELECT '质检-IQC' AS source, COUNT(*) AS cnt FROM mes_qc_iqc WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- ç”Ÿäº§ï¼šå·¥å• -->
            SELECT '生产-工单' AS source, COUNT(*) AS cnt FROM mes_pro_work_order WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- åº“存:库存 -->
            SELECT '库存-库存' AS source, COUNT(*) AS cnt FROM mes_wm_material_stock WHERE vendor_id = #{supplierId} AND deleted = 0
            UNION ALL
            <!-- åº“存:批次 -->
            SELECT '库存-批次' AS source, COUNT(*) AS cnt FROM mes_wm_batch WHERE vendor_id = #{supplierId} AND deleted = 0
        ) t
        WHERE t.cnt > 0
        ORDER BY t.source
    </select>
</mapper>
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemMapper.java
@@ -6,9 +6,11 @@
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
 * MDM ç‰©æ–™ä¸»æ•°æ® Mapper
@@ -81,4 +83,12 @@
        return selectList(MdmItemDO::getId, ids);
    }
    /**
     * æŸ¥è¯¢ç‰©æ–™è¢«å“ªäº›ä¸šåŠ¡è¡¨å¼•ç”¨ï¼ˆæœªåˆ é™¤çš„è®°å½•ï¼‰
     *
     * @param itemId ç‰©æ–™ç¼–号
     * @return å¼•用来源列表,每项包含 source(来源名) å’Œ cnt(引用数量),仅返回 cnt > 0 çš„
     */
    List<Map<String, Object>> selectItemReferenceCount(@Param("itemId") Long itemId);
}
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/ErrorCodeConstants.java
@@ -16,6 +16,7 @@
    ErrorCode MDM_ITEM_SKU_NOT_EXISTS = new ErrorCode(1_050_004, "物料SKU不存在");
    ErrorCode MDM_ITEM_SKU_IS_DISABLE = new ErrorCode(1_050_005, "物料SKU已禁用");
    ErrorCode MDM_ITEM_SKU_CODE_DUPLICATE = new ErrorCode(1_050_006, "SKU编码已存在");
    ErrorCode MDM_ITEM_EXISTS_REFERENCE = new ErrorCode(1_050_007, "物料已被业务引用,无法删除");
    // ========== ç‰©æ–™åˆ†ç±»ç›¸å…³ 1-050-051 ~ 1-050-100 ==========
    ErrorCode MDM_ITEM_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_051, "物料分类不存在");
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
@@ -177,15 +177,27 @@
    public void deleteItem(Long id) {
        // æ ¡éªŒå­˜åœ¨
        MdmItemDO item = validateItemExists(id);
        // è§£å†³è½¯åˆ é™¤å”¯ä¸€é”®å†²çªï¼šå¦‚果已存在相同 code ä¸”已软删除的记录,先物理删除它
//        MdmItemDO existingDeleted = itemMapper.selectByCodeAndDeleted(item.getCode(), true);
//        if (existingDeleted != null && !existingDeleted.getId().equals(id)) {
//            itemMapper.physicalDeleteById(existingDeleted.getId());
//        }
        // æ ¡éªŒç‰©æ–™æ˜¯å¦è¢«ä¸šåŠ¡å¼•ç”¨
        validateItemNoReference(id);
        // è½¯åˆ é™¤å½“前记录
        itemMapper.deleteById(id);
    }
    /**
     * æ ¡éªŒç‰©æ–™æœªè¢«ä¸šåŠ¡å¼•ç”¨ï¼ˆé”€å”®ã€é‡‡è´­ã€ç”Ÿäº§ã€è´¨æ£€ã€åº“å­˜ç­‰ï¼‰
     *
     * @param id ç‰©æ–™ç¼–号
     */
    private void validateItemNoReference(Long id) {
        List<Map<String, Object>> references = itemMapper.selectItemReferenceCount(id);
        if (CollUtil.isNotEmpty(references)) {
            String refDesc = references.stream()
                    .map(r -> r.get("source") + "(" + r.get("cnt") + ")")
                    .collect(Collectors.joining("、"));
            throw exception(MDM_ITEM_EXISTS_REFERENCE, refDesc);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteItemList(Collection<Long> ids) {
yudao-module-mdm/src/main/resources/mapper/item/MdmItemMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper">
    <!--
        æŸ¥è¯¢ç‰©æ–™è¢«å“ªäº›ä¸šåŠ¡è¡¨å¼•ç”¨ï¼ˆæœªåˆ é™¤çš„è®°å½•ï¼‰
        è¿”回有引用的表名和引用数量,用于删除校验
    -->
    <select id="selectItemReferenceCount" resultType="map">
        SELECT source, cnt FROM (
            <!-- ç”Ÿäº§ï¼šå·¥å•BOM -->
            SELECT '生产-工单BOM' AS source, COUNT(*) AS cnt FROM mes_pro_work_order_bom WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ç”Ÿäº§ï¼šæŠ¥å·¥ -->
            SELECT '生产-报工' AS source, COUNT(*) AS cnt FROM mes_pro_feedback WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ç”Ÿäº§ï¼šç”Ÿäº§ä»»åŠ¡ -->
            SELECT '生产-生产任务' AS source, COUNT(*) AS cnt FROM mes_pro_task WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ç”Ÿäº§ï¼šå·¥è‰ºè·¯çº¿äº§å“ -->
            SELECT '生产-工艺路线' AS source, COUNT(*) AS cnt FROM mes_pro_route_product WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ç”Ÿäº§ï¼šå·¥è‰ºè·¯çº¿BOM -->
            SELECT '生产-工艺路线BOM' AS source, COUNT(*) AS cnt FROM mes_pro_route_product_bom WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- è´¨æ£€ï¼šIQC -->
            SELECT '质检-IQC' AS source, COUNT(*) AS cnt FROM mes_qc_iqc WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- è´¨æ£€ï¼šIPQC -->
            SELECT '质检-IPQC' AS source, COUNT(*) AS cnt FROM mes_qc_ipqc WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- è´¨æ£€ï¼šOQC -->
            SELECT '质检-OQC' AS source, COUNT(*) AS cnt FROM mes_qc_oqc WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- è´¨æ£€ï¼šRQC -->
            SELECT '质检-RQC' AS source, COUNT(*) AS cnt FROM mes_qc_rqc WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- é‡‡è´­ï¼šåˆ°è´§é€šçŸ¥è¡Œ -->
            SELECT '采购-到货通知' AS source, COUNT(*) AS cnt FROM mes_wm_arrival_notice_line WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- é‡‡è´­ï¼šé‡‡è´­å…¥åº“行 -->
            SELECT '采购-采购入库' AS source, COUNT(*) AS cnt FROM mes_wm_item_receipt_line WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- é”€å”®ï¼šé”€å”®é€šçŸ¥è¡Œ -->
            SELECT '销售-销售通知' AS source, COUNT(*) AS cnt FROM mes_wm_sales_notice_line WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- é”€å”®ï¼šé”€å”®å‡ºåº“行 -->
            SELECT '销售-销售出库' AS source, COUNT(*) AS cnt FROM mes_wm_product_sales_line WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- é”€å”®ï¼šé”€å”®é€€è´§è¡Œ -->
            SELECT '销售-销售退货' AS source, COUNT(*) AS cnt FROM mes_wm_return_sales_line WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- åº“存:库存记录 -->
            SELECT '库存-库存' AS source, COUNT(*) AS cnt FROM mes_wm_material_stock WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- CRM:销售报价产品 -->
            SELECT '销售-报价单' AS source, COUNT(*) AS cnt FROM crm_sale_quotation_product WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- CRM:商机产品 -->
            SELECT '销售-商机' AS source, COUNT(*) AS cnt FROM crm_business_product WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- CRM:合同产品 -->
            SELECT '销售-合同' AS source, COUNT(*) AS cnt FROM crm_contract_product WHERE item_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ERP:采购订单明细(product_id å¼•用物料) -->
            SELECT '采购-采购订单' AS source, COUNT(*) AS cnt FROM erp_purchase_order_items WHERE product_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ERP:采购申请明细(product_id å¼•用物料) -->
            SELECT '采购-采购申请' AS source, COUNT(*) AS cnt FROM erp_purchase_request_items WHERE product_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ERP:销售订单明细(product_id å¼•用物料) -->
            SELECT '销售-销售订单' AS source, COUNT(*) AS cnt FROM erp_sale_order_items WHERE product_id = #{itemId} AND deleted = 0
            UNION ALL
            <!-- ç”Ÿäº§ï¼šå·¥å•产品(product_id å¼•用物料) -->
            SELECT '生产-生产工单' AS source, COUNT(*) AS cnt FROM mes_pro_work_order WHERE product_id = #{itemId} AND deleted = 0
        ) t
        WHERE t.cnt > 0
        ORDER BY t.source
    </select>
</mapper>
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptDO.java
@@ -57,6 +57,13 @@
     */
    private String purchaseOrderCode;
    /**
     * é‡‡è´­è®¢å•编号
     *
     * å…³è” ERP {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO#getId()}
     * ä»Žåˆ°è´§é€šçŸ¥å•带入,用于入库完成时回写采购订单入库数量
     */
    private Long purchaseOrderId;
    /**
     * ä¾›åº”商编号
     *
     * å…³è” ERP ä¾›åº”商 {@link cn.iocoder.yudao.module.erp.api.purchase.dto.ErpSupplierRespDTO#getId()}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
@@ -20,6 +20,7 @@
import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
@@ -34,6 +35,7 @@
import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -54,6 +56,7 @@
 */
@Service
@Validated
@Slf4j
public class MesQcIpqcServiceImpl implements MesQcIpqcService {
    /**
@@ -225,25 +228,34 @@
     * @param ipqc è¿‡ç¨‹æ£€éªŒå•
     */
    private void writeBackSourceDoc(MesQcIpqcDO ipqc) {
        if (ipqc.getSourceDocType() == null) {
            return;
        }
        if (ipqc.getSourceDocId() == null) {
            throw new IllegalArgumentException(
                    "IPQC å•[" + ipqc.getId() + "] sourceDocType éžç©ºä½† sourceDocId ä¸ºç©º");
        // 1. ç¡®å®š sourceDocType/sourceDocId
        Long sourceDocId = ipqc.getSourceDocId();
        Long sourceLineId = ipqc.getSourceLineId();
        // å¦‚æžœ IPQC å•没有设置来源,尝试通过 taskId æŸ¥æ‰¾å…³è”的待检验报工
        if (sourceDocId == null && ipqc.getTaskId() != null) {
            MesProFeedbackDO feedback = feedbackService.getFeedbackListByTaskId(ipqc.getTaskId()).stream()
                    .filter(f -> MesProFeedbackStatusEnum.UNCHECK.getStatus().equals(f.getStatus()))
                    .findFirst().orElse(null);
            if (feedback != null) {
                sourceDocId = feedback.getId();
                log.info("[writeBackSourceDoc] IPQC({}) æœªè®¾ç½®æ¥æºå•据,通过 taskId({}) æ‰¾åˆ°å¾…检验报工({})",
                        ipqc.getId(), ipqc.getTaskId(), feedback.getId());
            }
        }
        if (Objects.equals(ipqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)) {
            feedbackService.updateProFeedbackWhenIpqcFinish(ipqc.getSourceDocId(), ipqc.getSourceLineId(),
                    ObjectUtil.defaultIfNull(ipqc.getQualifiedQuantity(), BigDecimal.ZERO),
                    ObjectUtil.defaultIfNull(ipqc.getUnqualifiedQuantity(), BigDecimal.ZERO),
                    ObjectUtil.defaultIfNull(ipqc.getLaborScrapQuantity(), BigDecimal.ZERO),
                    ObjectUtil.defaultIfNull(ipqc.getMaterialScrapQuantity(), BigDecimal.ZERO),
                    ObjectUtil.defaultIfNull(ipqc.getOtherScrapQuantity(), BigDecimal.ZERO));
        } else {
            throw new IllegalArgumentException(
                    "IPQC å•[" + ipqc.getId() + "] sourceDocType=" + ipqc.getSourceDocType() + " æ— æ³•识别,无法回写来源单据");
        if (sourceDocId == null) {
            log.warn("[writeBackSourceDoc] IPQC({}) æ— æ³•确定来源报工,跳过回写", ipqc.getId());
            return;
        }
        // 2. å›žå†™æŠ¥å·¥
        feedbackService.updateProFeedbackWhenIpqcFinish(sourceDocId, sourceLineId,
                ObjectUtil.defaultIfNull(ipqc.getQualifiedQuantity(), BigDecimal.ZERO),
                ObjectUtil.defaultIfNull(ipqc.getUnqualifiedQuantity(), BigDecimal.ZERO),
                ObjectUtil.defaultIfNull(ipqc.getLaborScrapQuantity(), BigDecimal.ZERO),
                ObjectUtil.defaultIfNull(ipqc.getMaterialScrapQuantity(), BigDecimal.ZERO),
                ObjectUtil.defaultIfNull(ipqc.getOtherScrapQuantity(), BigDecimal.ZERO));
    }
    @Override
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java
@@ -247,28 +247,49 @@
     * å›žå†™ ERP é‡‡è´­è®¢å•的入库数量
     */
    private void updateErpPurchaseOrderInCount(MesWmItemReceiptDO receipt) {
        // èŽ·å–å…¥åº“å•è¡Œ
        List<MesWmItemReceiptLineDO> lines = itemReceiptLineService.getItemReceiptLineListByReceiptId(receipt.getId());
        if (CollUtil.isEmpty(lines)) {
            return;
        // 1. ç¡®å®šé‡‡è´­è®¢å• ID:优先从入库单头取(从到货通知单带入),其次从行反查
        Long purchaseOrderId = receipt.getPurchaseOrderId();
        if (purchaseOrderId == null && receipt.getNoticeId() != null) {
            // ä»Žå…³è”的到货通知单获取采购订单 ID
            MesWmArrivalNoticeDO notice = arrivalNoticeService.getArrivalNotice(receipt.getNoticeId());
            if (notice != null) {
                purchaseOrderId = notice.getPurchaseOrderId();
            }
        }
        // ç”¨äºŽå­˜å‚¨é‡‡è´­è®¢å• ID,避免重复更新
        Long purchaseOrderId = null;
        // éåŽ†è¡Œï¼ŒæŒ‰ purchaseOrderItemId æ›´æ–°å…¥åº“数量
        for (MesWmItemReceiptLineDO line : lines) {
            if (line.getPurchaseOrderItemId() != null && line.getReceivedQuantity() != null) {
                purchaseOrderApi.updateOrderItemInCount(line.getPurchaseOrderItemId(), line.getReceivedQuantity());
                // èŽ·å–é‡‡è´­è®¢å• ID(从第一个有效的明细项获取)
                if (purchaseOrderId == null) {
                    cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO itemDTO =
                            purchaseOrderApi.getPurchaseOrderItem(line.getPurchaseOrderItemId()).getCheckedData();
                    if (itemDTO != null && itemDTO.getOrderId() != null) {
                        purchaseOrderId = itemDTO.getOrderId();
        // 2. èŽ·å–å…¥åº“å•è¡Œï¼ŒæŒ‰ purchaseOrderItemId æ›´æ–°å…¥åº“数量
        List<MesWmItemReceiptLineDO> lines = itemReceiptLineService.getItemReceiptLineListByReceiptId(receipt.getId());
        if (CollUtil.isNotEmpty(lines)) {
            for (MesWmItemReceiptLineDO line : lines) {
                if (line.getPurchaseOrderItemId() != null && line.getReceivedQuantity() != null) {
                    purchaseOrderApi.updateOrderItemInCount(line.getPurchaseOrderItemId(), line.getReceivedQuantity());
                    // å¦‚果还没拿到 purchaseOrderId,从明细项反查
                    if (purchaseOrderId == null) {
                        cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO itemDTO =
                                purchaseOrderApi.getPurchaseOrderItem(line.getPurchaseOrderItemId()).getCheckedData();
                        if (itemDTO != null && itemDTO.getOrderId() != null) {
                            purchaseOrderId = itemDTO.getOrderId();
                        }
                    }
                }
            }
        } else if (receipt.getNoticeId() != null) {
            // å…œåº•:入库行为空时,从到货通知单行回写入库数量
            List<MesWmArrivalNoticeLineDO> noticeLines = arrivalNoticeLineService
                    .getArrivalNoticeLineListByNoticeId(receipt.getNoticeId());
            for (MesWmArrivalNoticeLineDO noticeLine : noticeLines) {
                if (noticeLine.getPurchaseOrderItemId() != null) {
                    // ä½¿ç”¨åˆæ ¼æ•°é‡ï¼ˆæœ‰ IQC æ—¶ä¸ºåˆæ ¼æ•°é‡ï¼Œå¦åˆ™ä¸ºåˆ°è´§æ•°é‡ï¼‰
                    BigDecimal qty = noticeLine.getQualifiedQuantity() != null
                            ? noticeLine.getQualifiedQuantity() : noticeLine.getArrivalQuantity();
                    if (qty != null && qty.compareTo(BigDecimal.ZERO) > 0) {
                        purchaseOrderApi.updateOrderItemInCount(noticeLine.getPurchaseOrderItemId(), qty);
                    }
                }
            }
        }
        // æ›´æ–°é‡‡è´­è®¢å•的入库状态
        // 3. æ›´æ–°é‡‡è´­è®¢å•的入库状态
        if (purchaseOrderId != null) {
            purchaseOrderApi.updateOrderInStatus(purchaseOrderId);
        }
@@ -394,6 +415,7 @@
        receipt.setCode(code);
        receipt.setName(notice.getName() + "入库单");
        receipt.setNoticeId(arrivalNoticeId);
        receipt.setPurchaseOrderId(notice.getPurchaseOrderId());
        receipt.setPurchaseOrderCode(notice.getPurchaseOrderCode());
        receipt.setVendorId(notice.getVendorId());
        receipt.setReceiptDate(java.time.LocalDateTime.now()); // å…¥åº“时间为当前时间