From 0d5d0e36c244175bbc11ba499a7697d22b77a813 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Fri, 21 Nov 2025 13:44:21 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WEB-INF/view/partMng/partMngTempList.jsp | 23 +----------------- .../WEB-INF/view/partMng/structureList.jsp | 24 +------------------ 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/WebContent/WEB-INF/view/partMng/partMngTempList.jsp b/WebContent/WEB-INF/view/partMng/partMngTempList.jsp index 649f637..e5d7e28 100644 --- a/WebContent/WEB-INF/view/partMng/partMngTempList.jsp +++ b/WebContent/WEB-INF/view/partMng/partMngTempList.jsp @@ -196,29 +196,8 @@ ui-jqgrid tr.jqgrow td { {headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '비고', field : 'REMARK' } ]; - // 중복 요청 방지 플래그 - var isSearching = false; - function fn_search(){ - // 이미 검색 중이면 중단 - if (isSearching) { - console.log('검색 중입니다. 잠시만 기다려주세요.'); - return; - } - - isSearching = true; - - _tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/partMng/partMngTempGridList.do", columns, true, function() { - // 검색 완료 후 플래그 해제 - isSearching = false; - }); - - // 타임아웃 방어 (10초 후 자동 해제) - setTimeout(function() { - if (isSearching) { - isSearching = false; - } - }, 10000); + _tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/partMng/partMngTempGridList.do", columns, true); } function openPartMngPopup(objId){ diff --git a/WebContent/WEB-INF/view/partMng/structureList.jsp b/WebContent/WEB-INF/view/partMng/structureList.jsp index cf8148c..6944cb5 100644 --- a/WebContent/WEB-INF/view/partMng/structureList.jsp +++ b/WebContent/WEB-INF/view/partMng/structureList.jsp @@ -234,31 +234,9 @@ var columns = [ {headerHozAlign : 'center', hozAlign : 'center', width : '110', title : '상태', field : 'STATUS' } ]; -// 중복 요청 방지를 위한 로딩 플래그 -var isSearching = false; - //var grid; function fn_search(){ - // 이미 검색 중이면 중복 요청 방지 - if (isSearching) { - console.log('검색 중입니다. 잠시만 기다려주세요.'); - return; - } - - isSearching = true; - - // 기존 그리드 검색 함수 실행 - _tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/partMng/searchStructureGridList.do", columns, true, function() { - // 검색 완료 후 플래그 해제 - isSearching = false; - }); - - // fnc_tabul_search가 콜백을 지원하지 않을 경우를 위한 타임아웃 처리 - setTimeout(function() { - if (isSearching) { - isSearching = false; - } - }, 10000); // 10초 타임아웃 + _tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/partMng/searchStructureGridList.do", columns, true); } //양산제품에 해당하는 SPEC 정보 목록을 가져온다. From 22406be147dd4ee3504886d75801ad2f2658d7d6 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Fri, 21 Nov 2025 14:37:55 +0900 Subject: [PATCH 2/4] =?UTF-8?q?e-bom=20csv=20=EC=97=85=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=20=EB=AC=B8=EC=A0=9C=20=EB=B0=9C=EC=83=9D=EC=8B=9C=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=EB=B2=84=ED=8A=BC=20=EC=88=A8=EA=B8=B0=EA=B8=B0,=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../partMng/openBomReportExcelImportPopUp.jsp | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp b/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp index 9324fdb..9b0d290 100644 --- a/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp +++ b/WebContent/WEB-INF/view/partMng/openBomReportExcelImportPopUp.jsp @@ -250,7 +250,7 @@ $(document).ready(function(){ ,datatype: "local" ,colNames: ["상태","모품번","품번","품명","수량","항목수량","재료","열처리경도","열처리방법","표면처리","공급업체","범주이름"] ,colModel: [ - {name:"NOTE",index:"NOTE", width: 160, align:"center", hidden: false, sortable:false, editable:true + {name:"NOTE",index:"NOTE", width: 200, align:"center", hidden: false, sortable:false, editable:true ,editoptions:{ dataInit : function(e){ e.style.fontSize = 13; @@ -947,17 +947,15 @@ function fn_save(){ -
- +
+
- - - - - - - - + + + + + + @@ -969,27 +967,29 @@ function fn_save(){ - - - - + + + + + - @@ -1032,7 +1032,27 @@ function fn_save(){ -->
- + - - - +
- + +
+ - + +
-
+ + +
+
+
   CSV upload
+
+
+
Drag & Drop CSV 템플릿
+
+ + + + + + +
Excel 첨부파일
+
+
+
+
+
-
-
-
Drag & Drop CSV 템플릿
-
- - - - - - -
Excel 첨부파일
-
-
-
- - -
- +
From 4f17449a2672213ec42583196c84a784ae417258 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Fri, 21 Nov 2025 14:46:57 +0900 Subject: [PATCH 3/4] =?UTF-8?q?e-bom=20=EA=B5=AC=EC=A1=B0=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=BC=EB=B3=84=20=EC=A0=95=EB=A0=AC=20=EC=A0=9C=EA=B1=B0!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../view/partMng/structurePopupLeft.jsp | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp b/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp index 3d50a16..9c69cef 100644 --- a/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp +++ b/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp @@ -80,6 +80,7 @@ function fn_initGrid() { width: 60, title: '선택', field: 'RADIO', + headerSort: false, formatter: function(cell) { var rowData = cell.getData(); return ' Date: Fri, 21 Nov 2025 16:56:52 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=97=86=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EC=A3=BC=EB=93=B1=EB=A1=9D=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estimateAndOrderRegistFormPopup.jsp | 1469 +++++++++++++++++ .../view/contractMgmt/estimateList_new.jsp | 1 + .../view/contractMgmt/orderMgmtList.jsp | 30 +- .../controller/ContractMgmtController.java | 92 +- src/com/pms/salesmgmt/mapper/contractMgmt.xml | 145 +- .../service/ContractMgmtService.java | 274 +++ 6 files changed, 2002 insertions(+), 9 deletions(-) create mode 100644 WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp new file mode 100644 index 0000000..c4db9ca --- /dev/null +++ b/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp @@ -0,0 +1,1469 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ page import="java.util.*"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@include file="/init_new.jsp"%> +<% + PersonBean person = (PersonBean) session.getAttribute(Constants.PERSON_BEAN); + String userId = CommonUtils.checkNull(person.getUserId()); +%> + + + + +<%=Constants.SYSTEM_NAME%> + + + + +
+ + + + + + +
+
+

+ 영업관리_주문서관리_수주통합등록 +

+
+ +
+
+ 수주통합 기본정보 +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + +
+
+ + +
+ 품목정보 + +
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
No품번 *품명 *S/N요청납기고객요청사항반납사유수주수량 *수주단가 *수주공급가액수주부가세수주총액삭제
+ 품목 추가 버튼을 클릭하여 품목을 등록하세요. +
+
+
+
+ +
+
+ + +
+
+ +
+
+ + + diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp index 08b0d86..a43c060 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp @@ -875,6 +875,7 @@ function openProjectFormPopUp(objId){
+ diff --git a/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp b/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp index d0c7249..570d8c2 100644 --- a/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp @@ -54,18 +54,34 @@ $(document).ready(function(){ $(".btnRegist").click(function(){ var selectedData = _tabulGrid.getSelectedData(); if(selectedData.length < 1){ - Swal.fire("수주등록할 영업정보를 선택해주십시오."); - return false; + // 선택이 없으면 견적요청+수주 통합 등록 팝업 오픈 + var popup_width = 1600; + var popup_height = 800; + var params = "?actionType=regist"; + var url = "/contractMgmt/estimateAndOrderRegistFormPopup.do"+params; + fn_centerPopup(popup_width, popup_height, url); } else if(selectedData.length > 1){ Swal.fire("한번에 한개의 수주만 등록 가능합니다."); return false; } else { var contractObjId = fnc_checkNull(selectedData[0].OBJID); - var popup_width = 1400; - var popup_height = 450; - var params = "?actionType=regist&contractObjId="+contractObjId; - var url = "/contractMgmt/orderRegistFormPopup.do"+params; - fn_centerPopup(popup_width, popup_height, url); + var isDirectOrder = fnc_checkNull(selectedData[0].IS_DIRECT_ORDER); + + // 통합 등록 건이면 통합 팝업 오픈 (수정 모드) + if(isDirectOrder === 'Y') { + var popup_width = 1600; + var popup_height = 800; + var params = "?actionType=update&objId="+contractObjId; + var url = "/contractMgmt/estimateAndOrderRegistFormPopup.do"+params; + fn_centerPopup(popup_width, popup_height, url); + } else { + // 일반 견적요청 건이면 기존 수주등록 팝업 오픈 + var popup_width = 1400; + var popup_height = 450; + var params = "?actionType=regist&contractObjId="+contractObjId; + var url = "/contractMgmt/orderRegistFormPopup.do"+params; + fn_centerPopup(popup_width, popup_height, url); + } } }); diff --git a/src/com/pms/salesmgmt/controller/ContractMgmtController.java b/src/com/pms/salesmgmt/controller/ContractMgmtController.java index c6c2a5c..6565dab 100644 --- a/src/com/pms/salesmgmt/controller/ContractMgmtController.java +++ b/src/com/pms/salesmgmt/controller/ContractMgmtController.java @@ -261,7 +261,7 @@ public class ContractMgmtController { } /** - * 계약관리 - 계약관리 목록 페이징 + * 계약관리 - 계약관리 목록 페이징 (주문서관리) * @param request * @param paramMap * @return @@ -270,6 +270,8 @@ public class ContractMgmtController { @RequestMapping("/contractMgmt/contractGridList.do") public Map getProductKindSpecListPaging(HttpServletRequest request, @RequestParam Map paramMap){ try { + // 주문서관리에서는 모든 건 표시 (list_type을 전달하지 않음) + // 페이징 데이터 조회 commonService.selectListPagingNew("contractMgmt.contractGridList", request, paramMap); @@ -1674,6 +1676,8 @@ public class ContractMgmtController { @ResponseBody @RequestMapping("/contractMgmt/estimateGridList.do") public Map getestimateListPaging(HttpServletRequest request, @RequestParam Map paramMap){ + // 견적관리에서는 통합 등록 건 제외 + paramMap.put("list_type", "estimate"); commonService.selectListPagingNew("contractMgmt.estimateGridList", request, paramMap); return paramMap; } @@ -2445,6 +2449,75 @@ public class ContractMgmtController { return resultMap; } + /** + * 견적요청 및 수주 통합 등록 팝업 페이지 + * @param session + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/contractMgmt/estimateAndOrderRegistFormPopup.do") + public String estimateAndOrderRegistFormPopup(HttpSession session, HttpServletRequest request, @RequestParam Map paramMap) { + String actionType = CommonUtils.checkNull(paramMap.get("actionType")); + String objId = CommonUtils.checkNull(paramMap.get("objId")); + Map code_map = new HashMap(); + Map info = new HashMap(); + List itemList = new ArrayList(); + + try { + // 수정 모드인 경우 기존 데이터 조회 + if("update".equals(actionType) && StringUtils.isNotBlank(objId)) { + paramMap.put("objId", objId); + paramMap.put("contractObjId", objId); // getContractItems에서 사용 + paramMap.put("actionType", actionType); // 통합 팝업 수정 모드 표시 + info = CommonUtils.keyChangeUpperMap(contractMgmtService.getContractMgmtInfo(paramMap)); + + // 품목 정보 조회 + itemList = contractMgmtService.getContractItems(paramMap); + } + + // Machine 여부 및 프로젝트 존재 여부 확인 + String productCd = CommonUtils.nullToEmpty((String)info.get("PRODUCT")); + boolean isMachine = "0000928".equals(productCd); + Map projectInfo = contractMgmtService.checkProjectExists(paramMap); + boolean hasProject = (projectInfo != null); + + // 주문유형 코드 + code_map.put("category_cd", commonService.bizMakeOptionList("0000167", CommonUtils.nullToEmpty((String)info.get("CATEGORY_CD")), "common.getCodeselect")); + + // 제품구분 코드 + code_map.put("product_cd", commonService.bizMakeOptionList("0000001", CommonUtils.nullToEmpty((String)info.get("PRODUCT")), "common.getCodeselect")); + + // 국내/해외 코드 + code_map.put("area_cd", commonService.bizMakeOptionList("0001219", CommonUtils.nullToEmpty((String)info.get("AREA_CD")), "common.getCodeselect")); + + // 고객사 코드 + code_map.put("customer_cd", commonService.bizMakeOptionList("", CommonUtils.nullToEmpty((String)info.get("CUSTOMER_OBJID")), "common.getsupplyselect")); + + // 수주상태 코드 + code_map.put("contract_result", commonService.bizMakeOptionList("0000963", CommonUtils.nullToEmpty((String)info.get("CONTRACT_RESULT")), "common.getCodeselect")); + + // 환종 코드 + code_map.put("contract_currency", commonService.bizMakeOptionList("0001533", CommonUtils.nullToEmpty((String)info.get("CONTRACT_CURRENCY")), "common.getCodeselect")); + + // 반납사유 코드 + code_map.put("return_reason_cd", commonService.bizMakeOptionList("0002268", "", "common.getCodeselect")); + + request.setAttribute("code_map",code_map); + request.setAttribute("info", info); + request.setAttribute("itemList", itemList); + request.setAttribute("actionType", actionType); + request.setAttribute("objId", objId); + request.setAttribute("isMachine", isMachine ? "Y" : "N"); + request.setAttribute("hasProject", hasProject ? "Y" : "N"); + + } catch(Exception e) { + e.printStackTrace(); + } + + return "/contractMgmt/estimateAndOrderRegistFormPopup"; + } + /** * 수주등록 팝업 페이지 * @param session @@ -2504,6 +2577,23 @@ public class ContractMgmtController { return "/contractMgmt/orderRegistFormPopup"; } + /** + * 견적요청 및 수주 통합 저장 + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/contractMgmt/saveEstimateAndOrderInfo.do") + public String saveEstimateAndOrderInfo(HttpServletRequest request, @RequestParam Map paramMap){ + try { + request.setAttribute("RESULT", CommonUtils.getJsonMap(contractMgmtService.saveEstimateAndOrderInfo(request, paramMap)) ); + + } catch (Exception e) { + e.printStackTrace(); + } + return "/ajax/ajaxResult"; + } + /** * 수주정보 저장 * @param session diff --git a/src/com/pms/salesmgmt/mapper/contractMgmt.xml b/src/com/pms/salesmgmt/mapper/contractMgmt.xml index f3b8400..ed60341 100644 --- a/src/com/pms/salesmgmt/mapper/contractMgmt.xml +++ b/src/com/pms/salesmgmt/mapper/contractMgmt.xml @@ -502,6 +502,7 @@ ,EXCHANGE_RATE ,EST_PRICE ,EST_SUPPLY_PRICE + ,IS_DIRECT_ORDER ,(SELECT COUNT(1) FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID) AS EST_STATUS ,( SELECT IS_SEND @@ -794,6 +795,12 @@ AND TO_DATE(DUE_DATE,'YYYY-MM-DD') TO_DATE(#{due_end_date}, 'YYYY-MM-DD') + + + + AND COALESCE(IS_DIRECT_ORDER, 'N') != 'Y' + + ORDER BY REGDATE DESC @@ -4758,6 +4765,88 @@ WHERE WHERE OBJID = #{objId} + + + UPDATE CONTRACT_MGMT + SET + ORDER_SUPPLY_PRICE = #{order_supply_price}, + ORDER_VAT = #{order_vat}, + ORDER_TOTAL_AMOUNT = #{order_total_amount} + WHERE OBJID = #{objId} + + + + + INSERT INTO CONTRACT_MGMT + ( + OBJID, + CATEGORY_CD, + CUSTOMER_OBJID, + PRODUCT, + AREA_CD, + CUSTOMER_EQUIP_NAME, + CUSTOMER_PROJECT_NAME, + CUSTOMER_PRODUCTION_NO, + MECHANICAL_TYPE, + PAID_TYPE, + RECEIPT_DATE, + REQ_DEL_DATE, + CONTRACT_RESULT, + PO_NO, + ORDER_DATE, + CONTRACT_CURRENCY, + EXCHANGE_RATE, + REGDATE, + WRITER, + CONTRACT_NO, + IS_DIRECT_ORDER + ) + VALUES + ( + #{objId}, + #{category_cd}, + #{customer_objid}, + #{product}, + #{area_cd}, + #{customer_equip_name}, + #{customer_project_name}, + #{customer_production_no}, + #{mechanical_type}, + #{paid_type}, + #{receipt_date}, + #{req_del_date}, + #{contract_result}, + #{po_no}, + #{order_date}, + #{contract_currency}, + #{exchange_rate}, + NOW(), + #{writer}, + (SELECT TO_CHAR(NOW(),'yy')::VARCHAR ||'C-'||LPAD((SELECT NEXTVAL('contract_mgmt_seq'))::VARCHAR ,4,'0')), + #{is_direct_order} + ) + ON CONFLICT (OBJID) DO + UPDATE + SET + CATEGORY_CD = #{category_cd}, + CUSTOMER_OBJID = #{customer_objid}, + PRODUCT = #{product}, + AREA_CD = #{area_cd}, + CUSTOMER_EQUIP_NAME = #{customer_equip_name}, + CUSTOMER_PROJECT_NAME = #{customer_project_name}, + CUSTOMER_PRODUCTION_NO = #{customer_production_no}, + MECHANICAL_TYPE = #{mechanical_type}, + PAID_TYPE = #{paid_type}, + RECEIPT_DATE = #{receipt_date}, + REQ_DEL_DATE = #{req_del_date}, + CONTRACT_RESULT = #{contract_result}, + PO_NO = #{po_no}, + ORDER_DATE = #{order_date}, + CONTRACT_CURRENCY = #{contract_currency}, + EXCHANGE_RATE = #{exchange_rate}, + IS_DIRECT_ORDER = #{is_direct_order} + + diff --git a/src/com/pms/salesmgmt/service/ContractMgmtService.java b/src/com/pms/salesmgmt/service/ContractMgmtService.java index d86195b..3cf1d8a 100644 --- a/src/com/pms/salesmgmt/service/ContractMgmtService.java +++ b/src/com/pms/salesmgmt/service/ContractMgmtService.java @@ -2574,6 +2574,279 @@ private String encodeImageToBase64(String imagePath) { return items; } + /** + * 견적요청 및 수주 통합 저장 + * 견적요청 정보와 수주 정보를 한번에 저장 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Map saveEstimateAndOrderInfo(HttpServletRequest request, Map paramMap){ + Map resultMap = new HashMap(); + SqlSession sqlSession = null; + try{ + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + PersonBean person = (PersonBean)request.getSession().getAttribute(Constants.PERSON_BEAN); + paramMap.put("writer", person.getUserId()); + + // 통합 등록 플래그 설정 (견적관리에서 숨김, 주문서관리에만 표시) + String objId = CommonUtils.checkNull(paramMap.get("objId")); + String actionType = CommonUtils.checkNull(paramMap.get("actionType")); + + // 신규 등록인 경우 OBJID 생성 및 is_direct_order를 'Y'로 설정 + if("regist".equals(actionType) || "".equals(objId)) { + objId = CommonUtils.createObjId(); + paramMap.put("objId", objId); + paramMap.put("is_direct_order", "Y"); + } else { + // 수정인 경우 기존 objId 유지 및 is_direct_order 값 유지 + paramMap.put("objId", objId); + Map existingInfo = (Map) sqlSession.selectOne("contractMgmt.getContractMgmtInfo", paramMap); + if(existingInfo != null) { + paramMap.put("is_direct_order", CommonUtils.checkNull(existingInfo.get("IS_DIRECT_ORDER"), "Y")); + } else { + paramMap.put("is_direct_order", "Y"); + } + } + + // 1. 견적요청 및 수주 기본 정보 저장 (통합 팝업용 쿼리 사용) + int cnt = sqlSession.update("contractMgmt.saveEstimateAndOrderInfo", paramMap); + + // 생성된 CONTRACT_OBJID 가져오기 + String contract_objid = objId; + + // 2. 품목 정보 저장 (CONTRACT_ITEM 테이블) + String itemsJson = CommonUtils.checkNull(paramMap.get("items_json")); + long totalSupplyPrice = 0; + long totalVat = 0; + long totalAmount = 0; + + if(!"".equals(itemsJson)){ + try { + JSONParser parser = new JSONParser(); + JSONArray jsonArray = (JSONArray) parser.parse(itemsJson); + + // 기존 품목 삭제 (전체 삭제 후 재등록 방식) + Map deleteParam = new HashMap(); + deleteParam.put("contractObjId", contract_objid); + deleteParam.put("userId", person.getUserId()); + sqlSession.update("contractMgmt.deleteContractItems", deleteParam); + + for(int i = 0; i < jsonArray.size(); i++) { + JSONObject item = (JSONObject) jsonArray.get(i); + Map itemMap = new HashMap(); + + // 품목 기본 정보 + String itemObjId = item.get("objId") != null ? item.get("objId").toString() : ""; + if("".equals(itemObjId) || itemObjId.startsWith("temp_")) { + itemObjId = CommonUtils.createObjId(); + } + + itemMap.put("objId", itemObjId); + itemMap.put("contractObjId", contract_objid); + itemMap.put("seq", i + 1); // SEQ는 1부터 시작 + itemMap.put("partObjId", item.get("partObjId") != null ? item.get("partObjId").toString() : ""); + itemMap.put("partNo", item.get("partNo") != null ? item.get("partNo").toString() : ""); + itemMap.put("partName", item.get("partName") != null ? item.get("partName").toString() : ""); + itemMap.put("dueDate", item.get("dueDate") != null ? item.get("dueDate").toString() : ""); + itemMap.put("customerRequest", item.get("customerRequest") != null ? item.get("customerRequest").toString() : ""); + itemMap.put("returnReason", item.get("returnReason") != null ? item.get("returnReason").toString() : ""); + + // 수주 정보 + String orderQuantity = item.get("orderQuantity") != null ? item.get("orderQuantity").toString().replace(",", "") : "0"; + String orderUnitPrice = item.get("orderUnitPrice") != null ? item.get("orderUnitPrice").toString().replace(",", "") : "0"; + String orderSupplyPrice = item.get("orderSupplyPrice") != null ? item.get("orderSupplyPrice").toString().replace(",", "") : "0"; + String orderVat = item.get("orderVat") != null ? item.get("orderVat").toString().replace(",", "") : "0"; + String orderTotalAmount = item.get("orderTotalAmount") != null ? item.get("orderTotalAmount").toString().replace(",", "") : "0"; + + // 통합 등록에서는 견적수량을 입력받지 않으므로 수주수량을 quantity에도 저장 + itemMap.put("quantity", orderQuantity); + itemMap.put("orderQuantity", orderQuantity); + itemMap.put("orderUnitPrice", orderUnitPrice); + itemMap.put("orderSupplyPrice", orderSupplyPrice); + itemMap.put("orderVat", orderVat); + itemMap.put("orderTotalAmount", orderTotalAmount); + itemMap.put("writer", person.getUserId()); + + // 품목 저장 (통합 등록용 - 수주 정보 포함) + sqlSession.insert("contractMgmt.insertContractItemWithOrder", itemMap); + + // S/N 저장 (별도 테이블) + JSONArray snArray = (JSONArray) item.get("snList"); + if(snArray != null && snArray.size() > 0) { + for(int j = 0; j < snArray.size(); j++) { + JSONObject sn = (JSONObject) snArray.get(j); + Map snMap = new HashMap(); + snMap.put("objId", CommonUtils.createObjId()); + snMap.put("itemObjId", itemObjId); + snMap.put("seq", j + 1); + snMap.put("serialNo", sn.get("value").toString()); + snMap.put("writer", person.getUserId()); + sqlSession.insert("contractMgmt.insertContractItemSerial", snMap); + } + } + + // 합계 계산 + try { + totalSupplyPrice += Long.parseLong(orderSupplyPrice); + totalVat += Long.parseLong(orderVat); + totalAmount += Long.parseLong(orderTotalAmount); + } catch (NumberFormatException e) { + // 숫자 변환 실패 시 무시 + } + } + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("품목 정보 저장 중 오류가 발생했습니다."); + } + } + + // 3. 수주 합계 업데이트 + paramMap.put("order_supply_price", String.valueOf(totalSupplyPrice)); + paramMap.put("order_vat", String.valueOf(totalVat)); + paramMap.put("order_total_amount", String.valueOf(totalAmount)); + + // 합계만 별도 업데이트 (기본 정보는 이미 saveEstimateAndOrderInfo에서 저장됨) + sqlSession.update("contractMgmt.updateOrderTotalAmounts", paramMap); + + // 4. 프로젝트 생성 로직 (수주 또는 수주(FCST)인 경우) + String result_cd = CommonUtils.checkNull(paramMap.get("contract_result")); + String category_cd = CommonUtils.checkNull(paramMap.get("category_cd")); + String target_project_no = CommonUtils.checkNull(paramMap.get("target_project_no_direct")); + + // 수주(0000964) 또는 수주(FCST)(0000968)인 경우 프로젝트 생성 + if("0000964".equals(result_cd) || "0000968".equals(result_cd)){ + // CONTRACT_OBJID로 프로젝트 존재 여부 확인 + Map resultList = sqlSession.selectOne("contractMgmt.getProjectListBycontractObjid", paramMap); + boolean hasProject = (resultList != null); + + // 제품구분 확인 (DB에서 조회) + Map contractInfo = (Map) sqlSession.selectOne("contractMgmt.getContractBasicInfo", paramMap); + contractInfo = CommonUtils.toUpperCaseMapKey(contractInfo); + + String product_cd = contractInfo != null ? CommonUtils.checkNull(contractInfo.get("PRODUCT")) : ""; + boolean isMachine = "0000928".equals(product_cd); + + if(isMachine) { + System.out.println("제품구분: Machine(0000928) - 품목별 수량만큼 프로젝트 생성"); + } + + // 품목별로 프로젝트 생성 또는 업데이트 + paramMap.put("contractObjId", contract_objid); + List contractItems = getContractItems(paramMap); + + if(contractItems != null && !contractItems.isEmpty()) { + System.out.println("품목 개수: " + contractItems.size() + "개 - 프로젝트 " + (hasProject ? "업데이트" : "생성") + " 시작" + (isMachine ? " (Machine - 수량별 생성)" : "")); + + for(Map item : contractItems) { + // 수량 가져오기 + Object quantityObj = item.get("ORDER_QUANTITY") != null ? item.get("ORDER_QUANTITY") : item.get("QUANTITY"); + int itemQuantity = 1; + try { + itemQuantity = Integer.parseInt(String.valueOf(quantityObj)); + } catch (Exception e) { + itemQuantity = 1; + } + + // Machine인 경우 수량만큼 반복, 아니면 1번만 실행 + int loopCount = (isMachine && !hasProject) ? itemQuantity : 1; + + for(int q = 0; q < loopCount; q++) { + if(!hasProject) { + // 프로젝트가 없으면 모든 품목에 대해 생성 + Map projectParam = new HashMap(); + projectParam.putAll(paramMap); // 기본 정보 복사 + + // 품목별 정보 설정 + projectParam.put("OBJID", CommonUtils.createObjId()); + projectParam.put("is_temp", '1'); + projectParam.put("part_objid", item.get("PART_OBJID")); + projectParam.put("part_no", item.get("PART_NO")); + projectParam.put("part_name", item.get("PART_NAME")); + // Machine인 경우 각 프로젝트의 수량은 1, 아니면 원래 수량 + projectParam.put("quantity", isMachine ? "1" : String.valueOf(itemQuantity)); + projectParam.put("due_date", item.get("DUE_DATE")); + + if("0000170".equals(category_cd) || "0000171".equals(category_cd)){ + projectParam.put("overhaul_project_no", target_project_no); + } + + if(isMachine) { + System.out.println("프로젝트 생성 [" + (q+1) + "/" + loopCount + "] - PART_OBJID: " + item.get("PART_OBJID") + ", 품번: " + item.get("PART_NO") + ", 품명: " + item.get("PART_NAME") + ", 수량: 1"); + } else { + System.out.println("프로젝트 생성 - PART_OBJID: " + item.get("PART_OBJID") + ", 품번: " + item.get("PART_NO") + ", 품명: " + item.get("PART_NAME") + ", 수량: " + itemQuantity); + } + + // 프로젝트 등록 + cnt = sqlSession.update("project.createProject", projectParam); + // 프로젝트 TASK 등록 + cnt = sqlSession.insert("contractMgmt.insertProjectTask", projectParam); + // 프로젝트 SETUP_TASK 등록 + cnt = sqlSession.insert("contractMgmt.insertProjectSetupTask", projectParam); + + // project_no - unit 폴더 생성 + Map projectInfo = (Map)sqlSession.selectOne("project.getProjectMngInfo", projectParam); + + projectParam.put("contract_objid", contract_objid); + projectParam.put("customer_product", projectParam.get("mechanical_type")); + List> taskUnitList = (ArrayList)sqlSession.selectList("project.getWbsTaskListByProject", projectParam); + if(CommonUtils.isNotEmpty(taskUnitList) && !taskUnitList.isEmpty()){ + String projectNo = (String)projectInfo.get("project_no"); + String filepath = Constants.FILE_STORAGE+"\\PART_DATA\\"; + for (Map map : taskUnitList) { + File file = new File(filepath+File.separator+projectNo+File.separator+CommonUtils.checkNull((String)map.get("unit_no"))+"-"+CommonUtils.checkNull((String)map.get("task_name"))); + if(!file.exists()){ + file.mkdirs(); + } + } + } + } else { + // 프로젝트가 있으면 모든 품목 업데이트 (수량, 금액 등만) + Map updateParam = new HashMap(); + updateParam.putAll(paramMap); + updateParam.put("part_objid", item.get("PART_OBJID")); + updateParam.put("quantity", String.valueOf(itemQuantity)); + updateParam.put("due_date", item.get("DUE_DATE")); + + System.out.println("프로젝트 업데이트 - PART_OBJID: " + item.get("PART_OBJID") + ", 수량: " + itemQuantity); + sqlSession.update("project.ModifyProjectByContract", updateParam); + } + } + } + } else { + System.out.println("품목이 없습니다 - 기존 방식으로 프로젝트 생성"); + // 품목이 없는 경우 기존 방식대로 처리 + if(!hasProject){ + paramMap.put("OBJID", CommonUtils.createObjId()); + paramMap.put("is_temp", '1'); + if("0000170".equals(category_cd) || "0000171".equals(category_cd)){ + paramMap.put("overhaul_project_no", target_project_no); + } + cnt = sqlSession.update("project.createProject", paramMap); + cnt = sqlSession.insert("contractMgmt.insertProjectTask", paramMap); + cnt = sqlSession.insert("contractMgmt.insertProjectSetupTask", paramMap); + }else{ + sqlSession.update("project.ModifyProjectByContract", paramMap); + } + } + } + + sqlSession.commit(); + resultMap.put("result", "true"); + resultMap.put("msg", "저장되었습니다."); + + } catch (Exception e) { + e.printStackTrace(); + resultMap.put("result", "false"); + resultMap.put("msg", "저장 중 오류가 발생했습니다: " + e.getMessage()); + if(sqlSession != null) { + sqlSession.rollback(); + } + } finally { + if(sqlSession != null) sqlSession.close(); + } + + return resultMap; + } + @SuppressWarnings({ "rawtypes", "unchecked" }) public Map saveOrderInfo(HttpServletRequest request, Map paramMap){ Map resultMap = new HashMap(); @@ -2672,6 +2945,7 @@ private String encodeImageToBase64(String imagePath) { } // 품목별로 프로젝트 생성 또는 업데이트 + paramMap.put("contractObjId", contract_objid); List contractItems = getContractItems(paramMap); if(contractItems != null && !contractItems.isEmpty()) {