From fd4283f3cf2cd05df0d2fdee8c33ed88bd385f3e Mon Sep 17 00:00:00 2001 From: leeheejin Date: Mon, 17 Nov 2025 17:29:04 +0900 Subject: [PATCH] auto commit --- Dockerfile | 4 +- Dockerfile.dev | 2 +- .../WEB-INF/classes/com/pms/mapper/common.xml | 24 +- .../com/pms/mapper/productionplanning.xml | 361 +++++++++-- .../partMng/structureBomCopyFormPopup.jsp | 33 +- .../view/partMng/structurePopupCenter.jsp | 10 +- .../productionplanning/mBomCenterBtnPopup.jsp | 439 +++++++++++++ .../productionplanning/mBomHeaderPopup.jsp | 584 ++++++++++++++++++ .../view/productionplanning/mBomMgmtList.jsp | 50 +- .../productionplanning/mBomPopupCenter.jsp | 146 +++++ .../view/productionplanning/mBomPopupFs.jsp | 7 + .../productionplanning/mBomPopupHeaderFs.jsp | 14 + .../view/productionplanning/mBomPopupLeft.jsp | 231 +++++++ .../productionplanning/mBomPopupRight.jsp | 161 +++++ .../view/productionplanning/mBomPopupTop.jsp | 140 +++++ .../view/productionplanning/mBomViewPopup.jsp | 183 ++++++ src/com/pms/controller/PartMngController.java | 106 +++- .../ProductionPlanningController.java | 236 ++++++- src/com/pms/mapper/partMng.xml | 7 +- src/com/pms/mapper/productionplanning.xml | 295 +++++++++ .../service/ProductionPlanningService.java | 53 ++ 21 files changed, 2987 insertions(+), 99 deletions(-) create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomCenterBtnPopup.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomPopupTop.jsp create mode 100644 WebContent/WEB-INF/view/productionplanning/mBomViewPopup.jsp diff --git a/Dockerfile b/Dockerfile index 0f52dbc..d044e9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,9 @@ RUN rm -rf /usr/local/tomcat/webapps/* # Copy web application content (compiled classes and web resources) COPY WebContent /usr/local/tomcat/webapps/ROOT -COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/src + +# Copy Java source files to classes directory (for mapper XMLs) +COPY src/com /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/com # Copy custom Tomcat context configuration for JNDI COPY ./tomcat-conf/context.xml /usr/local/tomcat/conf/context.xml diff --git a/Dockerfile.dev b/Dockerfile.dev index 03e8b29..2a377cb 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -5,7 +5,7 @@ RUN rm -rf /usr/local/tomcat/webapps/* # Copy web application content (compiled classes and web resources) COPY WebContent /usr/local/tomcat/webapps/ROOT -COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/src +COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/classes # Copy custom Tomcat context configuration for JNDI COPY ./tomcat-conf/context.xml /usr/local/tomcat/conf/context.xml diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/common.xml b/WebContent/WEB-INF/classes/com/pms/mapper/common.xml index d718536..07508a3 100644 --- a/WebContent/WEB-INF/classes/com/pms/mapper/common.xml +++ b/WebContent/WEB-INF/classes/com/pms/mapper/common.xml @@ -2530,18 +2530,18 @@ SELECT option_objid::VARCHAR AS CODE AND PRODUCT_MGMT_OBJID::VARCHAR = #{codeId}::VARCHAR - + SELECT + T.OBJID::varchar AS CODE + ,COALESCE(T.REVISION, T.REV, '1.0') AS NAME + ,T1.PRODUCT_CODE AS CODE_CD + ,'' AS STATUS + ,T.spec_name AS ID + ,'' AS EXT_VAL + FROM PART_BOM_REPORT T,PRODUCT_MGMT T1 +WHERE T.PRODUCT_MGMT_OBJID = T1.OBJID +AND T1.OBJID = #{code}::numeric +ORDER BY COALESCE(T.REVISION, T.REV, '1.0') diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml b/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml index 2edcdb4..ade66d9 100644 --- a/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml +++ b/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml @@ -2870,8 +2870,9 @@ ORDER BY SUBSTRING(PROJECT_NO,POSITION('-' IN PROJECT_NO)+1) DESC - + @@ -3003,4 +2999,299 @@ LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER WHERE T.OBJID::VARCHAR = #{objid} + + + + + + + + + + + + + + + + + SELECT REPLACE(UUID(),'-','') FROM DUAL + + INSERT INTO MBOM_HEADER ( + OBJID, + MBOM_NO, + PART_NO, + PART_NAME, + SAVE_DATE, + CREATE_USER, + CREATE_DATE, + UPDATE_USER, + UPDATE_DATE + ) VALUES ( + #{OBJID}, + CONCAT('MBOM-', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')), + #{PART_NO}, + #{PART_NAME}, + NOW(), + #{CREATE_USER}, + NOW(), + #{UPDATE_USER}, + NOW() + ) + + + + + + SELECT REPLACE(UUID(),'-','') FROM DUAL + + INSERT INTO MBOM_DETAIL ( + OBJID, + MBOM_HEADER_OBJID, + PART_NO, + PART_NAME, + QTY, + LEVEL, + REVISION, + SPEC, + PRODUCT_NAME, + STATUS_NAME, + CREATE_USER, + CREATE_DATE, + UPDATE_USER, + UPDATE_DATE + ) VALUES ( + #{OBJID}, + #{MBOM_HEADER_OBJID}, + #{PART_NO}, + #{PART_NAME}, + #{QTY}, + #{LEVEL}, + #{REVISION}, + #{SPEC}, + #{PRODUCT_NAME}, + #{STATUS_NAME}, + #{CREATE_USER}, + NOW(), + #{UPDATE_USER}, + NOW() + ) + + + + + /* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */ + /* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */ + WITH new_bom_report AS ( + INSERT INTO PART_BOM_REPORT ( + OBJID, + PART_NO, + PART_NAME, + WRITER, + REGDATE, + STATUS + ) VALUES ( + (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER), + #{PART_NO}, + #{PART_NAME}, + #{USER_ID}, + NOW(), + 'Y' + ) + RETURNING OBJID + ), + /* 2. E-BOM의 BOM_PART_QTY 데이터를 새 M-BOM으로 복사 */ + copied_bom_data AS ( + INSERT INTO BOM_PART_QTY ( + BOM_REPORT_OBJID, + OBJID, + PARENT_OBJID, + CHILD_OBJID, + PARENT_PART_NO, + PART_NO, + QTY, + ITEM_QTY, + QTY_TEMP, + REGDATE, + WRITER, + SEQ, + STATUS, + LAST_PART_OBJID + ) + SELECT + (SELECT OBJID FROM new_bom_report), + (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000 + ROW_NUMBER() OVER (ORDER BY OBJID))::INTEGER), + PARENT_OBJID, + CHILD_OBJID, + PARENT_PART_NO, + PART_NO, + QTY, + ITEM_QTY, + QTY_TEMP, + NOW(), + #{USER_ID}, + ROW_NUMBER() OVER (ORDER BY OBJID), + 'adding', + LAST_PART_OBJID + FROM BOM_PART_QTY + WHERE BOM_REPORT_OBJID::VARCHAR = #{SOURCE_BOM_OBJID} + AND COALESCE(STATUS, '') NOT IN ('deleting', 'deleted') + RETURNING 1 + ) + /* 3. PROJECT_MGMT 업데이트 */ + UPDATE PROJECT_MGMT + SET + BOM_REPORT_OBJID = (SELECT OBJID FROM new_bom_report), + MBOM_STATUS = 'Y', + PART_NO = #{PART_NO}, + PART_NAME = #{PART_NAME} + WHERE OBJID::VARCHAR = #{PROJECT_OBJID} + diff --git a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp index 0160a6d..7438365 100644 --- a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp +++ b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp @@ -134,6 +134,14 @@ var selectedBomType = null; // 'EBOM' 또는 'MBOM' var bomGridData = []; // BOM 그리드 데이터 $(function(){ + // 페이지 로드 시 프로젝트 정보가 있으면 품번/품명 자동 입력 + + console.log("projectInfo가 있습니다. 품번/품명 설정 중..."); + $("#COPY_PART_NO").val("${projectInfo.PART_NO}"); + $("#COPY_PART_NAME").val("${projectInfo.PART_NAME}"); + // E-BOM 품번은 사용자가 직접 입력하도록 비워둠 (M-BOM 품번과 다를 수 있음) + + // 담기 버튼 - 선택한 BOM을 복사 대상으로 설정 $("#btnAddItem").click(function(){ var partNo = $("#COPY_PART_NO").val().trim(); @@ -207,6 +215,8 @@ $(function(){ // BOM 미리보기 로드 function fn_loadBomPreview(partNo, bomType) { + console.log("fn_loadBomPreview 호출:", partNo, bomType); + // 먼저 품번으로 BOM OBJID 조회 $.ajax({ url: "/partMng/getBomObjIdByPartNo.do", @@ -214,6 +224,8 @@ function fn_loadBomPreview(partNo, bomType) { data: { partNo: partNo }, dataType: "json", success: function(response) { + console.log("getBomObjIdByPartNo 응답:", response); + if(response && response.OBJID) { $("#bomPartName").text(partNo); // 전역 변수에 저장 @@ -222,10 +234,12 @@ function fn_loadBomPreview(partNo, bomType) { // BOM 트리 데이터 로드 fn_loadBomTree(response.OBJID); } else { + console.error("BOM OBJID를 찾을 수 없음:", response); Swal.fire('해당 품번의 BOM을 찾을 수 없습니다.'); } }, - error: function() { + error: function(xhr, status, error) { + console.error("getBomObjIdByPartNo 에러:", xhr, status, error); Swal.fire('BOM 조회 중 오류가 발생했습니다.'); } }); @@ -233,6 +247,8 @@ function fn_loadBomPreview(partNo, bomType) { // BOM 트리 데이터 로드 function fn_loadBomTree(bomObjId) { + console.log("fn_loadBomTree 호출:", bomObjId); + $.ajax({ url: "/partMng/getStructureTreeJson.do", type: "POST", @@ -243,6 +259,8 @@ function fn_loadBomTree(bomObjId) { }, dataType: "json", success: function(response) { + console.log("getStructureTreeJson 응답:", response); + if(response && response.length > 0) { var maxLevel = response[0].MAX_LEVEL || 3; @@ -260,11 +278,13 @@ function fn_loadBomTree(bomObjId) { fn_initGrid(processedData, maxLevel); } else { + console.warn("BOM 트리 데이터가 비어있음"); bomGridData = []; fn_initGrid([], 3); } }, - error: function() { + error: function(xhr, status, error) { + console.error("getStructureTreeJson 에러:", xhr, status, error); Swal.fire('BOM 트리 조회 중 오류가 발생했습니다.'); } }); @@ -506,6 +526,10 @@ function fn_saveBomCopy() { text: 'M-BOM이 성공적으로 생성되었습니다.', icon: 'success' }).then(() => { + // 부모 창(M-BOM 관리) 새로고침하여 아이콘 업데이트 + if(window.opener && !window.opener.closed) { + window.opener.location.reload(); + } window.close(); }); } else { @@ -607,11 +631,6 @@ function fn_excel() {
- -
- - -
diff --git a/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp b/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp index 4c5934f..f9a1c99 100644 --- a/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp +++ b/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp @@ -422,16 +422,14 @@ function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPa } - +
-
+
-
- -
- + +
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomCenterBtnPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomCenterBtnPopup.jsp new file mode 100644 index 0000000..835ef7f --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomCenterBtnPopup.jsp @@ -0,0 +1,439 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + +
+ + +
+ +
+ +
+ +
+
+ + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp new file mode 100644 index 0000000..2f60269 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp @@ -0,0 +1,584 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + +
+ + +
+ + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + +
+
+
+ + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp index 79d8efa..a043b69 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp @@ -205,8 +205,20 @@ var columns = [ field: 'MBOM_STATUS', formatter: fnc_subInfoValueFormatter, cellClick: function(e, cell) { - var objid = fnc_checkNull(cell.getData().OBJID); - fn_openMBomPopup(objid); + var rowData = cell.getData(); + var objid = fnc_checkNull(rowData.OBJID); + var mbomStatus = fnc_checkNull(rowData.MBOM_STATUS); + + // 파란색(저장된 M-BOM)일 때만 팝업 열기 + if(mbomStatus !== '' && mbomStatus !== '0') { + fn_openMBomFormPopup(objid); + } else { + Swal.fire({ + title: '알림', + text: 'M-BOM이 생성되지 않았습니다.\nBOM 복사 버튼을 통해 먼저 M-BOM을 생성해주세요.', + icon: 'info' + }); + } } }, @@ -271,12 +283,20 @@ function fn_openEBomSelectPopup(projectMgmtObjid, partNo, partName, bomReportObj fn_centerPopup(popup_width, popup_height, url, 'ebomSelectPopup'); } -// M-BOM 팝업 +// M-BOM 조회 팝업 (읽기 전용) function fn_openMBomPopup(objId) { + var popup_width = 1000; + var popup_height = 700; + var url = "/productionplanning/mBomViewPopup.do?objId=" + objId; + fn_centerPopup(popup_width, popup_height, url, 'mbomViewPopup'); +} + +// M-BOM 편집 팝업 (왼쪽 트리 + 중앙 버튼 + 오른쪽 E-BOM) +function fn_openMBomFormPopup(objId) { var popup_width = 1800; - var popup_height = 800; + var popup_height = 900; var url = "/productionplanning/mBomFormPopup.do?objId=" + objId; - fn_centerPopup(popup_width, popup_height, url, 'mbomPopup'); + fn_centerPopup(popup_width, popup_height, url, 'mbomFormPopup'); } // BOM 복사 팝업 @@ -335,22 +355,10 @@ function fn_openBomCopyPopup() { // BOM 복사 팝업 창 열기 function fn_openBomCopyPopupWindow(objId) { - var popup_width = 1400; - var popup_height = 800; - var url = "/partMng/setBomCopyFormPopup.do?objId=" + objId; - var left = (screen.width - popup_width) / 2; - var top = (screen.height - popup_height) / 2; - - var popup = window.open(url, "bomCopyPopup", "width=" + popup_width + ",height=" + popup_height + ",left=" + left + ",top=" + top + ",scrollbars=yes,resizable=yes"); - - // 팝업이 닫힐 때 그리드 새로고침 - var checkPopup = setInterval(function() { - if(popup.closed) { - clearInterval(checkPopup); - console.log("BOM 복사 팝업 닫힘 - 그리드 새로고침"); - fn_search(); - } - }, 500); + var popup_width = 1800; + var popup_height = 900; + var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId; + fn_centerPopup(popup_width, popup_height, url, 'bomCopyPopup'); } diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp new file mode 100644 index 0000000..06fd456 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp @@ -0,0 +1,146 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + +
+ + +
+ +
+ +
+ +
+
+ + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp new file mode 100644 index 0000000..b1d7136 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp @@ -0,0 +1,7 @@ +<%String objId = com.pms.common.utils.CommonUtils.checkNull(request.getParameter("objId"));%> + + + + + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp new file mode 100644 index 0000000..21cfaee --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp @@ -0,0 +1,14 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<% +java.util.Map map = (java.util.HashMap)request.getAttribute("info"); +if(map == null || map.isEmpty()) { + response.sendRedirect("/common/error500.do"); + return; +} +String objId = com.pms.common.utils.CommonUtils.checkNull(map.get("OBJID")); +%> + + + + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp new file mode 100644 index 0000000..f8e27b2 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp @@ -0,0 +1,231 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + + + +
+ + + E-BOM: ${ebomInfo.PART_NO} - ${ebomInfo.PART_NAME} + + + 할당된 E-BOM이 없습니다. + + +
+
+ + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp new file mode 100644 index 0000000..1e6b297 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp @@ -0,0 +1,161 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+
+ +
+
+ + + + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupTop.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupTop.jsp new file mode 100644 index 0000000..5834029 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupTop.jsp @@ -0,0 +1,140 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + +
+
+

+ M-BOM 확인 + + + 프로젝트번호: ${projectNo} + + / 품번: ${partNo} + + + / 품명: ${partName} + + + +

+
+ + +
+ + + + + + + + + + +
+ + + + + + +
+
+
+ + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomViewPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomViewPopup.jsp new file mode 100644 index 0000000..eded7a7 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomViewPopup.jsp @@ -0,0 +1,183 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + + +
+
+

M-BOM 조회

+ + + + + + +
+ + - + + + - + + + - +
+
+ +
+
+
+ + +
+ + + + + diff --git a/src/com/pms/controller/PartMngController.java b/src/com/pms/controller/PartMngController.java index 05f251c..cfb469b 100644 --- a/src/com/pms/controller/PartMngController.java +++ b/src/com/pms/controller/PartMngController.java @@ -16,6 +16,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.SqlSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -888,23 +889,110 @@ public class PartMngController { } /** - * bom copy 저장 + * BOM COPY (M-BOM 관리에서 호출) + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/partMng/structureBomCopyFormPopup.do") + public String structureBomCopyFormPopup(HttpServletRequest request, @RequestParam Map paramMap){ + try { + String objId = CommonUtils.checkNull((String)paramMap.get("objId")); + System.out.println("========== structureBomCopyFormPopup =========="); + System.out.println("objId: " + objId); + + // objId를 항상 설정 (음수 포함) + request.setAttribute("TARGET_OBJID", objId); + + // objId가 유효한 경우 프로젝트 정보 조회 (음수도 유효한 OBJID임) + if(!"".equals(objId) && !"-1".equals(objId)) { + try { + long objIdLong = Long.parseLong(objId); + System.out.println("objIdLong: " + objIdLong); + + // PROJECT_MGMT 테이블에서 품번/품명 조회 (M-BOM 관리 리스트의 OBJID는 PROJECT_MGMT의 OBJID) + Map projectInfo = commonService.selectOne("productionplanning.getProjectMgmtDetail", request, paramMap); + System.out.println("projectInfo: " + projectInfo); + + if(projectInfo != null) { + System.out.println("PART_NO: " + projectInfo.get("PART_NO")); + System.out.println("PART_NAME: " + projectInfo.get("PART_NAME")); + request.setAttribute("projectInfo", projectInfo); + } else { + System.out.println("projectInfo is null!"); + } + } catch(NumberFormatException nfe) { + System.out.println("NumberFormatException: " + nfe.getMessage()); + } + } + + Map code_map = new HashMap(); + code_map.put("rev", commonService.bizMakeOptionList("", "", "common.getRevNoselect")); + code_map.put("product_code", commonService.bizMakeOptionList("", "", "common.getProductNoselect")); + request.setAttribute("code_map", code_map); + + } catch(Exception e) { + e.printStackTrace(); + } + + return "/partMng/structureBomCopyFormPopup"; + } + + /** + * bom copy 저장 (E-BOM을 M-BOM으로 복사) */ @RequestMapping("/partMng/saveBomCopy.do") @ResponseBody - public String saveBomCopySave(HttpSession session, HttpServletRequest request, @RequestParam Map paramMap){ - String result = ""; + public Map saveBomCopySave(HttpSession session, HttpServletRequest request, @RequestBody Map paramMap){ + Map resultMap = new HashMap(); try{ - PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN); - paramMap.put("CONNECTUSERID", CommonUtils.checkNull(person.getUserId())); + System.out.println("========== saveBomCopy =========="); + System.out.println("paramMap: " + paramMap); - partMngService.saveBomCopySave(request, paramMap); - result = "SUCCESS"; + PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN); + String userId = person.getUserId(); + + // targetObjId: PROJECT_MGMT의 OBJID + String targetObjId = CommonUtils.checkNull((String)paramMap.get("targetObjId")); + String sourceBomObjId = CommonUtils.checkNull((String)paramMap.get("sourceBomObjId")); + String targetPartNo = CommonUtils.checkNull((String)paramMap.get("targetPartNo")); + String targetPartName = CommonUtils.checkNull((String)paramMap.get("targetPartName")); + List> bomData = (List>)paramMap.get("bomData"); + + if(bomData == null || bomData.isEmpty()) { + resultMap.put("result", "fail"); + resultMap.put("message", "복사할 BOM 데이터가 없습니다."); + return resultMap; + } + + // M-BOM 저장 + Map saveParam = new HashMap(); + saveParam.put("PROJECT_OBJID", targetObjId); + saveParam.put("SOURCE_BOM_OBJID", sourceBomObjId); + saveParam.put("PART_NO", targetPartNo); + saveParam.put("PART_NAME", targetPartName); + saveParam.put("BOM_DATA", bomData); + saveParam.put("USER_ID", userId); + + // SqlSession을 통해 직접 실행 + SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(); + try { + sqlSession.insert("productionplanning.saveMbomFromEbom", saveParam); + sqlSession.commit(); + + resultMap.put("result", "success"); + resultMap.put("message", "M-BOM이 성공적으로 생성되었습니다."); + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } }catch(Exception e){ e.printStackTrace(); - result = "FAIL"; + resultMap.put("result", "fail"); + resultMap.put("message", "BOM 복사 중 오류가 발생했습니다: " + e.getMessage()); } - return result; + return resultMap; } diff --git a/src/com/pms/controller/ProductionPlanningController.java b/src/com/pms/controller/ProductionPlanningController.java index 7594b9b..9726c7d 100644 --- a/src/com/pms/controller/ProductionPlanningController.java +++ b/src/com/pms/controller/ProductionPlanningController.java @@ -9,10 +9,12 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.google.gson.Gson; import com.pms.common.service.BaseService; import com.pms.common.utils.CommonUtils; import com.pms.common.utils.Constants; @@ -934,13 +936,140 @@ public class ProductionPlanningController extends BaseService { } /** - * M-BOM 팝업 + * M-BOM 조회 팝업 (읽기 전용) + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/mBomViewPopup.do") + public String mBomViewPopup(HttpServletRequest request, @RequestParam Map paramMap) { + return "/productionplanning/mBomViewPopup"; + } + + /** + * M-BOM 복사 팝업 메인 (frameset) * @param request * @param paramMap * @return */ @RequestMapping("/productionplanning/mBomFormPopup.do") public String mBomFormPopup(HttpServletRequest request, @RequestParam Map paramMap) { + try { + String objId = CommonUtils.checkNull(paramMap.get("objId")); + System.out.println("========== mBomFormPopup =========="); + System.out.println("objId: " + objId); + + // PROJECT_MGMT 정보 조회 + if(!"".equals(objId)) { + paramMap.put("objId", objId); + Map projectInfo = commonService.selectOne("productionplanning.getProjectMgmtDetail", request, paramMap); + System.out.println("projectInfo: " + projectInfo); + + if(projectInfo != null && !projectInfo.isEmpty()) { + request.setAttribute("info", projectInfo); + } else { + System.out.println("projectInfo is null or empty!"); + } + } + } catch(Exception e) { + e.printStackTrace(); + } + return "/productionplanning/mBomPopupHeaderFs"; + } + + /** + * M-BOM 조회 팝업 상단 헤더 + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/mBomHeaderPopup.do") + public String mBomHeaderPopup(HttpServletRequest request, @RequestParam Map paramMap) { + try { + String objId = CommonUtils.checkNull(paramMap.get("objId")); + if(!"".equals(objId)) { + paramMap.put("objId", objId); + Map projectInfo = commonService.selectOne("productionplanning.getProjectMgmtDetail", request, paramMap); + request.setAttribute("info", projectInfo); + } + } catch(Exception e) { + e.printStackTrace(); + } + return "/productionplanning/mBomHeaderPopup"; + } + + /** + * M-BOM 조회 팝업 중앙 버튼 영역 + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/mBomCenterBtnPopup.do") + public String mBomCenterBtnPopup(HttpServletRequest request, @RequestParam Map paramMap) { + return "/productionplanning/mBomCenterBtnPopup"; + } + + /** + * M-BOM 조회 팝업 중앙 버튼 영역 + */ + @RequestMapping("/productionplanning/mBomPopupCenter.do") + public String mBomPopupCenter(HttpServletRequest request, @RequestParam Map paramMap) { + return "/productionplanning/mBomPopupCenter"; + } + + /** + * M-BOM 조회 팝업 오른쪽 E-BOM 목록 + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/mBomPopupRight.do") + public String mBomPopupRight(HttpServletRequest request, @RequestParam Map paramMap) { + return "/productionplanning/mBomPopupRight"; + } + + /** + * E-BOM 목록 조회 (AJAX) + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/getEbomList.do") + @ResponseBody + public Map getEbomList(HttpServletRequest request, @RequestParam Map paramMap) { + Map result = new HashMap<>(); + try { + List> list = commonService.selectList("productionplanning.getEbomList", request, paramMap); + result.put("list", list); + result.put("result", true); + } catch(Exception e) { + e.printStackTrace(); + result.put("result", false); + result.put("list", new ArrayList<>()); + } + return result; + } + + /** + * M-BOM 조회 팝업 하단 frameset + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/mBomBottomPopupFS.do") + public String mBomBottomPopupFS(HttpServletRequest request, @RequestParam Map paramMap) { + return "/productionplanning/mBomPopupFs"; + } + + /** + * M-BOM 조회 팝업 왼쪽 트리 + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/productionplanning/mBomPopupLeft.do") + public String mBomPopupLeft(HttpServletRequest request, @RequestParam Map paramMap) { + Gson gson = new Gson(); try { String objId = CommonUtils.checkNull(paramMap.get("objId")); @@ -948,10 +1077,27 @@ public class ProductionPlanningController extends BaseService { if(!"".equals(objId)) { paramMap.put("objId", objId); Map projectInfo = commonService.selectOne("productionplanning.getProjectMgmtDetail", request, paramMap); - request.setAttribute("info", projectInfo); - // 할당된 E-BOM 정보 조회 if(projectInfo != null) { + // 1. 먼저 저장된 M-BOM 데이터가 있는지 확인 + List> mbomDetailList = commonService.selectList("productionplanning.getMbomDetailByProject", request, paramMap); + + if(mbomDetailList != null && !mbomDetailList.isEmpty()) { + // 저장된 M-BOM 데이터가 있으면 이를 표시 + int maxLevel = 1; + for(Map item : mbomDetailList) { + Integer level = (Integer) item.get("LEVEL"); + if(level != null && level > maxLevel) { + maxLevel = level; + } + } + + request.setAttribute("MAXLEV", maxLevel); + request.setAttribute("bomTreeListJson", gson.toJson(mbomDetailList)); + return "/productionplanning/mBomPopupLeft"; + } + + // 저장된 M-BOM이 없으면 할당된 E-BOM 정보 조회 String bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID")); if(!"".equals(bomReportObjid)) { Map ebomParam = new HashMap<>(); @@ -964,14 +1110,31 @@ public class ProductionPlanningController extends BaseService { // BOM 트리 데이터 조회 (레벨 정보 포함) List> bomTreeList = commonService.selectList("partMng.getBOMTreeList", request, ebomParam); - request.setAttribute("bomTreeList", bomTreeList); + + if(bomTreeList != null && !bomTreeList.isEmpty()) { + // MAX LEVEL 계산 + int maxLevel = 1; + for(Map item : bomTreeList) { + Integer level = (Integer) item.get("LEVEL"); + if(level != null && level > maxLevel) { + maxLevel = level; + } + } + request.setAttribute("MAXLEV", maxLevel); + request.setAttribute("bomTreeListJson", gson.toJson(bomTreeList)); + return "/productionplanning/mBomPopupLeft"; + } } } } } catch(Exception e) { e.printStackTrace(); } - return "/productionplanning/mBomFormPopup"; + + // 데이터가 없을 때 빈 배열 설정 + request.setAttribute("MAXLEV", 1); + request.setAttribute("bomTreeListJson", "[]"); + return "/productionplanning/mBomPopupLeft"; } /** @@ -1011,4 +1174,67 @@ public class ProductionPlanningController extends BaseService { } return resultMap; } + + /** + * M-BOM 목록 조회 (검색 조건 포함) + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/getMbomList.do") + public Map getMbomList(HttpServletRequest request, @RequestParam Map paramMap) { + Map result = new HashMap<>(); + try { + // 검색 조건에 맞는 M-BOM 목록 조회 + List> list = commonService.selectList("productionplanning.getMbomList", request, paramMap); + result.put("list", list); + result.put("result", true); + } catch(Exception e) { + e.printStackTrace(); + result.put("result", false); + result.put("list", new ArrayList<>()); + } + return result; + } + + /** + * M-BOM 저장 + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/saveMbom.do") + public Map saveMbom(HttpServletRequest request, @RequestBody Map paramMap) { + Map resultMap = new HashMap<>(); + try { + // M-BOM 데이터 저장 로직 + List> mbomData = (List>) paramMap.get("mbomData"); + String partNo = CommonUtils.checkNull(paramMap.get("partNo")); + String partName = CommonUtils.checkNull(paramMap.get("partName")); + + if(mbomData == null || mbomData.isEmpty()) { + resultMap.put("result", "fail"); + resultMap.put("message", "저장할 데이터가 없습니다."); + return resultMap; + } + + // M-BOM 저장 서비스 호출 + int saveResult = productionPlanningService.saveMbom(request, mbomData, partNo, partName); + + if(saveResult > 0) { + resultMap.put("result", "success"); + resultMap.put("message", "M-BOM이 저장되었습니다."); + } else { + resultMap.put("result", "fail"); + resultMap.put("message", "저장에 실패했습니다."); + } + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("result", "fail"); + resultMap.put("message", "오류가 발생했습니다: " + e.getMessage()); + } + return resultMap; + } } diff --git a/src/com/pms/mapper/partMng.xml b/src/com/pms/mapper/partMng.xml index 8c9a0b9..ef4ce06 100644 --- a/src/com/pms/mapper/partMng.xml +++ b/src/com/pms/mapper/partMng.xml @@ -3007,8 +3007,11 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.* PART_NAME FROM PART_BOM_REPORT WHERE PART_NO = #{partNo} - AND (STATUS IS NULL OR STATUS != 'deleted') - ORDER BY CREATE_DATE DESC + AND PART_NO IS NOT NULL + AND TRIM(PART_NO) != '' + AND PART_NAME IS NOT NULL + AND TRIM(PART_NAME) != '' + ORDER BY REGDATE DESC LIMIT 1 diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index f416654..ade66d9 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -2999,4 +2999,299 @@ LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER WHERE T.OBJID::VARCHAR = #{objid} + + + + + + + + + + + + + + + + + SELECT REPLACE(UUID(),'-','') FROM DUAL + + INSERT INTO MBOM_HEADER ( + OBJID, + MBOM_NO, + PART_NO, + PART_NAME, + SAVE_DATE, + CREATE_USER, + CREATE_DATE, + UPDATE_USER, + UPDATE_DATE + ) VALUES ( + #{OBJID}, + CONCAT('MBOM-', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')), + #{PART_NO}, + #{PART_NAME}, + NOW(), + #{CREATE_USER}, + NOW(), + #{UPDATE_USER}, + NOW() + ) + + + + + + SELECT REPLACE(UUID(),'-','') FROM DUAL + + INSERT INTO MBOM_DETAIL ( + OBJID, + MBOM_HEADER_OBJID, + PART_NO, + PART_NAME, + QTY, + LEVEL, + REVISION, + SPEC, + PRODUCT_NAME, + STATUS_NAME, + CREATE_USER, + CREATE_DATE, + UPDATE_USER, + UPDATE_DATE + ) VALUES ( + #{OBJID}, + #{MBOM_HEADER_OBJID}, + #{PART_NO}, + #{PART_NAME}, + #{QTY}, + #{LEVEL}, + #{REVISION}, + #{SPEC}, + #{PRODUCT_NAME}, + #{STATUS_NAME}, + #{CREATE_USER}, + NOW(), + #{UPDATE_USER}, + NOW() + ) + + + + + /* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */ + /* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */ + WITH new_bom_report AS ( + INSERT INTO PART_BOM_REPORT ( + OBJID, + PART_NO, + PART_NAME, + WRITER, + REGDATE, + STATUS + ) VALUES ( + (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER), + #{PART_NO}, + #{PART_NAME}, + #{USER_ID}, + NOW(), + 'Y' + ) + RETURNING OBJID + ), + /* 2. E-BOM의 BOM_PART_QTY 데이터를 새 M-BOM으로 복사 */ + copied_bom_data AS ( + INSERT INTO BOM_PART_QTY ( + BOM_REPORT_OBJID, + OBJID, + PARENT_OBJID, + CHILD_OBJID, + PARENT_PART_NO, + PART_NO, + QTY, + ITEM_QTY, + QTY_TEMP, + REGDATE, + WRITER, + SEQ, + STATUS, + LAST_PART_OBJID + ) + SELECT + (SELECT OBJID FROM new_bom_report), + (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000 + ROW_NUMBER() OVER (ORDER BY OBJID))::INTEGER), + PARENT_OBJID, + CHILD_OBJID, + PARENT_PART_NO, + PART_NO, + QTY, + ITEM_QTY, + QTY_TEMP, + NOW(), + #{USER_ID}, + ROW_NUMBER() OVER (ORDER BY OBJID), + 'adding', + LAST_PART_OBJID + FROM BOM_PART_QTY + WHERE BOM_REPORT_OBJID::VARCHAR = #{SOURCE_BOM_OBJID} + AND COALESCE(STATUS, '') NOT IN ('deleting', 'deleted') + RETURNING 1 + ) + /* 3. PROJECT_MGMT 업데이트 */ + UPDATE PROJECT_MGMT + SET + BOM_REPORT_OBJID = (SELECT OBJID FROM new_bom_report), + MBOM_STATUS = 'Y', + PART_NO = #{PART_NO}, + PART_NAME = #{PART_NAME} + WHERE OBJID::VARCHAR = #{PROJECT_OBJID} + diff --git a/src/com/pms/service/ProductionPlanningService.java b/src/com/pms/service/ProductionPlanningService.java index 3f3f063..bb6e7c5 100644 --- a/src/com/pms/service/ProductionPlanningService.java +++ b/src/com/pms/service/ProductionPlanningService.java @@ -749,4 +749,57 @@ public class ProductionPlanningService { return resultMap; } + + /** + * M-BOM 저장 + * @param request + * @param mbomData + * @param partNo + * @param partName + * @return + */ + public int saveMbom(HttpServletRequest request, List> mbomData, String partNo, String partName) { + SqlSession sqlSession = null; + int result = 0; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + HttpSession session = request.getSession(); + PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN); + String userId = CommonUtils.checkNull(person.getUserId()); + + // M-BOM 헤더 정보 생성 + Map headerMap = new HashMap<>(); + headerMap.put("PART_NO", partNo); + headerMap.put("PART_NAME", partName); + headerMap.put("CREATE_USER", userId); + headerMap.put("UPDATE_USER", userId); + + // M-BOM 헤더 저장 + sqlSession.insert("productionplanning.insertMbomHeader", headerMap); + String mbomHeaderObjid = (String) headerMap.get("OBJID"); + + // M-BOM 상세 데이터 저장 + for(Map item : mbomData) { + item.put("MBOM_HEADER_OBJID", mbomHeaderObjid); + item.put("CREATE_USER", userId); + item.put("UPDATE_USER", userId); + sqlSession.insert("productionplanning.insertMbomDetail", item); + } + + sqlSession.commit(); + result = 1; + } catch(Exception e) { + if(sqlSession != null) { + sqlSession.rollback(); + } + e.printStackTrace(); + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + + return result; + } }