diff --git a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp index 8c9e7cd..d093d44 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp @@ -107,13 +107,23 @@ $(function(){ var sourceBomType = "${info.SOURCE_BOM_TYPE}"; var sourceEbomObjId = "${info.SOURCE_EBOM_OBJID}"; var sourceMbomObjId = "${info.SOURCE_MBOM_OBJID}"; + var productCode = "${info.PRODUCT_CODE}"; console.log("할당된 BOM 정보:", { sourceBomType: sourceBomType, sourceEbomObjId: sourceEbomObjId, - sourceMbomObjId: sourceMbomObjId + sourceMbomObjId: sourceMbomObjId, + productCode: productCode }); + // Machine 이외 제품: M-BOM 템플릿 자동 로드 + + console.log("M-BOM 템플릿 발견 - 자동 로드 시작"); + setTimeout(function() { + fn_loadMbomTemplate(); + }, 500); + + // Controller에서 이미 데이터를 로드하여 JSP에 전달하므로 자동 조회 불필요 // setTimeout(function() { // fn_searchMbom(); @@ -197,6 +207,59 @@ function fn_applyBulkDeadline() { } } +// M-BOM 템플릿 로드 (Machine 이외 제품) +function fn_loadMbomTemplate() { + console.log("fn_loadMbomTemplate 호출됨"); + + // 템플릿 데이터를 JSP에서 받아옴 + var templateDetails = []; + + + templateDetails.push({ + OBJID: '', // 새로 생성될 ID + CHILD_OBJID: '${item.CHILD_OBJID}', // 템플릿의 CHILD_OBJID 유지 (트리 구조용) + PARENT_OBJID: '${item.PARENT_OBJID}', + SEQ: ${item.SEQ}, + LEVEL: ${item.LEVEL}, + PART_OBJID: '${item.PART_OBJID}', + PART_NO: '${item.PART_NO}', + PART_NAME: '${item.PART_NAME}', + QTY: ${item.QTY}, + ITEM_QTY: ${item.QTY}, // 항목수량 + QTY_TEMP: ${item.QTY}, + UNIT: '${item.UNIT}', + SUPPLY_TYPE: '${item.SUPPLY_TYPE}', + MAKE_OR_BUY: '${item.MAKE_OR_BUY}', + RAW_MATERIAL: '${item.RAW_MATERIAL}', + RAW_MATERIAL_SPEC: '${item.RAW_MATERIAL_SPEC}', + SIZE: '${item.RAW_MATERIAL_SIZE}', + RAW_MATERIAL_NO: '${item.RAW_MATERIAL_PART_NO}', + PROCESSING_VENDOR: '${item.PROCESSING_VENDOR}', + PROCESSING_DEADLINE: '${item.PROCESSING_DEADLINE}', + GRINDING_DEADLINE: '${item.GRINDING_DEADLINE}', + REQUIRED_QTY: ${item.REQUIRED_QTY != null ? item.REQUIRED_QTY : 0}, + // ORDER_QTY, PRODUCTION_QTY는 명시적으로 설정하지 않음 (undefined) + // 이렇게 하면 formatter에서 자동 계산됨 + REMARK: '${item.REMARK}', + STATUS: 'ACTIVE' + }); + + + + console.log("템플릿 데이터 개수:", templateDetails.length); + + // 왼쪽 프레임에 데이터 로드 + var bottomFrame = parent.frames[1]; + var leftFrame = bottomFrame ? bottomFrame.frames['leftFrame'] : null; + + if(leftFrame && leftFrame._tabulGrid) { + leftFrame._tabulGrid.setData(templateDetails); + console.log("템플릿 데이터 로드 완료"); + } else { + console.error("왼쪽 프레임 또는 그리드를 찾을 수 없습니다."); + } +} + // M-BOM 조회 function fn_searchMbom() { var partNo = $("#search_part_no").val().trim(); diff --git a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp index d79f771..c0fb90b 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp @@ -384,13 +384,26 @@ function fn_checkAssignmentAndOpenMbom(projectObjId) { success: function(response) { console.log("BOM 할당 정보:", response); + // Machine(0000928) 이외 제품인지 확인 + var productCode = response ? response.PRODUCT_CODE : null; + var partNo = response ? response.PART_NO : null; + if(!response || !response.SOURCE_BOM_TYPE) { // 할당 정보가 없는 경우 - Swal.fire({ - title: '알림', - text: 'BOM 할당 정보가 없습니다.\nBOM 복사 버튼을 통해 먼저 BOM을 할당해주세요.', - icon: 'info' - }); + + // Machine 이외 제품이고 품번이 있으면 템플릿 확인 + if(productCode && productCode !== '0000928' && partNo) { + console.log("Machine 이외 제품 - 템플릿 확인 후 팝업 열기"); + // 템플릿이 있을 수 있으므로 팝업 열기 + fn_openMBomFormPopup(projectObjId); + } else { + // Machine 제품이거나 품번이 없으면 할당 필요 + Swal.fire({ + title: '알림', + text: 'BOM 할당 정보가 없습니다.\nBOM 복사 버튼을 통해 먼저 BOM을 할당해주세요.', + icon: 'info' + }); + } return; } diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp index 39f0098..733487c 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp @@ -397,6 +397,10 @@ function fn_initGrid() { var data = cell.getRow().getData(); var itemQty = parseFloat(data.ITEM_QTY) || 0; var orderQty = itemQty * projectQuantity; + + // 실제 데이터에도 저장 (getMbomTreeData에서 사용) + cell.getRow().update({ORDER_QTY: orderQty}, false); + return orderQty.toLocaleString(); } }, @@ -421,12 +425,16 @@ function fn_initGrid() { step: 1 }, formatter: function(cell) { - // 초기값은 소재발주수량 (항목수량 × 프로젝트 수주수량) + // 초기값은 소재발주수량과 동일 var value = cell.getValue(); - if(!value) { + + if(value === undefined || value === null || value === '' || value === 0) { var data = cell.getRow().getData(); - var itemQty = parseFloat(data.ITEM_QTY) || 0; - value = itemQty * projectQuantity; + // ORDER_QTY 값을 그대로 사용 + value = data.ORDER_QTY || 0; + + // 실제 데이터에도 저장 (getMbomTreeData에서 사용) + cell.getRow().update({PRODUCTION_QTY: value}, false); } return Number(value).toLocaleString(); } @@ -704,7 +712,15 @@ function fn_searchMbom(searchParams) { console.log("M-BOM 조회 결과:", data); if(data && data.list) { console.log("데이터 개수:", data.list.length); - _tabulGrid.setData(data.list); + + // ORDER_QTY, PRODUCTION_QTY 제거하여 formatter에서 재계산되도록 + var processedData = data.list.map(function(item) { + delete item.ORDER_QTY; + delete item.PRODUCTION_QTY; + return item; + }); + + _tabulGrid.setData(processedData); } else { console.log("데이터 없음"); _tabulGrid.setData([]); diff --git a/src/com/pms/controller/ProductionPlanningController.java b/src/com/pms/controller/ProductionPlanningController.java index 33ffd8b..2b31b07 100644 --- a/src/com/pms/controller/ProductionPlanningController.java +++ b/src/com/pms/controller/ProductionPlanningController.java @@ -967,6 +967,38 @@ public class ProductionPlanningController extends BaseService { if(projectInfo != null && !projectInfo.isEmpty()) { request.setAttribute("info", projectInfo); + + // Machine 이외 제품: 품번 기준 M-BOM 템플릿 조회 + String productCode = CommonUtils.checkNull(projectInfo.get("PRODUCT_CODE")); + String partNo = CommonUtils.checkNull(projectInfo.get("PART_NO")); + + System.out.println("제품구분 코드: " + productCode); + System.out.println("품번: " + partNo); + + // Machine(0000928) 이외 제품이고 품번이 있는 경우 + if(!"0000928".equals(productCode) && !"".equals(partNo)) { + Map templateParam = new HashMap<>(); + templateParam.put("partNo", partNo); + + // 품번 기준 최신 M-BOM 템플릿 조회 + Map template = commonService.selectOne("productionplanning.getLatestMbomTemplateByPartNo", request, templateParam); + + if(template != null && !template.isEmpty()) { + System.out.println("M-BOM 템플릿 발견: " + template.get("TEMPLATE_MBOM_NO")); + + // 템플릿 상세 항목 조회 + Map detailParam = new HashMap<>(); + detailParam.put("mbomHeaderObjid", template.get("TEMPLATE_HEADER_OBJID")); + List> templateDetails = commonService.selectList("productionplanning.getMbomTemplateDetails", request, detailParam); + + System.out.println("템플릿 상세 항목 수: " + (templateDetails != null ? templateDetails.size() : 0)); + + request.setAttribute("mbomTemplate", template); + request.setAttribute("mbomTemplateDetails", templateDetails); + } else { + System.out.println("해당 품번의 M-BOM 템플릿 없음"); + } + } } else { System.out.println("projectInfo is null or empty!"); } @@ -1115,8 +1147,29 @@ public class ProductionPlanningController extends BaseService { bomReportObjid = sourceMbomObjId; System.out.println("할당된 M-BOM 사용: " + bomReportObjid); } else { - bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID")); - System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid); + // 할당된 BOM도 없으면 Machine 이외 제품은 템플릿 확인 + String productCode = CommonUtils.checkNull(projectInfo.get("PRODUCT_CODE")); + String partNo = CommonUtils.checkNull(projectInfo.get("PART_NO")); + + if(!"0000928".equals(productCode) && !"".equals(partNo)) { + System.out.println("Machine 이외 제품 - 템플릿 조회 시도"); + Map templateParam = new HashMap<>(); + templateParam.put("partNo", partNo); + + Map template = commonService.selectOne("productionplanning.getLatestMbomTemplateByPartNo", request, templateParam); + + if(template != null && !template.isEmpty()) { + bomReportObjid = CommonUtils.checkNull(template.get("TEMPLATE_HEADER_OBJID")); + isSavedMbom = true; // 템플릿도 MBOM_DETAIL에서 조회 + System.out.println("템플릿 M-BOM 사용: " + bomReportObjid); + } else { + bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID")); + System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid); + } + } else { + bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID")); + System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid); + } } } @@ -1470,13 +1523,15 @@ public class ProductionPlanningController extends BaseService { if(assignment == null || assignment.isEmpty()) { resultMap.put("result", "fail"); - resultMap.put("message", "M-BOM 기준 정보가 없습니다. BOM 복사 팝업에서 먼저 기준을 설정해주세요."); + resultMap.put("message", "프로젝트 정보를 찾을 수 없습니다."); return resultMap; } String sourceBomType = CommonUtils.checkNull(assignment.get("SOURCE_BOM_TYPE")); String sourceBomObjId = ""; String baseBomPartNo = ""; + String productCode = CommonUtils.checkNull(assignment.get("PRODUCT_CODE")); + String partNo = CommonUtils.checkNull(assignment.get("PART_NO")); if("EBOM".equals(sourceBomType)) { sourceBomObjId = CommonUtils.checkNull(assignment.get("SOURCE_EBOM_OBJID")); @@ -1484,12 +1539,18 @@ public class ProductionPlanningController extends BaseService { } else if("MBOM".equals(sourceBomType)) { sourceBomObjId = CommonUtils.checkNull(assignment.get("SOURCE_MBOM_OBJID")); baseBomPartNo = CommonUtils.checkNull(assignment.get("MBOM_NO")); - } - - if(sourceBomObjId.isEmpty()) { - resultMap.put("result", "fail"); - resultMap.put("message", "기준 BOM 정보가 올바르지 않습니다."); - return resultMap; + } else { + // 할당 정보가 없는 경우 - Machine 이외 제품은 템플릿 기반 저장 허용 + if(!"0000928".equals(productCode) && !"".equals(partNo)) { + System.out.println("Machine 이외 제품 - 템플릿 기반 저장 허용"); + sourceBomType = "TEMPLATE"; // 템플릿 기반 저장 표시 + baseBomPartNo = partNo; + } else { + // Machine 제품이거나 품번이 없으면 할당 필요 + resultMap.put("result", "fail"); + resultMap.put("message", "M-BOM 기준 정보가 없습니다. BOM 복사 팝업에서 먼저 기준을 설정해주세요."); + return resultMap; + } } // M-BOM 품번 생성 또는 사용 diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index 0b576d7..91e21d0 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -3060,6 +3060,7 @@ '' ) AS CATEGORY_NAME, CM.PRODUCT, + CM.PRODUCT AS PRODUCT_CODE, COALESCE( (SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1), '' @@ -3442,6 +3443,59 @@ LIMIT 1 + + + + + + diff --git a/src/com/pms/service/ProductionPlanningService.java b/src/com/pms/service/ProductionPlanningService.java index 428fec8..acd033d 100644 --- a/src/com/pms/service/ProductionPlanningService.java +++ b/src/com/pms/service/ProductionPlanningService.java @@ -1119,6 +1119,13 @@ public class ProductionPlanningService { cleanPartNo = cleanPartNo.substring(2); // "M-" 제거 } mbomPrefix = "M-" + cleanPartNo + "-" + dateStr; + } else if("TEMPLATE".equals(sourceBomType)) { + // 템플릿 기준: M-{품번}-YYMMDD + String cleanPartNo = baseBomPartNo.trim(); + if(cleanPartNo.startsWith("M-")) { + cleanPartNo = cleanPartNo.substring(2); // "M-" 제거 + } + mbomPrefix = "M-" + cleanPartNo + "-" + dateStr; } else if("MBOM".equals(sourceBomType)) { // M-BOM 기준: 기존 M-BOM 품번에서 날짜/순번 부분 제거 후 새 날짜 추가 // 예: M-000AN014000-251124-01 → M-000AN014000 → M-000AN014000-251124 @@ -1430,6 +1437,10 @@ public class ProductionPlanningService { } else if("MBOM".equals(sourceBomType)) { paramMap.put("sourceEbomObjid", null); paramMap.put("sourceMbomObjid", sourceBomObjId); + } else if("TEMPLATE".equals(sourceBomType)) { + // 템플릿 기반 저장: 할당 정보 없음 + paramMap.put("sourceEbomObjid", null); + paramMap.put("sourceMbomObjid", null); } // MBOM_HEADER 삽입