From a22c1501ca8c1fd407d89ba77ba5f9fa548e9104 Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Wed, 26 Nov 2025 15:36:24 +0800 Subject: [PATCH] =?UTF-8?q?BOM=E5=A4=8D=E5=88=B6=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E8=A1=A8tree=E7=BB=93=E6=9E=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/part/mapper/BomSearch3Mapper.java | 4 + .../service/impl/BomSearch3ServiceImpl.java | 132 ++++++++++++------ .../mapper/part/BomSearch3Mapper.xml | 110 ++++++++++++--- 3 files changed, 184 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/xujie/sys/modules/part/mapper/BomSearch3Mapper.java b/src/main/java/com/xujie/sys/modules/part/mapper/BomSearch3Mapper.java index 665ffb21..8c2a5857 100644 --- a/src/main/java/com/xujie/sys/modules/part/mapper/BomSearch3Mapper.java +++ b/src/main/java/com/xujie/sys/modules/part/mapper/BomSearch3Mapper.java @@ -93,4 +93,8 @@ public interface BomSearch3Mapper { void saveRoutingHeaderFromTemp(@Param("bomId") Long bomId, @Param("createBy") String createBy); void saveRoutingDetailFromTemp(@Param("bomId") Long bomId, @Param("createBy") String createBy); + + void updateBomDetailStatusToReleased(@Param("bomId") Long bomId, @Param("createBy") String createBy); + + void updateRoutingDetailStatusToReleased(@Param("bomId") Long bomId, @Param("createBy") String createBy); } diff --git a/src/main/java/com/xujie/sys/modules/part/service/impl/BomSearch3ServiceImpl.java b/src/main/java/com/xujie/sys/modules/part/service/impl/BomSearch3ServiceImpl.java index 6775fc6a..1e968692 100644 --- a/src/main/java/com/xujie/sys/modules/part/service/impl/BomSearch3ServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/part/service/impl/BomSearch3ServiceImpl.java @@ -611,6 +611,10 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { // 2. 新增BOM detail(明细表) log.info("步骤2: 保存BOM detail"); bomSearch3Mapper.saveBomDetailFromTemp(data.getBomId(), data.getCreateBy()); + + // 2.1 更新 Tentative 状态为 Released + log.info("步骤2.1: 更新BOM detail状态为Released"); + bomSearch3Mapper.updateBomDetailStatusToReleased(data.getBomId(), data.getCreateBy()); // 3. 新增Routing header(主表)⚠️ 调整顺序:必须先保存Routing log.info("步骤3: 保存Routing header"); @@ -619,6 +623,10 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { // 4. 新增Routing detail(明细表) log.info("步骤4: 保存Routing detail"); bomSearch3Mapper.saveRoutingDetailFromTemp(data.getBomId(), data.getCreateBy()); + + // 4.1 更新 Tentative 状态为 Released + log.info("步骤4.1: 更新Routing detail状态为Released"); + bomSearch3Mapper.updateRoutingDetailStatusToReleased(data.getBomId(), data.getCreateBy()); // 5. 新增Routing component(工艺路线)⚠️ 关键步骤:生成新的operation_id log.info("步骤5: 保存Routing component"); @@ -631,7 +639,7 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { // 7. 新增BOM节点树到快速创建BOM表 log.info("步骤7: 保存BOM节点树"); // data.getPartNo() = 原BOM的物料编码, bomTreeHeader.getPartNo() = 新BOM的物料编码 - saveQuicklyBomInfoFromTemp(data.getSite(), data.getPartNo(), bomTreeHeader.getPartNo(), data.getCreateBy()); + saveQuicklyBomInfoFromTemp(data.getBomId(), data.getSite(), data.getPartNo(), bomTreeHeader.getPartNo(), data.getCreateBy()); log.info("=== 完整BOM数据保存完成 ==="); @@ -669,65 +677,111 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { } /** - * 复制原BOM的节点树到新的mainPart下 + * 从临时表保存BOM节点树到快速创建表(支持多级节点变更) + * + *

关键修复逻辑:

+ * + * + * @param bomId BOM ID(必须,用于精确查询临时表数据) * @param site 站点 - * @param originalPartNo 原BOM物料编码(被复制的) - * @param newPartNo 新BOM物料编码(复制目标) + * @param originalPartNo 原BOM物料编码 + * @param newPartNo 新BOM物料编码(根节点) * @param createBy 创建人 */ - private void saveQuicklyBomInfoFromTemp(String site, String originalPartNo, String newPartNo, String createBy) { - log.info("=== 开始复制BOM节点树到快速创建表 ==="); - log.info("site: {}, 原BOM物料: {}, 新BOM物料: {}, 创建人: {}", site, originalPartNo, newPartNo, createBy); + private void saveQuicklyBomInfoFromTemp(Long bomId, String site, String originalPartNo, String newPartNo, String createBy) { + log.info("=== 开始从临时表保存BOM节点树到快速创建表 ==="); + log.info("bomId: {}, site: {}, 原BOM物料: {}, 新BOM根节点物料: {}, 创建人: {}", bomId, site, originalPartNo, newPartNo, createBy); + + // 1. ⚠️ 关键修复:从临时表查询所有节点(包含所有层级的变更后part_no) + List tempNodes = copyTempBomTreeMapper.selectList( + new LambdaQueryWrapper() + .eq(CopyTempBomTree::getBomId, bomId) + .eq(CopyTempBomTree::getUsername, createBy) + .orderByAsc(CopyTempBomTree::getLevel) + .orderByAsc(CopyTempBomTree::getId) + ); + + if (tempNodes.isEmpty()) { + log.warn("临时表中没有BOM节点树数据,不执行保存。bomId: {}, createBy: {}", bomId, createBy); + return; + } + + log.info("从临时表找到变更后的节点树,共{}个节点", tempNodes.size()); - // 查询原BOM的节点树结构 + // 2. 查询原BOM的节点树模板信息(仅用于获取template_no、node_id等元数据) List originalNodes = bomSearch3Mapper.queryOriginalBomNodeTree(site, originalPartNo); - if (originalNodes.isEmpty()) { - log.warn("原BOM没有节点树数据,不执行复制。originalPartNo: {}", originalPartNo); - log.warn("这可能是因为原BOM不是通过快速创建BOM功能创建的"); - return; + // 3. 构建原节点的 (level -> originalNode) 映射,用于匹配模板信息 + Map levelToOriginalNodeMap = new HashMap<>(); + for (int i = 0; i < originalNodes.size(); i++) { + levelToOriginalNodeMap.put(i, originalNodes.get(i)); } - log.info("找到原BOM节点树,共{}个节点", originalNodes.size()); - - // 复制节点树,修改mainPart和part_no(根节点) + // 4. ✅ 正确逻辑:使用临时表的所有数据(变更后的part_no)+ 原模板的结构信息 List newNodes = new ArrayList<>(); - for (PlmQuicklyBomInfoEntity originalNode : originalNodes) { + + for (int i = 0; i < tempNodes.size(); i++) { + CopyTempBomTree tempNode = tempNodes.get(i); PlmQuicklyBomInfoEntity newNode = new PlmQuicklyBomInfoEntity(); - // 复制所有字段(保留原节点结构) - newNode.setSite(originalNode.getSite()); - newNode.setTemplateNo(originalNode.getTemplateNo()); - newNode.setNodeId(originalNode.getNodeId()); - newNode.setNodeName(originalNode.getNodeName()); - newNode.setId(originalNode.getId()); - newNode.setpId(originalNode.getpId()); - newNode.setEngChgLevel(originalNode.getEngChgLevel()); - newNode.setRoutingRevision(originalNode.getRoutingRevision()); - newNode.setCreateBy(createBy); - - // 修改mainPart为新物料编码 + // ✅ 使用临时表的数据(包含变更后的part_no) + newNode.setPartNo(tempNode.getPartNo()); + newNode.setSite(tempNode.getSite()); + newNode.setEngChgLevel(String.valueOf(tempNode.getEngChgLevel())); + newNode.setRoutingRevision(String.valueOf(tempNode.getEngChgLevel())); newNode.setMainPart(newPartNo); + newNode.setCreateBy(createBy); - // 如果是根节点(p_id = '0'),修改part_no为新物料编码 - if ("0".equals(originalNode.getpId())) { - newNode.setPartNo(newPartNo); - log.info("复制根节点: id={}, 原partNo={} → 新partNo={}", - originalNode.getId(), originalNode.getPartNo(), newPartNo); + // 尝试从原节点获取模板信息 + PlmQuicklyBomInfoEntity originalNode = levelToOriginalNodeMap.get(i); + if (originalNode != null) { + // 使用原模板的树形结构信息 + newNode.setTemplateNo(originalNode.getTemplateNo()); + newNode.setNodeId(originalNode.getNodeId()); + newNode.setNodeName(originalNode.getNodeName()); + newNode.setId(originalNode.getId()); + newNode.setpId(originalNode.getpId()); + + log.info("节点[{}]: 层级={}, part_no={} (原={}, 已变更={}), 模板id={}", + i, tempNode.getLevel(), tempNode.getPartNo(), + originalNode.getPartNo(), tempNode.getChangeFlag(), originalNode.getId()); } else { - // 子节点保持原来的part_no - newNode.setPartNo(originalNode.getPartNo()); - log.debug("复制子节点: id={}, partNo={}", originalNode.getId(), originalNode.getPartNo()); + // 没有原模板,使用默认值 + newNode.setNodeId(String.valueOf(tempNode.getLevel())); + newNode.setNodeName("Node-Level" + tempNode.getLevel()); + newNode.setId(String.valueOf(tempNode.getLevel())); + newNode.setpId(tempNode.getParentId() == 0 ? "0" : String.valueOf(tempNode.getLevel() - 1)); + + log.info("节点[{}]: 层级={}, part_no={} (新增节点, 无原模板), 变更标识={}", + i, tempNode.getLevel(), tempNode.getPartNo(), tempNode.getChangeFlag()); } newNodes.add(newNode); } - // 批量插入 + // 5. 批量插入 if (!newNodes.isEmpty()) { bomSearch3Mapper.batchInsertQuicklyBomInfo(newNodes); - log.info("=== BOM节点树复制完成!共复制{}个节点 ===", newNodes.size()); - log.info("新BOM物料编码: {}, 可在quicklyCreateBom页面查看", newPartNo); + log.info("=== BOM节点树保存完成!共保存{}个节点 ===", newNodes.size()); + log.info("新BOM根节点物料编码: {}, 可在quicklyCreateBom页面查看", newPartNo); + + // 打印变更摘要 + int changeCount = 0; + for (int i = 0; i < newNodes.size(); i++) { + PlmQuicklyBomInfoEntity newNode = newNodes.get(i); + PlmQuicklyBomInfoEntity originalNode = levelToOriginalNodeMap.get(i); + if (originalNode != null && !newNode.getPartNo().equals(originalNode.getPartNo())) { + log.info(" ✓ 节点[{}] 物料已变更: {} → {}", + i, originalNode.getPartNo(), newNode.getPartNo()); + changeCount++; + } + } + log.info("✅ 变更统计: 共{}个节点发生物料变更", changeCount); } } diff --git a/src/main/resources/mapper/part/BomSearch3Mapper.xml b/src/main/resources/mapper/part/BomSearch3Mapper.xml index cec589d5..f60ef5fb 100644 --- a/src/main/resources/mapper/part/BomSearch3Mapper.xml +++ b/src/main/resources/mapper/part/BomSearch3Mapper.xml @@ -722,12 +722,12 @@ insert into plm_bom_detail (site, bu_no, part_no, eng_chg_level, bom_type, alternative_no, alternative_description, status, min_lot_qty, default_flag, note_text, create_date, create_by) select distinct - site, - bu_no, - part_no, - eng_chg_level, - bom_type, - alternative_no, + t.site, + t.bu_no, + t.part_no, + t.eng_chg_level, + t.bom_type, + t.alternative_no, '*' as alternative_description, 'Released' as status, 1 as min_lot_qty, @@ -735,9 +735,37 @@ null as note_text, getDate() as create_date, #{createBy} as create_by - from plm_copy_temp_bom_tree - where bom_id = #{bomId} and username = #{createBy} and change_flag = 'Y' and level = 0 + from plm_copy_temp_bom_tree t + where t.bom_id = #{bomId} and t.username = #{createBy} and t.change_flag = 'Y' + and not exists ( + select 1 from plm_bom_detail d + where d.site = t.site + and d.bu_no = t.bu_no + and d.part_no = t.part_no + and d.eng_chg_level = t.eng_chg_level + and d.bom_type = t.bom_type + and d.alternative_no = t.alternative_no + ) + + + + update plm_bom_detail + set status = 'Released' + where status = 'Tentative' + and exists ( + select 1 from plm_copy_temp_bom_tree t + where t.bom_id = #{bomId} + and t.username = #{createBy} + and t.change_flag = 'Y' + and t.site = plm_bom_detail.site + and t.bu_no = plm_bom_detail.bu_no + and t.part_no = plm_bom_detail.part_no + and t.eng_chg_level = plm_bom_detail.eng_chg_level + and t.bom_type = plm_bom_detail.bom_type + and t.alternative_no = plm_bom_detail.alternative_no + ) + @@ -754,17 +782,25 @@ insert into plm_routing_header (site, bu_no, part_no, routing_revision, routing_type, note_text, phase_in_date, create_date, create_by) select distinct - site, - bu_no, - part_no, - eng_chg_level as routing_revision, - bom_type as routing_type, + t.site, + t.bu_no, + t.part_no, + t.eng_chg_level as routing_revision, + t.bom_type as routing_type, null as note_text, getDate() as phase_in_date, getDate() as create_date, #{createBy} as create_by - from plm_copy_temp_bom_tree - where bom_id = #{bomId} and username = #{createBy} and change_flag = 'Y' and level = 0 + from plm_copy_temp_bom_tree t + where t.bom_id = #{bomId} and t.username = #{createBy} and t.change_flag = 'Y' + and not exists ( + select 1 from plm_routing_header h + where h.site = t.site + and h.bu_no = t.bu_no + and h.part_no = t.part_no + and h.routing_revision = t.eng_chg_level + and h.routing_type = t.bom_type + ) @@ -782,18 +818,46 @@ insert into plm_routing_detail (site, bu_no, part_no, routing_revision, routing_type, alternative_no, status, create_date, create_by) select distinct - site, - bu_no, - part_no, - eng_chg_level as routing_revision, - bom_type as routing_type, - alternative_no, + t.site, + t.bu_no, + t.part_no, + t.eng_chg_level as routing_revision, + t.bom_type as routing_type, + t.alternative_no, 'Released' as status, getDate() as create_date, #{createBy} as create_by - from plm_copy_temp_bom_tree - where bom_id = #{bomId} and username = #{createBy} and change_flag = 'Y' and level = 0 + from plm_copy_temp_bom_tree t + where t.bom_id = #{bomId} and t.username = #{createBy} and t.change_flag = 'Y' + and not exists ( + select 1 from plm_routing_detail d + where d.site = t.site + and d.bu_no = t.bu_no + and d.part_no = t.part_no + and d.routing_revision = t.eng_chg_level + and d.routing_type = t.bom_type + and d.alternative_no = t.alternative_no + ) + + + + update plm_routing_detail + set status = 'Released' + where status = 'Tentative' + and exists ( + select 1 from plm_copy_temp_bom_tree t + where t.bom_id = #{bomId} + and t.username = #{createBy} + and t.change_flag = 'Y' + and t.site = plm_routing_detail.site + and t.bu_no = plm_routing_detail.bu_no + and t.part_no = plm_routing_detail.part_no + and t.eng_chg_level = plm_routing_detail.routing_revision + and t.bom_type = plm_routing_detail.routing_type + and t.alternative_no = plm_routing_detail.alternative_no + ) +