|
|
@ -611,6 +611,10 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { |
|
|
// 2. 新增BOM detail(明细表) |
|
|
// 2. 新增BOM detail(明细表) |
|
|
log.info("步骤2: 保存BOM detail"); |
|
|
log.info("步骤2: 保存BOM detail"); |
|
|
bomSearch3Mapper.saveBomDetailFromTemp(data.getBomId(), data.getCreateBy()); |
|
|
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 |
|
|
// 3. 新增Routing header(主表)⚠️ 调整顺序:必须先保存Routing |
|
|
log.info("步骤3: 保存Routing header"); |
|
|
log.info("步骤3: 保存Routing header"); |
|
|
@ -619,6 +623,10 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { |
|
|
// 4. 新增Routing detail(明细表) |
|
|
// 4. 新增Routing detail(明细表) |
|
|
log.info("步骤4: 保存Routing detail"); |
|
|
log.info("步骤4: 保存Routing detail"); |
|
|
bomSearch3Mapper.saveRoutingDetailFromTemp(data.getBomId(), data.getCreateBy()); |
|
|
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 |
|
|
// 5. 新增Routing component(工艺路线)⚠️ 关键步骤:生成新的operation_id |
|
|
log.info("步骤5: 保存Routing component"); |
|
|
log.info("步骤5: 保存Routing component"); |
|
|
@ -631,7 +639,7 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { |
|
|
// 7. 新增BOM节点树到快速创建BOM表 |
|
|
// 7. 新增BOM节点树到快速创建BOM表 |
|
|
log.info("步骤7: 保存BOM节点树"); |
|
|
log.info("步骤7: 保存BOM节点树"); |
|
|
// data.getPartNo() = 原BOM的物料编码, bomTreeHeader.getPartNo() = 新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数据保存完成 ==="); |
|
|
log.info("=== 完整BOM数据保存完成 ==="); |
|
|
|
|
|
|
|
|
@ -669,65 +677,111 @@ public class BomSearch3ServiceImpl implements BomSearch3Service { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 复制原BOM的节点树到新的mainPart下 |
|
|
|
|
|
|
|
|
* 从临时表保存BOM节点树到快速创建表(支持多级节点变更) |
|
|
|
|
|
* |
|
|
|
|
|
* <p><b>关键修复逻辑:</b></p> |
|
|
|
|
|
* <ul> |
|
|
|
|
|
* <li>❌ 错误方式:从原BOM复制数据,只修改根节点物料</li> |
|
|
|
|
|
* <li>✅ 正确方式:从临时表读取所有节点(包含所有层级的变更)</li> |
|
|
|
|
|
* <li>✅ 使用 bomId 精确查询当前BOM的临时数据</li> |
|
|
|
|
|
* <li>✅ 按层级排序,确保父子关系正确</li> |
|
|
|
|
|
* </ul> |
|
|
|
|
|
* |
|
|
|
|
|
* @param bomId BOM ID(必须,用于精确查询临时表数据) |
|
|
* @param site 站点 |
|
|
* @param site 站点 |
|
|
* @param originalPartNo 原BOM物料编码(被复制的) |
|
|
|
|
|
* @param newPartNo 新BOM物料编码(复制目标) |
|
|
|
|
|
|
|
|
* @param originalPartNo 原BOM物料编码 |
|
|
|
|
|
* @param newPartNo 新BOM物料编码(根节点) |
|
|
* @param createBy 创建人 |
|
|
* @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<CopyTempBomTree> tempNodes = copyTempBomTreeMapper.selectList( |
|
|
|
|
|
new LambdaQueryWrapper<CopyTempBomTree>() |
|
|
|
|
|
.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<PlmQuicklyBomInfoEntity> originalNodes = bomSearch3Mapper.queryOriginalBomNodeTree(site, originalPartNo); |
|
|
List<PlmQuicklyBomInfoEntity> originalNodes = bomSearch3Mapper.queryOriginalBomNodeTree(site, originalPartNo); |
|
|
|
|
|
|
|
|
if (originalNodes.isEmpty()) { |
|
|
|
|
|
log.warn("原BOM没有节点树数据,不执行复制。originalPartNo: {}", originalPartNo); |
|
|
|
|
|
log.warn("这可能是因为原BOM不是通过快速创建BOM功能创建的"); |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
// 3. 构建原节点的 (level -> originalNode) 映射,用于匹配模板信息 |
|
|
|
|
|
Map<Integer, PlmQuicklyBomInfoEntity> 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<PlmQuicklyBomInfoEntity> newNodes = new ArrayList<>(); |
|
|
List<PlmQuicklyBomInfoEntity> newNodes = new ArrayList<>(); |
|
|
for (PlmQuicklyBomInfoEntity originalNode : originalNodes) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < tempNodes.size(); i++) { |
|
|
|
|
|
CopyTempBomTree tempNode = tempNodes.get(i); |
|
|
PlmQuicklyBomInfoEntity newNode = new PlmQuicklyBomInfoEntity(); |
|
|
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.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 { |
|
|
} 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); |
|
|
newNodes.add(newNode); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 批量插入 |
|
|
|
|
|
|
|
|
// 5. 批量插入 |
|
|
if (!newNodes.isEmpty()) { |
|
|
if (!newNodes.isEmpty()) { |
|
|
bomSearch3Mapper.batchInsertQuicklyBomInfo(newNodes); |
|
|
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); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|