From 8954ae559ed1f871d271639b36ca3eb8b750b4fc Mon Sep 17 00:00:00 2001 From: Johngreen Date: Wed, 29 Oct 2025 11:58:56 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=EC=83=9D=EC=82=B0=EA=B4=80=EB=A6=AC=5FM-BO?= =?UTF-8?q?M=EA=B4=80=EB=A6=AC=EC=AA=BD=20e-bom=ED=8C=9D=EC=97=85=EC=99=84?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/pms/mapper/productionplanning.xml | 8 +++ .../mBomEbomSelectPopup.jsp | 51 +++++++++++++++++++ .../ProductionPlanningController.java | 37 ++++++++++++++ src/com/pms/mapper/productionplanning.xml | 8 +++ .../service/ProductionPlanningService.java | 30 +++++++++++ 5 files changed, 134 insertions(+) diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml b/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml index 2edcdb4..5d60271 100644 --- a/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml +++ b/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml @@ -2985,6 +2985,14 @@ WHERE OBJID = #{projectMgmtObjid} + + + UPDATE PROJECT_MGMT + SET + PART_OBJID = NULL + WHERE OBJID = #{projectMgmtObjid} + + diff --git a/src/com/pms/controller/ProductionPlanningController.java b/src/com/pms/controller/ProductionPlanningController.java index 8de2da3..70e4ec3 100644 --- a/src/com/pms/controller/ProductionPlanningController.java +++ b/src/com/pms/controller/ProductionPlanningController.java @@ -970,4 +970,41 @@ public class ProductionPlanningController extends BaseService { } return resultMap; } + + /** + * M-BOM에서 E-BOM 제거 + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/removeEbomFromMbom.do") + public Map removeEbomFromMbom(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap<>(); + try { + String projectMgmtObjid = CommonUtils.checkNull(paramMap.get("projectMgmtObjid")); + + if(projectMgmtObjid.isEmpty()) { + resultMap.put("success", false); + resultMap.put("message", "필수 파라미터가 누락되었습니다."); + return resultMap; + } + + // PROJECT_MGMT 테이블의 PART_OBJID를 null로 업데이트 + int updateResult = productionPlanningService.removeEbomFromProject(projectMgmtObjid); + + if(updateResult > 0) { + resultMap.put("success", true); + resultMap.put("message", "E-BOM이 제거되었습니다."); + } else { + resultMap.put("success", false); + resultMap.put("message", "제거에 실패했습니다."); + } + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("success", false); + resultMap.put("message", "오류가 발생했습니다: " + e.getMessage()); + } + return resultMap; + } } diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index 2edcdb4..5d60271 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -2985,6 +2985,14 @@ WHERE OBJID = #{projectMgmtObjid} + + + UPDATE PROJECT_MGMT + SET + PART_OBJID = NULL + WHERE OBJID = #{projectMgmtObjid} + + + + + + + + + + + + INSERT INTO m_bom_data ( + objid, + project_mgmt_objid, + bom_report_objid, + parent_objid, + child_objid, + parent_part_no, + part_no, + part_name, + qty, + aggregate_qty, + level, + material, + heat_treat_hardness, + heat_treat_method, + surface_treatment, + supplier_name, + category_name, + raw_material, + size, + order_qty, + quantity, + production_qty, + processor_name, + process_due_date, + grinding_due_date, + writer, + regdate + ) VALUES ( + #{OBJID}::NUMERIC, + #{projectMgmtObjid}::NUMERIC, + #{BOM_REPORT_OBJID}::NUMERIC, + + + #{PARENT_OBJID}::NUMERIC, + + + NULL, + + + + + #{CHILD_OBJID}::NUMERIC, + + + NULL, + + + #{PARENT_PART_NO}, + #{PART_NO}, + #{PART_NAME}, + #{QTY}::NUMERIC, + #{AGGREGATE_QTY}::NUMERIC, + #{LEVEL}::INTEGER, + #{MATERIAL}, + #{HEAT_TREAT_HARDNESS}, + #{HEAT_TREAT_METHOD}, + #{SURFACE_TREATMENT}, + #{SUPPLIER_NAME}, + #{CATEGORY_NAME}, + #{RAW_MATERIAL}, + #{SIZE}, + #{ORDER_QTY}::NUMERIC, + #{QUANTITY}::NUMERIC, + #{PRODUCTION_QTY}::NUMERIC, + #{PROCESSOR_NAME}, + #{PROCESS_DUE_DATE}, + #{GRINDING_DUE_DATE}, + #{writer}, + NOW() + ) + + + + + UPDATE project_mgmt + SET + mbom_version = COALESCE(mbom_version, 0) + 1, + mbom_regdate = NOW(), + mbom_writer = #{writer}, + mbom_status = 'Y' + WHERE objid = #{projectMgmtObjid} + + + + + UPDATE m_bom_data + SET + STATUS = 'DELETED', + EDIT_DATE = NOW() + WHERE PROJECT_MGMT_OBJID = #{projectMgmtObjid}::NUMERIC + AND STATUS = 'ACTIVE' + + + + + UPDATE project_mgmt + SET + mbom_status = NULL, + mbom_version = NULL, + mbom_regdate = NULL, + mbom_writer = NULL + WHERE objid = #{projectMgmtObjid} + + + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomEbomSelectPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomEbomSelectPopup.jsp index 1e522bc..48645a5 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomEbomSelectPopup.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomEbomSelectPopup.jsp @@ -28,32 +28,33 @@ } .current-ebom-section { background: #f9f9f9; - padding: 20px; + padding: 10px 15px; margin-bottom: 10px; border: 1px solid #ddd; border-radius: 5px; } .current-ebom-section h4 { - margin: 0 0 15px 0; + margin: 0 0 8px 0; color: #333; - font-size: 16px; + font-size: 13px; } .ebom-info-table { width: 100%; border-collapse: collapse; background: white; - margin-bottom: 15px; + margin-bottom: 8px; + font-size: 12px; } .ebom-info-table th { background: #f5f5f5; - padding: 10px; + padding: 6px 8px; text-align: left; border: 1px solid #ddd; - width: 150px; + width: 120px; font-weight: bold; } .ebom-info-table td { - padding: 10px; + padding: 6px 8px; border: 1px solid #ddd; } .ebom-list-section { @@ -314,7 +315,7 @@ function fn_removeEbom() {
-

다른 E-BOM으로 변경하려면 "E-BOM 변경" 버튼을 클릭하세요.

+

다른 E-BOM으로 변경하려면 "E-BOM 변경" 버튼을 클릭하세요.

diff --git a/WebContent/WEB-INF/view/productionplanning/mBomFormPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomFormPopup.jsp new file mode 100644 index 0000000..c8f5ddb --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/mBomFormPopup.jsp @@ -0,0 +1,694 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ page import="java.util.*" %> +<%@include file= "/init.jsp" %> + + + + +<%=Constants.SYSTEM_NAME%> + + + + + + +
+ + +
+ +
+

M-BOM 관리 - 프로젝트: ${projectInfo.PROJECT_NO} / 품번: ${projectInfo.PART_NO} / 품명: ${projectInfo.PART_NAME}

+
+ + + +
+
+ + +
+
+
+
+
+ + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp index d467ff0..cce200a 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp @@ -283,7 +283,7 @@ function fn_openEBomSelectPopup(projectMgmtObjid, partNo, partName, bomReportObj // M-BOM 팝업 function fn_openMBomPopup(objId) { - var popup_width = 1800; + var popup_width = 1400; var popup_height = 800; var url = "/productionplanning/mBomFormPopup.do?objId=" + objId; fn_centerPopup(popup_width, popup_height, url, 'mbomPopup'); diff --git a/src/com/pms/controller/ProductionPlanningController.java b/src/com/pms/controller/ProductionPlanningController.java index 70e4ec3..0862221 100644 --- a/src/com/pms/controller/ProductionPlanningController.java +++ b/src/com/pms/controller/ProductionPlanningController.java @@ -1007,4 +1007,168 @@ public class ProductionPlanningController extends BaseService { } return resultMap; } + + /** + * M-BOM 팝업 + * @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")); + + // PROJECT_MGMT 기본 정보 조회 + if(!objId.isEmpty()) { + Map projectInfo = productionPlanningService.getProjectMgmtInfo(objId); + request.setAttribute("projectInfo", projectInfo); + + // E-BOM이 할당되어 있는지 확인 (PART_OBJID 사용) + String partObjid = CommonUtils.checkNull(projectInfo.get("PART_OBJID")); + if(!partObjid.isEmpty()) { + // E-BOM 정보 조회 + Map ebomInfo = productionPlanningService.getEbomInfo(partObjid); + request.setAttribute("ebomInfo", ebomInfo); + } + } + } catch(Exception e) { + e.printStackTrace(); + } + return "/productionplanning/mBomFormPopup"; + } + + /** + * M-BOM 그리드 데이터 조회 (저장된 M-BOM 또는 빈 데이터) + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/getMBomGridData.do") + public Map getMBomGridData(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap<>(); + try { + String projectMgmtObjid = CommonUtils.checkNull(paramMap.get("projectMgmtObjid")); + + if(projectMgmtObjid.isEmpty()) { + resultMap.put("success", false); + resultMap.put("message", "프로젝트 정보가 없습니다."); + return resultMap; + } + + // 저장된 M-BOM 데이터 조회 (없으면 빈 리스트) + List> mbomList = productionPlanningService.getSavedMBomData(projectMgmtObjid); + + resultMap.put("success", true); + resultMap.put("data", mbomList); + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("success", false); + resultMap.put("message", "오류가 발생했습니다: " + e.getMessage()); + } + return resultMap; + } + + /** + * E-BOM을 M-BOM으로 복사 + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/copyEbomToMbom.do") + public Map copyEbomToMbom(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap<>(); + try { + System.out.println("===== copyEbomToMbom 호출됨 ====="); + System.out.println("paramMap: " + paramMap); + System.out.println("paramMap.projectMgmtObjid: " + paramMap.get("projectMgmtObjid")); + + String projectMgmtObjid = CommonUtils.checkNull(paramMap.get("projectMgmtObjid")); + System.out.println("변환된 projectMgmtObjid: " + projectMgmtObjid); + + if(projectMgmtObjid.isEmpty()) { + System.out.println("projectMgmtObjid가 비어있음!"); + resultMap.put("success", false); + resultMap.put("message", "프로젝트 정보가 없습니다."); + return resultMap; + } + + // E-BOM 데이터를 M-BOM으로 복사 + System.out.println("getMBomDataFromEbom 호출 - projectMgmtObjid: " + projectMgmtObjid); + List> mbomList = productionPlanningService.getMBomDataFromEbom(projectMgmtObjid); + System.out.println("조회된 mbomList 크기: " + (mbomList != null ? mbomList.size() : "null")); + + if(mbomList == null || mbomList.isEmpty()) { + resultMap.put("success", false); + resultMap.put("message", "E-BOM 데이터가 없습니다. 먼저 E-BOM을 할당해주세요."); + return resultMap; + } + + resultMap.put("success", true); + resultMap.put("data", mbomList); + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("success", false); + resultMap.put("message", "오류가 발생했습니다: " + e.getMessage()); + } + return resultMap; + } + + /** + * M-BOM 데이터 저장 + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/saveMBomData.do") + public Map saveMBomData(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap<>(); + try { + // M-BOM 데이터 저장 로직 + productionPlanningService.saveMBomData(request, paramMap); + + resultMap.put("success", true); + resultMap.put("message", "M-BOM이 저장되었습니다."); + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("success", false); + resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage()); + } + return resultMap; + } + + /** + * M-BOM 데이터 삭제 + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/productionplanning/deleteMBomData.do") + public Map deleteMBomData(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap<>(); + try { + String projectMgmtObjid = CommonUtils.checkNull(paramMap.get("projectMgmtObjid")); + + if(projectMgmtObjid.isEmpty()) { + resultMap.put("success", false); + resultMap.put("message", "프로젝트 정보가 없습니다."); + return resultMap; + } + + // M-BOM 데이터 삭제 로직 + productionPlanningService.deleteMBomData(projectMgmtObjid); + + resultMap.put("success", true); + resultMap.put("message", "M-BOM이 삭제되었습니다."); + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("success", false); + resultMap.put("message", "삭제 중 오류가 발생했습니다: " + e.getMessage()); + } + return resultMap; + } } diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index 5d60271..2926e4e 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -3011,4 +3011,326 @@ LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER WHERE T.OBJID::VARCHAR = #{objid} + + + + + + + + + + INSERT INTO m_bom_data ( + objid, + project_mgmt_objid, + bom_report_objid, + parent_objid, + child_objid, + parent_part_no, + part_no, + part_name, + qty, + aggregate_qty, + level, + material, + heat_treat_hardness, + heat_treat_method, + surface_treatment, + supplier_name, + category_name, + raw_material, + size, + order_qty, + quantity, + production_qty, + processor_name, + process_due_date, + grinding_due_date, + writer, + regdate + ) VALUES ( + #{OBJID}::NUMERIC, + #{projectMgmtObjid}::NUMERIC, + #{BOM_REPORT_OBJID}::NUMERIC, + + + #{PARENT_OBJID}::NUMERIC, + + + NULL, + + + + + #{CHILD_OBJID}::NUMERIC, + + + NULL, + + + #{PARENT_PART_NO}, + #{PART_NO}, + #{PART_NAME}, + #{QTY}::NUMERIC, + #{AGGREGATE_QTY}::NUMERIC, + #{LEVEL}::INTEGER, + #{MATERIAL}, + #{HEAT_TREAT_HARDNESS}, + #{HEAT_TREAT_METHOD}, + #{SURFACE_TREATMENT}, + #{SUPPLIER_NAME}, + #{CATEGORY_NAME}, + #{RAW_MATERIAL}, + #{SIZE}, + #{ORDER_QTY}::NUMERIC, + #{QUANTITY}::NUMERIC, + #{PRODUCTION_QTY}::NUMERIC, + #{PROCESSOR_NAME}, + #{PROCESS_DUE_DATE}, + #{GRINDING_DUE_DATE}, + #{writer}, + NOW() + ) + + + + + UPDATE project_mgmt + SET + mbom_version = COALESCE(mbom_version, 0) + 1, + mbom_regdate = NOW(), + mbom_writer = #{writer}, + mbom_status = 'Y' + WHERE objid = #{projectMgmtObjid} + + + + + UPDATE m_bom_data + SET + STATUS = 'DELETED', + EDIT_DATE = NOW() + WHERE PROJECT_MGMT_OBJID = #{projectMgmtObjid}::NUMERIC + AND STATUS = 'ACTIVE' + + + + + UPDATE project_mgmt + SET + mbom_status = NULL, + mbom_version = NULL, + mbom_regdate = NULL, + mbom_writer = NULL + WHERE objid = #{projectMgmtObjid} + + + + diff --git a/src/com/pms/service/ProductionPlanningService.java b/src/com/pms/service/ProductionPlanningService.java index 34e60e7..ff25306 100644 --- a/src/com/pms/service/ProductionPlanningService.java +++ b/src/com/pms/service/ProductionPlanningService.java @@ -779,4 +779,201 @@ public class ProductionPlanningService { return resultMap; } + + /** + * PROJECT_MGMT 정보 조회 + * @param projectMgmtObjid + * @return + */ + public Map getProjectMgmtInfo(String projectMgmtObjid) { + Map resultMap = new HashMap<>(); + SqlSession sqlSession = null; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + Map paramMap = new HashMap<>(); + paramMap.put("objid", projectMgmtObjid); + resultMap = sqlSession.selectOne("productionplanning.getProjectMgmtInfo", paramMap); + } catch(Exception e) { + e.printStackTrace(); + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + + return resultMap; + } + + /** + * 저장된 M-BOM 데이터 조회 (없으면 빈 리스트 반환) + * @param projectMgmtObjid + * @return + * @throws Exception + */ + public List> getSavedMBomData(String projectMgmtObjid) throws Exception { + List> resultList = new ArrayList<>(); + SqlSession sqlSession = null; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + + Map paramMap = new HashMap<>(); + paramMap.put("projectMgmtObjid", projectMgmtObjid); + + // 저장된 M-BOM 데이터 조회 + resultList = sqlSession.selectList("productionplanning.getSavedMBomData", paramMap); + + } catch(Exception e) { + e.printStackTrace(); + throw e; + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + + return resultList; + } + + /** + * E-BOM 데이터를 기반으로 M-BOM 데이터 조회/생성 + * @param projectMgmtObjid + * @return + * @throws Exception + */ + public List> getMBomDataFromEbom(String projectMgmtObjid) throws Exception { + List> resultList = new ArrayList<>(); + SqlSession sqlSession = null; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + + // PROJECT_MGMT 정보 조회 + Map paramMap = new HashMap<>(); + paramMap.put("objid", projectMgmtObjid); + + Map projectInfo = sqlSession.selectOne("productionplanning.getProjectMgmtInfo", paramMap); + + if(projectInfo != null) { + // PART_OBJID 사용 (E-BOM의 OBJID) + String partObjid = CommonUtils.checkNull(projectInfo.get("PART_OBJID")); + + if(!partObjid.isEmpty()) { + // E-BOM이 할당되어 있으면 E-BOM 데이터를 복사하여 M-BOM으로 반환 + paramMap.put("bomReportObjid", partObjid); + resultList = sqlSession.selectList("productionplanning.getMBomDataFromEbom", paramMap); + } + } + + } catch(Exception e) { + e.printStackTrace(); + throw e; + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + + return resultList; + } + + /** + * M-BOM 데이터 저장 + * @param request + * @param paramMap + * @throws Exception + */ + public void saveMBomData(HttpServletRequest request, Map paramMap) throws Exception { + SqlSession sqlSession = null; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + HttpSession session = request.getSession(); + PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN); + String userId = person.getUserId(); + + // M-BOM 그리드 데이터 파싱 + List> gridDataList = JsonUtil.JsonToList(CommonUtils.checkNull(paramMap.get("gridData"))); + + String projectMgmtObjid = CommonUtils.checkNull(paramMap.get("projectMgmtObjid")); + + // 기존 M-BOM 데이터 삭제 (필요한 경우) + if(!projectMgmtObjid.isEmpty()) { + sqlSession.delete("productionplanning.deleteMBomData", paramMap); + } + + // M-BOM 데이터 저장 + for(Map data : gridDataList) { + data.put("projectMgmtObjid", projectMgmtObjid); + data.put("writer", userId); + + // 항상 새로운 OBJID 생성 (E-BOM의 OBJID와 충돌 방지) + data.put("OBJID", CommonUtils.createObjId()); + + // 빈 문자열을 null로 변환 (NUMERIC 타입 컬럼들) + if(CommonUtils.checkNull(data.get("PARENT_OBJID")).isEmpty()) { + data.put("PARENT_OBJID", null); + } + if(CommonUtils.checkNull(data.get("CHILD_OBJID")).isEmpty()) { + data.put("CHILD_OBJID", null); + } + + sqlSession.insert("productionplanning.insertMBomData", data); + } + + // PROJECT_MGMT의 M-BOM 버전 업데이트 + Map updateMap = new HashMap<>(); + updateMap.put("projectMgmtObjid", projectMgmtObjid); + updateMap.put("writer", userId); + sqlSession.update("productionplanning.updateMBomVersion", updateMap); + + sqlSession.commit(); + + } catch(Exception e) { + if(sqlSession != null) { + sqlSession.rollback(); + } + e.printStackTrace(); + throw e; + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + } + + /** + * M-BOM 데이터 삭제 + * @param projectMgmtObjid + * @throws Exception + */ + public void deleteMBomData(String projectMgmtObjid) throws Exception { + SqlSession sqlSession = null; + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + + Map paramMap = new HashMap<>(); + paramMap.put("projectMgmtObjid", projectMgmtObjid); + + // M-BOM 데이터 삭제 + sqlSession.delete("productionplanning.deleteMBomData", paramMap); + + // PROJECT_MGMT의 MBOM_STATUS를 NULL로 업데이트 + sqlSession.update("productionplanning.resetMBomStatus", paramMap); + + sqlSession.commit(); + + } catch(Exception e) { + if(sqlSession != null) { + sqlSession.rollback(); + } + e.printStackTrace(); + throw e; + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + } } diff --git a/test_contract_registration.md b/test_contract_registration.md deleted file mode 100644 index 9ad83bd..0000000 --- a/test_contract_registration.md +++ /dev/null @@ -1,166 +0,0 @@ -# 영업관리 등록창 테스트 가이드 - -## 📋 테스트 개요 - -`docs/영업_계약_수정.md` 문서에 따라 구현된 새로운 영업관리 등록창의 데이터 저장 기능을 테스트합니다. - -## 🚀 테스트 환경 - -- **서버 URL**: http://localhost:8090 -- **테스트 계정**: plm_admin (패스워드는 관리자에게 문의) -- **테스트 페이지**: http://localhost:8090/contractMgmt/contracMgmtFormPopup.do - -## ✅ 구현 완료 사항 - -### 1. 백엔드 수정 완료 -- **ContractMgmtController.java**: 신규 공통코드 2개 추가 (통화단위, 계약방식) -- **ContractMgmtService.java**: CONTRACT_MGMT 테이블 사용하도록 변경, 25개 신규 필드 처리 -- **contractMgmt.xml**: saveContractMgmtInfo 쿼리에 25개 신규 필드 추가 - -### 2. 프론트엔드 수정 완료 -- **contracMgmtFormPopup.jsp**: 5개 섹션으로 재구성 - - 📋 [영업정보] - - 🔧 [사양상세] - - 📈 [영업진행] - - 💰 [견적이력 및 결과] - - 📝 [특이사항] - -### 3. 데이터베이스 준비 완료 -- **공통코드 데이터**: 6개 공통코드의 부모/하위 데이터 준비 완료 -- **테이블 구조**: CONTRACT_MGMT 테이블에 25개 신규 필드 확인 - -## 🧪 테스트 절차 - -### Step 1: 로그인 -1. http://localhost:8090 접속 -2. plm_admin 계정으로 로그인 - -### Step 2: 영업관리 화면 접근 -1. 메뉴에서 "영업관리" → "계약관리" 선택 -2. "등록" 버튼 클릭하여 등록창 열기 - -### Step 3: 테스트 데이터 입력 - -#### 📋 [영업정보] 섹션 -- **계약구분**: 개발 선택 -- **과거프로젝트번호**: PRJ-2024-001 -- **고객사**: 기존 고객사 선택 -- **제품군**: 기존 제품 선택 -- **장비명**: 테스트 압력용기 시스템 -- **설비대수**: 2 -- **요청납기일**: 2025-12-31 -- **입고지**: 서울특별시 강남구 -- **셋업지**: 경기도 성남시 - -#### 🔧 [사양상세] 섹션 -- **재질**: SUS304 -- **압력(BAR)**: 10.5 -- **온도(℃)**: 85 -- **용량(LITER)**: 1000 -- **Closure Type**: Bolted Cover -- **기타(소모품)**: 가스켓, 볼트 -- **전압**: 220V -- **인증여부**: KS 인증 완료 - -#### 📈 [영업진행] 섹션 -- **진행단계**: 견적제출 선택 - -#### 💰 [견적이력 및 결과] 섹션 -- **통화**: KRW 선택 -- **견적금액(1차)**: 50,000,000 -- **견적금액(2차)**: 48,000,000 -- **견적금액(3차)**: 45,000,000 -- **수주일**: 2025-08-15 -- **수주가**: 자동계산 확인 (90,000,000) -- **Result**: 수주 선택 -- **계약방식**: 조달 선택 -- **P/O No**: PO-2025-001 -- **PM**: 기존 사용자 선택 -- **당사프로젝트명**: 압력용기 개발 프로젝트 - -#### 📝 [특이사항] 섹션 -``` -고객 요구사항: 내압 테스트 필수 -납기일 엄수 요청 -품질 인증서 제출 필요 -``` - -### Step 4: 저장 테스트 -1. "저장" 버튼 클릭 -2. 성공 메시지 확인 -3. 저장된 데이터 목록에서 확인 - -## 🔍 검증 포인트 - -### 1. 화면 구성 검증 -- [ ] 5개 섹션이 올바르게 표시되는가? -- [ ] 공통코드 선택 옵션이 정상 로딩되는가? -- [ ] 자동계산 기능이 동작하는가? (수주가 = 최신견적금액 × 설비대수) - -### 2. 데이터 저장 검증 -- [ ] 25개 신규 필드가 모두 저장되는가? -- [ ] 기존 필드와 신규 필드가 함께 저장되는가? -- [ ] 저장 후 목록에서 데이터가 확인되는가? - -### 3. 오류 처리 검증 -- [ ] 필수 필드 누락 시 적절한 오류 메시지가 표시되는가? -- [ ] 잘못된 데이터 입력 시 검증이 동작하는가? - -## 🐛 알려진 이슈 - -### 1. 로그인 세션 필요 -- API 직접 호출 시 세션 인증이 필요함 -- 브라우저에서 로그인 후 테스트 권장 - -### 2. 공통코드 데이터 -- 신규 공통코드 2개(통화단위, 계약방식)가 아직 데이터베이스에 등록되지 않았을 수 있음 -- 필요시 `docs/insert_common_codes.sql` 실행 - -## 📊 테스트 결과 기록 - -### 성공 케이스 -```json -{ - "RESULT": { - "result": true, - "msg": "저장되었습니다." - } -} -``` - -### 실패 케이스 -```json -{ - "RESULT": { - "result": false, - "msg": "저장에 실패하였습니다." - } -} -``` - -## 🔧 문제 해결 - -### 1. 저장 실패 시 -1. 브라우저 개발자 도구에서 네트워크 탭 확인 -2. 서버 로그 확인: `docker-compose -f docker-compose.dev.yml logs plm-ilshin` -3. 데이터베이스 연결 상태 확인 - -### 2. 화면 오류 시 -1. 브라우저 콘솔에서 JavaScript 오류 확인 -2. CSS 파일 로딩 상태 확인 -3. JSP 컴파일 오류 확인 - -## 📞 지원 - -테스트 중 문제 발생 시: -1. 브라우저 개발자 도구 스크린샷 -2. 서버 로그 복사 -3. 입력한 테스트 데이터 기록 - -위 정보와 함께 문의하시기 바랍니다. - ---- - -**마지막 업데이트**: 2025-07-14 -**테스트 환경**: Docker 개발환경, PostgreSQL 데이터베이스 -**구현 완료도**: 95% (로그인 세션 테스트 제외) diff --git a/test_contract_registration_final.md b/test_contract_registration_final.md deleted file mode 100644 index 8f853c5..0000000 --- a/test_contract_registration_final.md +++ /dev/null @@ -1,207 +0,0 @@ -# 🎯 영업관리 등록창 최종 테스트 가이드 - -## 📋 현재 구현 상태 - -### ✅ **완료된 작업 (95%)** - -#### 1. **백엔드 수정 완료** - -- **ContractMgmtController.java**: 신규 공통코드 2개 추가 (통화단위, 계약방식) -- **ContractMgmtService.java**: CONTRACT_MGMT 테이블 사용하도록 변경, 25개 신규 필드 처리 -- **contractMgmt.xml**: saveContractMgmtInfo 쿼리에 25개 신규 필드 추가 - -#### 2. **프론트엔드 수정 완료** - -- **contracMgmtFormPopup.jsp**: 5개 섹션으로 완전 재구성 - - 📋 [영업정보]: 계약구분, 과거프로젝트번호, 국내/해외, 고객사, 제품군, 제품코드, 장비명, 설비대수, 요청납기일, 입고지, 셋업지 - - 🔧 [사양상세]: 재질, 압력(BAR), 온도(℃), 용량(LITER), Closure Type, 기타(소모품), 전압, 인증여부 - - 📈 [영업진행]: 진행단계 선택 - - 💰 [견적이력 및 결과]: 통화, 견적금액(1/2/3차), 수주일, 수주가(자동계산), Result, 계약방식, 실패사유, P/O No, PM, 당사프로젝트명 - - 📝 [특이사항]: 텍스트 영역 - -#### 3. **데이터베이스 준비 완료** - -- **공통코드 데이터**: 6개 공통코드의 부모/하위 데이터 완전 작성 -- **테이블 구조**: CONTRACT_MGMT 테이블에 25개 신규 필드 확인 - -### 🚫 **현재 문제점 (5%)** - -#### API 호출 시 세션 인증 문제 - -- **현상**: `{"RESULT":{"result":false,"msg":"저장에 실패하였습니다."}}` -- **원인**: PersonBean 세션 정보 없음으로 인한 NullPointerException -- **해결**: 브라우저에서 로그인 후 테스트 필요 - -## 🧪 **브라우저 테스트 방법** - -### Step 1: 서버 접근 - -``` -URL: http://localhost:8090 -상태: ✅ 정상 실행 중 -``` - -### Step 2: 로그인 - -``` -계정: plm_admin (또는 시스템 관리자에게 문의) -패스워드: 관리자에게 문의 -``` - -### Step 3: 영업관리 화면 접근 - -1. 메뉴에서 **"영업관리"** 클릭 -2. **"계약관리"** 하위 메뉴 클릭 -3. **"신규 등록"** 버튼 클릭 - -### Step 4: 등록창 테스트 - -URL: `http://localhost:8090/contractMgmt/contracMgmtFormPopup.do` - -#### 필수 입력 필드 테스트: - -``` -[영업정보] -- 계약구분: "개발" 선택 -- 장비명: "테스트 장비명" 입력 -- 설비대수: "1" 입력 - -[사양상세] -- 재질: "SUS316L" 입력 -- 압력(BAR): "10.5" 입력 - -[영업진행] -- 진행단계: "사양협의" 선택 - -[특이사항] -- 특이사항: "테스트용 영업관리 데이터입니다." 입력 -``` - -### Step 5: 저장 테스트 - -1. **"저장"** 버튼 클릭 -2. **성공 메시지** 확인: "저장되었습니다." -3. **리스트 화면**에서 저장된 데이터 확인 - -## 🔧 **자동계산 기능 테스트** - -### 수주가 자동계산 테스트: - -1. **견적금액(1차)**: "1000000" 입력 -2. **설비대수**: "2" 입력 -3. **수주가**: 자동으로 "2000000" 계산 확인 - -### 계산 공식: - -```javascript -수주가 = 최신 견적금액 × 설비대수 -``` - -## 📊 **예상 결과** - -### ✅ **성공 시나리오** - -```json -{ - "RESULT": { - "result": true, - "msg": "저장되었습니다." - } -} -``` - -### 🔍 **데이터 확인 방법** - -1. **리스트 화면**: 저장된 데이터가 목록에 표시 -2. **상세 화면**: 저장된 모든 필드값 확인 -3. **데이터베이스**: CONTRACT_MGMT 테이블에 레코드 생성 확인 - -## 🎯 **테스트 체크리스트** - -### 기본 기능 테스트: - -- [ ] 로그인 성공 -- [ ] 등록창 정상 로딩 (5개 섹션 표시) -- [ ] 공통코드 정상 로딩 (계약구분, 진행단계, 통화, 계약방식 등) -- [ ] 필수 필드 입력 -- [ ] 저장 버튼 클릭 -- [ ] 성공 메시지 확인 -- [ ] 리스트에서 데이터 확인 - -### 고급 기능 테스트: - -- [ ] 자동계산 기능 (수주가 = 견적금액 × 설비대수) -- [ ] 캘린더 기능 (요청납기일, 수주일) -- [ ] 파일 첨부 기능 (입수자료, 제출자료) -- [ ] 수정 기능 -- [ ] 삭제 기능 - -## 🚨 **문제 발생 시 대응** - -### 로그인 실패 시: - -``` -1. 계정 정보 확인 -2. 시스템 관리자에게 문의 -3. 데이터베이스 사용자 테이블 확인 -``` - -### 저장 실패 시: - -``` -1. 필수 필드 입력 확인 -2. 브라우저 개발자 도구 > 네트워크 탭에서 오류 확인 -3. 서버 로그 확인 -``` - -### 화면 로딩 실패 시: - -``` -1. 서버 상태 확인: http://localhost:8090 -2. 브라우저 캐시 클리어 -3. 다른 브라우저에서 테스트 -``` - -## 📈 **성능 확인 사항** - -### 응답 시간: - -- **등록창 로딩**: 2초 이내 -- **저장 처리**: 3초 이내 -- **리스트 조회**: 2초 이내 - -### 브라우저 호환성: - -- **Chrome**: ✅ 권장 -- **Firefox**: ✅ 지원 -- **Safari**: ✅ 지원 -- **IE**: ⚠️ 제한적 지원 - -## 🎉 **최종 결과 예상** - -### 성공 시: - -``` -✅ 영업관리 등록창 정상 동작 -✅ 25개 신규 필드 모두 저장 -✅ 자동계산 기능 정상 동작 -✅ 공통코드 정상 연동 -✅ 파일 첨부 기능 정상 동작 -``` - -### 완료도: **95%** - -**남은 5%는 실제 브라우저 테스트를 통한 최종 검증입니다.** - ---- - -## 📞 **지원 연락처** - -문제 발생 시 다음 정보와 함께 문의하세요: - -- 브라우저 종류 및 버전 -- 발생한 오류 메시지 -- 입력한 데이터 -- 스크린샷 (가능한 경우) - -**모든 백엔드 로직, 프론트엔드 화면, 데이터베이스 구조가 완성되어 실제 사용 가능한 상태입니다!** 🎯 From 42bb799b73e4b3d2820722d82808f6557d832a2b Mon Sep 17 00:00:00 2001 From: Johngreen Date: Thu, 30 Oct 2025 14:49:20 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=EC=9D=B4=EB=B4=84=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8>=EC=9D=B4=EB=B4=84=EB=93=B1=EB=A1=9D=20csv=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=EC=8B=9C=20=ED=95=AD=EB=AA=A9?= =?UTF-8?q?=EC=88=98=EB=9F=89=20=EC=BB=AC=EB=9F=BC=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../partMng/openBomReportExcelImportPopUp.jsp | 196 ++++++++---------- .../WEB-INF/view/partMng/structureList.jsp | 15 +- src/com/pms/service/PartMngService.java | 106 ++++------ 3 files changed, 144 insertions(+), 173 deletions(-) diff --git a/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp b/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp index 0428bf8..635e0c9 100644 --- a/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp +++ b/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp @@ -434,17 +434,8 @@ var gridFn = { ,datatype : "json" ,postData:{"targetObjId":"${objid}","docType":"PART_EXCEL_IMPORT","OBJID":"${CONTRACT_OBJID}"} ,loadComplete : function(data) { - // CSV 파일에서만 LEVEL 값을 PARENT_PART_NO 컬럼에 표시 - if(data && data.rows) { - for(var i = 0; i < data.rows.length; i++) { - var row = data.rows[i]; - // CSV 파일이고 LEVEL 값이 있는 경우 - if(row.IS_CSV === 'Y' && row.LEVEL && row.LEVEL !== '') { - // LEVEL 값을 PARENT_PART_NO 컬럼에 표시 (화면용) - grid.jqGrid('setCell', row.id, 'PARENT_PART_NO', row.LEVEL); - } - } - } + // CSV 파일: 모품번을 그대로 표시 (수정 불필요) + // PARENT_PART_NO 컬럼에 이미 모품번이 들어있음 gridFn.footerSummary(); } ,gridComplete : function() { @@ -516,108 +507,103 @@ function fn_checkDuplicatePartNo(){ function fn_save(){ var ids = grid.jqGrid("getDataIDs"); + // 필수 필드 검증 (제품구분, 품번, 품명) + if(!fnc_valitate("form1")){ + return; + } + + // 품번 중복 검증 (PART_BOM_REPORT 테이블 - 헤더 품번) + if(fn_checkDuplicatePartNo()){ + Swal.fire('입력한 품번이 이미 존재합니다. 다른 품번을 입력해주세요.'); + $('#bom_part_no').focus(); + return; + } + + // 그리드에 데이터가 있는 경우에만 검증 수행 if(ids!=""){ - if(fnc_valitate("form1")){ + var valid = true; + var existPart = true; + var part = ""; + if (fnc_isEmpty(${bomInfo.OBJID})) { + var partNo1 = ""; - var valid = true; - var existPart = true; - var part = ""; - if (fnc_isEmpty(${bomInfo.OBJID})) { - var partNo1 = ""; - - gridFn.closeEdit(); - $.each(grid.getRowData(), function(i, d) { - if (i == 0) { - partNo1 = d["PART_NO"]; - } - var partType = d["PART_TYPE"]; - var partNo = d["PART_NO"]; - - if (partType == '0001788') { - if (!fn_existPartNo(partNo)) { - existPart = false; - part = partNo; - return false; // Exit the loop - } - } - - if(!fnc_isEmpty(d["NOTE"])){ - valid = false; - } - }); - gridFn.opennEdit(); - - var project_no = $("#project_name").find("option:selected").text(); - if (partNo1.indexOf(project_no) < 0) { - valid = false; - } - } - - if (!existPart) { - Swal.fire(part+'품번에 해당하는 구매품표준이 없습니다. 확인해 주세요.'); - return; - } - - if (!valid) { - Swal.fire('1레벨 품번에 프로젝트번호가 없습니다. 확인해 주세요.'); - return; - } - - // 품번 중복 검증 (PART_BOM_REPORT 테이블 - 헤더 품번) - if(fn_checkDuplicatePartNo()){ - Swal.fire('입력한 품번이 이미 존재합니다. 다른 품번을 입력해주세요.'); - $('#bom_part_no').focus(); - return; - } - - var existsDup = false; - var ARR_APPLICATION_PROJECT_NO = new Array(); - $(".APPLICATION_PROJECT_NO").each(function(){ - for(var i=0; i { + // 검색 플래그 초기화 후 목록 새로고침 + isSearching = false; + fn_search(); + }); }, error: function(jqxhr, status, error){ + Swal.fire('삭제 중 오류가 발생했습니다.'); + // 에러 시에도 플래그 초기화 + isSearching = false; } }); } diff --git a/src/com/pms/service/PartMngService.java b/src/com/pms/service/PartMngService.java index d495923..86fbf9b 100644 --- a/src/com/pms/service/PartMngService.java +++ b/src/com/pms/service/PartMngService.java @@ -3232,48 +3232,25 @@ public class PartMngService extends BaseService { AtomicInteger emptyColCnt = new AtomicInteger(0); String noteMsg = ""; - int colIndex = 0; - - // 각 컬럼 파싱 (CSV: 수준, 품번, 품명, 수량, ...) - String level = getCsvValue(values, colIndex++, emptyColCnt); // 0: 수준 - String partNo = getCsvValue(values, colIndex++, emptyColCnt); // 1: 품번 - String partName = getCsvValue(values, colIndex++, emptyColCnt); // 2: 품명 - String qty = getCsvValue(values, colIndex++, emptyColCnt); // 3: 수량 - String itemQty = getCsvValue(values, colIndex++, emptyColCnt); // 4: 항목수량 - String material = getCsvValue(values, colIndex++, emptyColCnt); // 5: 재료 - String heatTreatmentHardness = getCsvValue(values, colIndex++, emptyColCnt); // 6: 열처리경도 - String heatTreatmentMethod = getCsvValue(values, colIndex++, emptyColCnt); // 7: 열처리방법 - String surfaceTreatment = getCsvValue(values, colIndex++, emptyColCnt); // 8: 표면처리 - String supplier = getCsvValue(values, colIndex++, emptyColCnt); // 9: 공급업체 - String partType = getCsvValue(values, colIndex++, emptyColCnt); // 10: 범주이름 - - // 수준으로부터 부모 품번 찾기 - String parentPartNo = ""; - if (!StringUtils.isBlank(level)) { - // 숫자만 있는 경우 (1, 2, 3, 4 등) - try { - int currentDepth = Integer.parseInt(level); - - // 현재 깊이의 품번 저장 (다음 행에서 참조할 수 있도록) - if (!StringUtils.isBlank(partNo)) { - currentDepthPartNoMap.put(currentDepth, partNo); - } - - // 부모 찾기: 바로 이전 깊이의 최신 품번 - if (currentDepth > 1) { - int parentDepth = currentDepth - 1; - if (currentDepthPartNoMap.containsKey(parentDepth)) { - parentPartNo = currentDepthPartNoMap.get(parentDepth); - } - } - } catch (NumberFormatException e) { - // 숫자가 아닌 경우 (1.1, 1.4.1 등) - 기존 로직 사용 - String parentLevel = getParentLevel(level); - if (!StringUtils.isBlank(parentLevel) && levelToPartNoMap.containsKey(parentLevel)) { - parentPartNo = levelToPartNoMap.get(parentLevel); - } - } - } + int colIndex = 0; + + // 각 컬럼 파싱 (CSV: 상태, 모품번, 품번, 품명, 수량, 항목수량, ...) + String level = getCsvValue(values, colIndex++, emptyColCnt); // 0: 상태(수준) + String parentPartNo = getCsvValue(values, colIndex++, emptyColCnt); // 1: 모품번 + String partNo = getCsvValue(values, colIndex++, emptyColCnt); // 2: 품번 + String partName = getCsvValue(values, colIndex++, emptyColCnt); // 3: 품명 + String qty = getCsvValue(values, colIndex++, emptyColCnt); // 4: 수량 + String itemQty = getCsvValue(values, colIndex++, emptyColCnt); // 5: 항목수량 + String material = getCsvValue(values, colIndex++, emptyColCnt); // 6: 재료 + String heatTreatmentHardness = getCsvValue(values, colIndex++, emptyColCnt); // 7: 열처리경도 + String heatTreatmentMethod = getCsvValue(values, colIndex++, emptyColCnt); // 8: 열처리방법 + String surfaceTreatment = getCsvValue(values, colIndex++, emptyColCnt); // 9: 표면처리 + String supplier = getCsvValue(values, colIndex++, emptyColCnt); // 10: 공급업체 + String partType = getCsvValue(values, colIndex++, emptyColCnt); // 11: 범주이름 + + // CSV에서 모품번을 직접 제공하므로 별도 처리 불필요 + // level은 상태(수준) 값으로 사용됨 + // parentPartNo는 이미 1번 컬럼에서 읽음 // 유효성 검증 if(!StringUtils.isBlank(parentPartNo) && rowIndex > 2) { @@ -4446,28 +4423,29 @@ public class PartMngService extends BaseService { insertMap.put("OBJID", CommonUtils.createObjId()); insertMap.put("BOM_REPORT_OBJID", objid); insertMap.put("PARENT_PART_NO", PARENT_PART_NO); - insertMap.put("PART_NO", PART_NO); - insertMap.put("PART_NAME", CommonUtils.checkNull((String)insertMap.get("PART_NAME"))); - insertMap.put("QTY", CommonUtils.checkNull((String)insertMap.get("QTY"))); - insertMap.put("UNIT", CommonUtils.checkNull((String)insertMap.get("UNIT"))); - insertMap.put("SPEC", CommonUtils.checkNull((String)insertMap.get("SPEC"))); - insertMap.put("MATERIAL", CommonUtils.checkNull((String)insertMap.get("MATERIAL"))); - insertMap.put("THICKNESS", CommonUtils.checkNull((String)insertMap.get("THICKNESS"))); - insertMap.put("WIDTH", CommonUtils.checkNull((String)insertMap.get("WIDTH"))); - insertMap.put("HEIGHT", CommonUtils.checkNull((String)insertMap.get("HEIGHT"))); - insertMap.put("OUT_DIAMETER", CommonUtils.checkNull((String)insertMap.get("OUT_DIAMETER"))); - insertMap.put("IN_DIAMETER", CommonUtils.checkNull((String)insertMap.get("IN_DIAMETER"))); - insertMap.put("LENGTH", CommonUtils.checkNull((String)insertMap.get("LENGTH"))); - insertMap.put("PART_TYPE", CommonUtils.checkNull((String)insertMap.get("PART_TYPE"))); - insertMap.put("REMARK", CommonUtils.checkNull((String)insertMap.get("REMARK"))); - insertMap.put("SUPPLY_CODE", CommonUtils.checkNull((String)insertMap.get("SUPPLY_CODE"))); - insertMap.put("MAKER", CommonUtils.checkNull((String)insertMap.get("MAKER"))); - insertMap.put("POST_PROCESSING", CommonUtils.checkNull((String)insertMap.get("POST_PROCESSING"))); - insertMap.put("HEAT_TREATMENT_HARDNESS", CommonUtils.checkNull((String)insertMap.get("HEAT_TREATMENT_HARDNESS"))); - insertMap.put("HEAT_TREATMENT_METHOD", CommonUtils.checkNull((String)insertMap.get("HEAT_TREATMENT_METHOD"))); - insertMap.put("SURFACE_TREATMENT", CommonUtils.checkNull((String)insertMap.get("SURFACE_TREATMENT"))); - insertMap.put("STATUS", "deploy"); // 엑셀 업로드 시 deploy 상태로 저장 - insertMap.put("WRITER", CommonUtils.checkNull((String)paramMap.get("CONNECTUSERID"))); + insertMap.put("PART_NO", PART_NO); + insertMap.put("PART_NAME", CommonUtils.checkNull((String)insertMap.get("PART_NAME"))); + insertMap.put("QTY", CommonUtils.checkNull((String)insertMap.get("QTY"))); + insertMap.put("ITEM_QTY", CommonUtils.checkNull((String)insertMap.get("ITEM_QTY"))); // 항목수량 추가 + insertMap.put("UNIT", CommonUtils.checkNull((String)insertMap.get("UNIT"))); + insertMap.put("SPEC", CommonUtils.checkNull((String)insertMap.get("SPEC"))); + insertMap.put("MATERIAL", CommonUtils.checkNull((String)insertMap.get("MATERIAL"))); + insertMap.put("THICKNESS", CommonUtils.checkNull((String)insertMap.get("THICKNESS"))); + insertMap.put("WIDTH", CommonUtils.checkNull((String)insertMap.get("WIDTH"))); + insertMap.put("HEIGHT", CommonUtils.checkNull((String)insertMap.get("HEIGHT"))); + insertMap.put("OUT_DIAMETER", CommonUtils.checkNull((String)insertMap.get("OUT_DIAMETER"))); + insertMap.put("IN_DIAMETER", CommonUtils.checkNull((String)insertMap.get("IN_DIAMETER"))); + insertMap.put("LENGTH", CommonUtils.checkNull((String)insertMap.get("LENGTH"))); + insertMap.put("PART_TYPE", CommonUtils.checkNull((String)insertMap.get("PART_TYPE"))); + insertMap.put("REMARK", CommonUtils.checkNull((String)insertMap.get("REMARK"))); + insertMap.put("SUPPLY_CODE", CommonUtils.checkNull((String)insertMap.get("SUPPLY_CODE"))); + insertMap.put("MAKER", CommonUtils.checkNull((String)insertMap.get("MAKER"))); + insertMap.put("POST_PROCESSING", CommonUtils.checkNull((String)insertMap.get("POST_PROCESSING"))); + insertMap.put("HEAT_TREATMENT_HARDNESS", CommonUtils.checkNull((String)insertMap.get("HEAT_TREATMENT_HARDNESS"))); + insertMap.put("HEAT_TREATMENT_METHOD", CommonUtils.checkNull((String)insertMap.get("HEAT_TREATMENT_METHOD"))); + insertMap.put("SURFACE_TREATMENT", CommonUtils.checkNull((String)insertMap.get("SURFACE_TREATMENT"))); + insertMap.put("STATUS", "deploy"); // 엑셀 업로드 시 deploy 상태로 저장 + insertMap.put("WRITER", CommonUtils.checkNull((String)paramMap.get("CONNECTUSERID"))); insertMap.put("CONTRACT_OBJID", CommonUtils.checkNull((String)paramMap.get("CONTRACT_OBJID"))); insertMap.put("PRODUCT_MGMT_OBJID", CommonUtils.checkNull((String)paramMap.get("product_mgmt_objid")));