diff --git a/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp b/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp index 3ec405d..b3d943a 100644 --- a/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp +++ b/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp @@ -65,7 +65,7 @@ function buildSubTreeFlatList(subTree, parentObjid, baseLevel) { var originalChildObjid = item.CHILD_OBJID || item.child_objid || ''; if(originalChildObjid) originalChildToNew[originalChildObjid] = newChildObjid; - flatList.push({ + var subPartData = { OBJID: generateTempId(), CHILD_OBJID: newChildObjid, PARENT_OBJID: parentObjid, @@ -80,7 +80,11 @@ function buildSubTreeFlatList(subTree, parentObjid, baseLevel) { REVISION: item.REVISION || item.revision || '', STATUS: 'ACTIVE', _IS_SUB_PART: true - }); + }; + for(var lv = 1; lv <= 10; lv++) { + subPartData['LEVEL_' + lv] = (lv == subPartData.LEVEL) ? '*' : ''; + } + flatList.push(subPartData); } // 2레벨 이상 항목의 부모 OBJID 재매핑 @@ -160,7 +164,7 @@ $(function(){ var rowData = rightSelectedRows[i].getData(); var partChildObjid = generateTempId(); - newParts.push({ + var newPartData = { OBJID: generateTempId(), CHILD_OBJID: partChildObjid, PARENT_OBJID: parentObjid, @@ -174,7 +178,11 @@ $(function(){ SPEC: rowData.SPEC || '', REVISION: rowData.REVISION || '', STATUS: 'ACTIVE' - }); + }; + for(var lv = 1; lv <= 10; lv++) { + newPartData['LEVEL_' + lv] = (lv == newPartData.LEVEL) ? '*' : ''; + } + newParts.push(newPartData); // 반제품 E-BOM 하위 구조 조회 var ebomResult = fetchEbomSubTree(rowData.PART_NO); diff --git a/src/com/pms/service/PartMngService.java b/src/com/pms/service/PartMngService.java index 044cbfc..836519f 100644 --- a/src/com/pms/service/PartMngService.java +++ b/src/com/pms/service/PartMngService.java @@ -3960,7 +3960,8 @@ public class PartMngService extends BaseService { } } - // 새 데이터에서 참조하는 PARENT_OBJID 셋 (삭제 보호용) + // 삭제 보호용: UI 새 데이터에서 참조되는 PARENT_OBJID만 수집 + // (DB 기존 데이터는 포함하지 않음 - 의도적 삭제를 막게 되므로) Set referencedParentObjids = new HashSet<>(); for(Map item : ebomData) { String parentObjid = CommonUtils.checkNull(item.get("parentObjid")); @@ -3969,12 +3970,22 @@ public class PartMngService extends BaseService { } } - // 2. 삭제: 기존에 있지만 새 데이터에 없는 항목 (다른 행이 참조하는 부모는 보호) + // 2. 삭제: 기존에 있지만 새 데이터에 없는 항목 for(String existingChildObjid : existingMap.keySet()) { if(!newChildObjids.contains(existingChildObjid)) { - if(referencedParentObjids.contains(existingChildObjid)) { + // 루트 행(PARENT_OBJID 비어있음)은 절대 삭제하지 않음 + Map existingRow = existingMap.get(existingChildObjid); + String existingParentObjid = CommonUtils.checkNull(existingRow.get("parent_objid"), CommonUtils.checkNull(existingRow.get("PARENT_OBJID"))); + if(existingParentObjid.isEmpty()) { + System.out.println("[saveEbomBatch] 루트 행 삭제 방지: CHILD_OBJID=" + existingChildObjid); continue; } + // 다른 행이 이 CHILD_OBJID를 부모로 참조하면 삭제 방지 + if(referencedParentObjids.contains(existingChildObjid)) { + System.out.println("[saveEbomBatch] 참조된 부모 행 삭제 방지: CHILD_OBJID=" + existingChildObjid); + continue; + } + System.out.println("[saveEbomBatch] 삭제: CHILD_OBJID=" + existingChildObjid); Map deleteParam = new HashMap<>(); deleteParam.put("bomReportObjId", bomReportObjId); deleteParam.put("childObjid", existingChildObjid); @@ -3982,29 +3993,43 @@ public class PartMngService extends BaseService { } } - // 3. 추가/수정 + // 3. 추가/수정 (임시ID → 새ID 매핑으로 부모-자식 관계 유지) + Map tempIdToNewIdMap = new HashMap<>(); + for(int i = 0; i < ebomData.size(); i++) { Map item = ebomData.get(i); String childObjid = CommonUtils.checkNull(item.get("childObjid")); if(existingMap.containsKey(childObjid)) { // 기존 항목 → 수정 (수량, 순서 등만 업데이트) + String parentObjid = CommonUtils.checkNull(item.get("parentObjid")); + // 부모가 임시ID였다면 새 ID로 치환 + if(!parentObjid.isEmpty() && tempIdToNewIdMap.containsKey(parentObjid)) { + parentObjid = tempIdToNewIdMap.get(parentObjid); + } Map updateParam = new HashMap<>(); updateParam.put("bomReportObjId", bomReportObjId); updateParam.put("childObjid", childObjid); - updateParam.put("PARENT_OBJID", CommonUtils.checkNull(item.get("parentObjid"))); + updateParam.put("PARENT_OBJID", parentObjid); updateParam.put("QTY", CommonUtils.checkNull(item.get("qty"), "1")); updateParam.put("ITEM_QTY", CommonUtils.checkNull(item.get("itemQty"), "1")); updateParam.put("QTY_TEMP", CommonUtils.checkNull(item.get("qtyTemp"), "1")); updateParam.put("SEQ", i + 1); sqlSession.update("partMng.updateBomPartQtyByChildObjid", updateParam); } else { - // 신규 항목 → INSERT + // 신규 항목 → INSERT (항상 새 CHILD_OBJID 생성, 매핑 추적) + String newChildObjid = CommonUtils.createObjId(); + tempIdToNewIdMap.put(childObjid, newChildObjid); + String parentObjid = CommonUtils.checkNull(item.get("parentObjid")); + // 부모가 임시ID였다면 새 ID로 치환 + if(!parentObjid.isEmpty() && tempIdToNewIdMap.containsKey(parentObjid)) { + parentObjid = tempIdToNewIdMap.get(parentObjid); + } Map insertParam = new HashMap<>(); insertParam.put("BOM_REPORT_OBJID", bomReportObjId); insertParam.put("OBJID", CommonUtils.createObjId()); - insertParam.put("PARENT_OBJID", CommonUtils.checkNull(item.get("parentObjid"))); - insertParam.put("CHILD_OBJID", childObjid.startsWith("-") ? CommonUtils.createObjId() : childObjid); + insertParam.put("PARENT_OBJID", parentObjid); + insertParam.put("CHILD_OBJID", newChildObjid); insertParam.put("PARENT_PART_NO", CommonUtils.checkNull(item.get("parentPartNo"))); insertParam.put("PART_NO", CommonUtils.checkNull(item.get("partNo"))); insertParam.put("LAST_PART_OBJID", CommonUtils.checkNull(item.get("lastPartObjid")));