diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/salesMng.xml b/WebContent/WEB-INF/classes/com/pms/mapper/salesMng.xml index c74dadc..c752153 100644 --- a/WebContent/WEB-INF/classes/com/pms/mapper/salesMng.xml +++ b/WebContent/WEB-INF/classes/com/pms/mapper/salesMng.xml @@ -663,6 +663,20 @@ VALUES SRM.PROJECT_NO, PM.PROJECT_NO AS PROJECT_NUMBER, PM.PROJECT_NAME, + COALESCE( + PM.OBJID, + (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1) + ) AS PROJECT_MGMT_OBJID, + -- M-BOM 조회용: MBOM_HEADER에서 직접 OBJID 가져오기 + (SELECT MH.OBJID FROM MBOM_HEADER MH + WHERE MH.PROJECT_OBJID = COALESCE(PM.OBJID, (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)) + AND MH.STATUS = 'Y' + ORDER BY MH.REGDATE DESC LIMIT 1 + ) AS MBOM_HEADER_OBJID, + COALESCE( + PM.BOM_REPORT_OBJID, + (SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1) + ) AS BOM_REPORT_OBJID, PM.SETUP, SM.SUPPLY_NAME AS CUSTOMER_NAME, SM.OBJID::VARCHAR AS CUSTOMER_OBJID, -- 고객사 OBJID (드롭다운 선택용) @@ -705,7 +719,7 @@ VALUES FROM SALES_REQUEST_MASTER SRM - LEFT JOIN PROJECT_MGMT PM ON SRM.PROJECT_NO = PM.OBJID::VARCHAR + LEFT JOIN PROJECT_MGMT PM ON (SRM.PROJECT_NO = PM.OBJID::VARCHAR OR SRM.PROJECT_NO = PM.PROJECT_NO) LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID::VARCHAR LEFT JOIN SUPPLY_MNG SM ON CM.CUSTOMER_OBJID::VARCHAR = SM.OBJID::VARCHAR LEFT JOIN PURCHASE_ORDER_MASTER POM ON SRM.OBJID = POM.SALES_REQUEST_OBJID @@ -1242,31 +1256,51 @@ VALUES AND PM.OBJID = #{PROJECT_NO} + + + @@ -2775,18 +2809,19 @@ UPDATE SET + + + SELECT + SRP.OBJID, + SRP.SALES_REQUEST_MASTER_OBJID, + SRP.PART_OBJID, + COALESCE(PM.PART_NO, '') AS PART_NO, + COALESCE(PM.PART_NAME, '') AS PART_NAME, + SRP.QTY, + 0 AS ITEM_QTY, + -- 파일 개수 + (SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT, + (SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT, + (SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT, + COALESCE(PM.MATERIAL, '') AS MATERIAL, + COALESCE(PM.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS, + COALESCE(PM.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD, + COALESCE(PM.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT, + COALESCE(PM.MAKER, '') AS VENDOR, + (SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE) AS PART_TYPE_TITLE, + '' AS SUPPLY_TYPE, + '' AS RAW_MATERIAL, + '' AS SIZE, + '' AS RAW_MATERIAL_NO, + 0 AS REQUIRED_QTY, + 0 AS ORDER_QTY, + 0 AS ITEM_QTY2, + 0 AS PRODUCTION_QTY, + '' AS PROCESSING_VENDOR, + NULL AS PROCESSING_DEADLINE, + NULL AS GRINDING_DEADLINE, + -- 구매 관련 컬럼 (SALES_REQUEST_PART에서 조회) + COALESCE(SRP.USE_YN, 'Y') AS USE_YN, + COALESCE(SRP.NET_QTY, 0) AS NET_QTY, + COALESCE(SRP.PO_QTY, 0) AS PO_QTY, + COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID) AS VENDOR_PM, + COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE, + COALESCE(SRP.TOTAL_PRICE, 0) AS TOTAL_PRICE, + SRP.PROPOSAL_DATE, + 'SRP' AS DATA_SOURCE -- 데이터 소스 구분용 + FROM + SALES_REQUEST_PART SRP + LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR + WHERE + SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID} + ORDER BY + SRP.REGDATE + + + + + + + + + + + UPDATE MBOM_DETAIL SET + USE_YN = #{USE_YN}, + NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0), + PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0), + VENDOR = #{VENDOR_PM}, + UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0), + TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0), + PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END, + EDITER = #{EDITER}, + EDIT_DATE = NOW() + WHERE OBJID::VARCHAR = #{OBJID} + + + + + UPDATE SALES_REQUEST_PART SET + USE_YN = #{USE_YN}, + NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0), + PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0), + VENDOR_PM = #{VENDOR_PM}, + UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0), + TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0), + PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END, + WRITER = #{EDITER} + WHERE OBJID::VARCHAR = #{OBJID} + \ No newline at end of file diff --git a/WebContent/WEB-INF/view/admin/clientMng/clientExcelImportPopUp.jsp b/WebContent/WEB-INF/view/admin/clientMng/clientExcelImportPopUp.jsp index 7743831..2feb4f2 100644 --- a/WebContent/WEB-INF/view/admin/clientMng/clientExcelImportPopUp.jsp +++ b/WebContent/WEB-INF/view/admin/clientMng/clientExcelImportPopUp.jsp @@ -152,14 +152,14 @@ $(document).ready(function(){ ,{name:"CLIENT_TYPE",index:"CLIENT_TYPE", width: 100, align:"center", hidden: false, sortable:false, editable:true ,edittype:"select" ,formatter:"select" - ,editoptions:{ + ,editoptions:{ value: client_type - ,dataInit : function(e){ - e.style.width = "92%"; - e.style.fontSize = 13; - } - } - } + ,dataInit : function(e){ + e.style.width = "92%"; + e.style.fontSize = 13; + } + } + } ,{name:"BUS_REG_NO",index:"BUS_REG_NO", width: 150, align:"center", hidden: false, sortable:false, editable:true ,editoptions:{dataInit : function(e){e.style.fontSize = 13;}} } @@ -513,23 +513,23 @@ function fn_count(){ var clientCd = gridData[i].CLIENT_CD; if(clientCd && clientCd.trim() !== ""){ // AJAX로 중복 체크 - $.ajax({ + $.ajax({ url:"/admin/checkDuplicateClientMngList.do", - type:"POST", + type:"POST", data:{"CLIENT_CD": clientCd}, - dataType:"json", - async: false, - success:function(data){ + dataType:"json", + async: false, + success:function(data){ if(data.result == "true"){ dupCnt++; // 중복 } else { nowCnt++; // 신규 } - }, - error: function(jqxhr, status, error){ + }, + error: function(jqxhr, status, error){ nowCnt++; // 에러 시 신규로 간주 - } - }); + } + }); } } diff --git a/WebContent/WEB-INF/view/admin/clientMng/clientMngListFormPopUp.jsp b/WebContent/WEB-INF/view/admin/clientMng/clientMngListFormPopUp.jsp index 981b04e..35f1f19 100644 --- a/WebContent/WEB-INF/view/admin/clientMng/clientMngListFormPopUp.jsp +++ b/WebContent/WEB-INF/view/admin/clientMng/clientMngListFormPopUp.jsp @@ -20,7 +20,7 @@ function saveClient(){ alert(result.MESSAGE || result.message); if(result.RESULTFLAG == "true" || result.resultFlag == "true"){ if(opener && opener.fn_search){ - opener.fn_search(); + opener.fn_search(); } self.close(); } diff --git a/WebContent/WEB-INF/view/admin/warehouseList/warehouseListFormPopUp.jsp b/WebContent/WEB-INF/view/admin/warehouseList/warehouseListFormPopUp.jsp index 4deadb9..70a1aac 100644 --- a/WebContent/WEB-INF/view/admin/warehouseList/warehouseListFormPopUp.jsp +++ b/WebContent/WEB-INF/view/admin/warehouseList/warehouseListFormPopUp.jsp @@ -21,20 +21,20 @@ function saveWarehouse(){ form.modify_dt.value = convertToDBFormat(modifyDt); } - $.ajax({ + $.ajax({ type: "POST", url: "/admin/saveWarehouseListInfo.do", data: $(form).serialize(), dataType: "json", - success: function(result){ + success: function(result){ alert(result.message); if(result.resultFlag == "true"){ opener.fn_search(); self.close(); - } - } - }); - } + } + } + }); + } } function convertToDBFormat(dateStr) { @@ -70,10 +70,10 @@ function convertToDBFormat(dateStr) { -
-
+
+

창고 등록/수정

-
+
@@ -87,94 +87,94 @@ function convertToDBFormat(dateStr) { 위치명
-
+
+
-
-
+ + \ No newline at end of file diff --git a/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp b/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp index e1d6857..37ff63f 100644 --- a/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp +++ b/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp @@ -1,240 +1,741 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> -<%@ page import="com.pms.common.utils.*"%> -<%@ page import="java.util.*" %> +<%@ 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"%> - - - - - - + + +<%-- MBOM_HEADER.OBJID를 직접 사용 (M-BOM 관리 화면에서 사용하는 것과 동일) --%> + + + + + <%=Constants.SYSTEM_NAME%> + + + + +
+
+ + +
+ +
+
+
+ + +
+ - - - -
- - -
-
-

- 구매리스트 작성 -

-
- -
-
- - - - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NO품번품명수량항목수량3D2DPDF재료열처리경도열처리방법표면처리공급업체범주이름지급/사급소재사이즈소재품번소재소요량소재발주수량항목수량제작수량가공업체가공납기연삭납기사용여부정미수량발주수량공급업체단가총단가품의서작성일
-
-
-
- + - diff --git a/WebContent/WEB-INF/view/salesMng/salesRequestFormPopUp.jsp b/WebContent/WEB-INF/view/salesMng/salesRequestFormPopUp.jsp index b22ff50..92349f3 100644 --- a/WebContent/WEB-INF/view/salesMng/salesRequestFormPopUp.jsp +++ b/WebContent/WEB-INF/view/salesMng/salesRequestFormPopUp.jsp @@ -178,6 +178,8 @@ $("#REQUEST_CD,#PROJECT_NO,#CUSTOMER_NAME,#PRODUCT_NAME,#MECHANICAL_TYPE,#PROJEC } } + // ★★★ M-BOM 품목 자동 로드 ★★★ + fn_loadMbomParts($(this).val()); } }); @@ -296,14 +298,35 @@ function fn_getSalesRequestTargetPartList(masterObjId,bomObjId){ }); $("#partListArea").append(appendText); + // 프로젝트번호가 설정되어 있는지 확인하고, 없으면 품번 드롭다운을 채울 수 없음 + var projectNo = $("#PROJECT_NO").val(); + if(!projectNo || projectNo == "") { + console.warn("프로젝트번호가 선택되지 않아 품번 목록을 불러올 수 없습니다."); + } + $.each(resultData, function(i){ var rowObjId = fnc_checkNull(resultData[i].OBJID); var PART_OBJID = fnc_checkNull(resultData[i].PART_OBJID); + var PART_NO = fnc_checkNull(resultData[i].PART_NO); + var PART_NAME = fnc_checkNull(resultData[i].PART_NAME); + // 공급업체 제거로 주석처리 // var PARTNER_OBJID = fnc_checkNull(resultData[i].PARTNER_OBJID); // fnc_getAdminSupCdListAppend("", "PARTNER_OBJID_"+rowObjId, PARTNER_OBJID); // $("#PARTNER_OBJID_"+rowObjId).val(PARTNER_OBJID); + fn_addBomPart("PART_OBJID_"+rowObjId, PART_OBJID, "PART_NAME_"+rowObjId,""); + + // M-BOM에 없는 품번이면 수동으로 추가 + if(PART_OBJID != "" && PART_NO != "") { + var selectBox = $("#PART_OBJID_"+rowObjId); + // 이미 옵션이 있는지 확인 + if(selectBox.find("option[value='"+PART_OBJID+"']").length == 0) { + selectBox.append(""); + } + selectBox.val(PART_OBJID); + $("#PART_NAME_"+rowObjId).val(PART_NAME); + } }); $(".select2").select2(); }, @@ -469,44 +492,122 @@ function fn_Supply_save(){ } } +// ★★★ 프로젝트 선택 시 M-BOM 품목 자동 로드 ★★★ +function fn_loadMbomParts(projectObjId){ + if(fnc_checkNull(projectObjId) == "") return; + + console.log("M-BOM 품목 로드 시작, PROJECT_OBJID:", projectObjId); + + // M-BOM 품목 조회 + var paramData = {"sqlId":"salesMng.SalesBomPartListByProjectUnit", "PROJECT_OBJID":projectObjId}; + var resultList = fnc_getJsonAllDataListBySqlId(paramData); + + console.log("M-BOM 품목 조회 결과:", resultList); + + if(resultList && resultList.length > 0){ + // 기존 품목 초기화 + $("#partListArea").empty(); + + // M-BOM 품목을 행으로 추가 + $.each(resultList, function(i, item){ + var rowObjId = fnc_createObjId(); + var PART_OBJID = fnc_checkNull(item.PART_OBJID); + var PART_NO = fnc_checkNull(item.PART_NO); + var PART_NAME = fnc_checkNull(item.PART_FULL_NAME) || fnc_checkNull(item.PART_NAME); + var QTY = fnc_checkNull(item.ORDER_QTY) || 1; + + var appendText = ""; + appendText += ""; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += " "; + appendText += ""; + + $("#partListArea").append(appendText); + + // 품번 드롭다운에 M-BOM 전체 품목 옵션 추가 + fn_addBomPart("PART_OBJID_"+rowObjId, PART_OBJID, "PART_NAME_"+rowObjId, ""); + }); + + $(".select2").select2(); + console.log("M-BOM 품목 " + resultList.length + "건 로드 완료"); + } else { + console.log("M-BOM 품목이 없습니다."); + } +} + //계약제품, 업체명으로 BOM에 등록된 부품정보를 자동 추가 function fn_addBomPart(selectboxId,selectedVal,sql_id,sql_supply){ $("#BOM_REPORT_OBJID").val(""); - //var type = $("#TYPE").val(); //발주부품 var project_objid = $("#PROJECT_NO").val(); //프로젝트명 var unit_code = $("#UNIT_NAME").val(); //유닛명 - //var partner_objid = $("#PARTNER_OBJID").val(); //공급업체 - //console.log('type:'+type + ' contract_mgmt_objid:'+contract_mgmt_objid + ' unit_code:'+unit_code + ' partner_objid:'+partner_objid); + $("#"+selectboxId).empty(); + $("#"+selectboxId).append(""); - //프로젝트번호만 있으면 품번 조회 가능 (유닛명은 선택사항) + var resultList = []; + + // 1. 프로젝트가 선택되어 있으면 M-BOM 품목 먼저 조회 if(fnc_checkNull(project_objid)!=""){ - $("#"+selectboxId).empty(); - $("#"+selectboxId).append(""); - //구매BOM 조회해서 부품정보를 가져온다 var paramData = {"sqlId":"salesMng.SalesBomPartListByProjectUnit", "PROJECT_OBJID":project_objid}; - // 유닛명이 있으면 추가 if(fnc_checkNull(unit_code)!=""){ paramData.UNIT_CODE = unit_code; } - var resultList = fnc_getJsonAllDataListBySqlId(paramData); + resultList = fnc_getJsonAllDataListBySqlId(paramData); + console.log("M-BOM 품목 조회 결과:", resultList.length, "건"); + } + + // 2. M-BOM 품목이 없으면 전체 PART_MNG에서 조회 + if(resultList.length == 0){ + console.log("M-BOM 품목이 없어 전체 품목에서 조회합니다."); + var allPartData = {"sqlId":"salesMng.getAllPartMngList"}; + resultList = fnc_getJsonAllDataListBySqlId(allPartData); + console.log("전체 품목 조회 결과:", resultList.length, "건"); + + // 전체 품목 조회 결과 처리 if(0 < resultList.length){ for (var i = 0; i < resultList.length; i++) { - var commonCodeId = resultList[i].PART_OBJID; + var commonCodeId = resultList[i].OBJID; var commonCodeName = resultList[i].PART_NO; var partName = resultList[i].PART_NAME; - var supplyObjid = resultList[i].SUPPLY_OBJID; - $("#"+selectboxId).append(""); + $("#"+selectboxId).append(""); } - $("#"+selectboxId).val(selectedVal); - $("#"+selectboxId).change(function(){ - $("#"+sql_id).val($(this).find("option:selected").attr("data-part_name")); - $("#"+sql_supply).val($(this).find("option:selected").attr("data-supplyObjid")); - }); + } + } else { + // M-BOM 품목 처리 + for (var i = 0; i < resultList.length; i++) { + var commonCodeId = resultList[i].PART_OBJID; + var commonCodeName = resultList[i].PART_NO; + var partName = resultList[i].PART_NAME || resultList[i].PART_FULL_NAME; + var supplyObjid = resultList[i].SUPPLY_OBJID; + $("#"+selectboxId).append(""); } } + // 선택값 설정 및 change 이벤트 바인딩 + if(fnc_checkNull(selectedVal) != ""){ + $("#"+selectboxId).val(selectedVal); + } + $("#"+selectboxId).off("change").on("change", function(){ + $("#"+sql_id).val($(this).find("option:selected").attr("data-part_name")); + if(sql_supply){ + $("#"+sql_supply).val($(this).find("option:selected").attr("data-supplyObjid")); + } + }); + $("#"+selectboxId).trigger("change"); } diff --git a/WebContent/WEB-INF/view/salesMng/salesRequestMngRegList.jsp b/WebContent/WEB-INF/view/salesMng/salesRequestMngRegList.jsp index 2cbd8cb..8b232ea 100644 --- a/WebContent/WEB-INF/view/salesMng/salesRequestMngRegList.jsp +++ b/WebContent/WEB-INF/view/salesMng/salesRequestMngRegList.jsp @@ -100,7 +100,7 @@ $(document).ready(function(){ //구매요청서 작성 $("#btnOrderReg").click(function(){ - fn_openSalesRequestPopUp(""); + fn_openSalesRequestFormPopUp(""); }); //품의서 생성 (TODO: 품의서 생성 기능 구현 필요 - 기존 발주서 작성 기능과 다름) @@ -221,16 +221,16 @@ var columns = [ ,{headerHozAlign : 'center', hozAlign : 'center', title : "유/무상", field :"PAID_TYPE_NAME" , widthGrow:0.9 } ,{headerHozAlign : 'center', hozAlign : 'left', title : "품번", field :"PART_NO" , widthGrow:1.4} ,{headerHozAlign : 'center', hozAlign : 'left' , title : "품명", field :"PART_NAME" , widthGrow:1.8 } - ,{headerHozAlign : 'center', hozAlign : 'center', title : "구매요청서", field :"REQUEST_MNG_NO" , widthGrow:1.1, - formatter: function(cell, formatterParams, onRendered){ - var objid = fnc_checkNull(cell.getData().OBJID); - var iconClass = (objid != '' && objid != null) ? 'file_icon' : 'file_empty_icon'; - return ''; - }, - cellClick : function(e, cell) { - fn_openSalesRequestPopUp(cell.getData().OBJID); + ,{headerHozAlign : 'center', hozAlign : 'center', title : "구매요청서", field :"REQUEST_MNG_NO" , widthGrow:1.1, + formatter: function(cell, formatterParams, onRendered){ + var objid = fnc_checkNull(cell.getData().OBJID); + var iconClass = (objid != '' && objid != null) ? 'file_icon' : 'file_empty_icon'; + return ''; + }, + cellClick : function(e, cell) { + fn_openSalesRequestFormPopUp(cell.getData().OBJID); } - } + } ,{headerHozAlign : 'center', hozAlign : 'center', title : "요청인", field :"REQUEST_USER_NAME" , widthGrow:1.1 } ,{headerHozAlign : 'center', hozAlign : 'center', title : "입고요청일", field :"DELIVERY_REQUEST_DATE" , widthGrow:1.1 } ,{headerHozAlign : 'center', hozAlign : 'center', title : "작성일", field :"REGDATE_TITLE" , widthGrow:1.1 } @@ -281,17 +281,16 @@ function fn_salesRequestTargetBOMListPopUp(){ window.open(url,"salesRequestTargetBOMListPopUp","width=1300,height=550"); } -//구매의뢰 요청 팝업 +//구매의뢰 요청 팝업 (요청번호 클릭 시 - 구매리스트 화면) function fn_openSalesRequestPopUp(objId){ - var url = ""; - - if("" == objId){ - url = "/salesMng/salesRequestFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId; - }else{ - //url = "/salesMng/salesRequestDetailPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId; - url = "/salesMng/salesRequestFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId; - } - window.open(url,"salesRequestPopUp","width=1100,height=630"); + var url = "/salesMng/purchaseListFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId; + window.open(url,"purchaseListPopUp","width=1400,height=800,scrollbars=yes,resizable=yes"); +} + +//구매요청서 작성 팝업 (구매요청서 파일 아이콘 클릭 시) +function fn_openSalesRequestFormPopUp(objId){ + var url = "/salesMng/salesRequestFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId; + window.open(url,"salesRequestFormPopUp","width=1100,height=630"); } function fn_releaseSalesRequest(){ diff --git a/database/add_minimal_purchase_columns.sql b/database/add_minimal_purchase_columns.sql new file mode 100644 index 0000000..d373960 --- /dev/null +++ b/database/add_minimal_purchase_columns.sql @@ -0,0 +1,17 @@ +-- SALES_REQUEST_PART 테이블에 구매리스트 필수 컬럼만 추가 +-- 기존: OBJID, PART_OBJID, SALES_REQUEST_MASTER_OBJID, QTY, PARTNER_OBJID, PARTNER_PRICE, WRITER, REGDATE 등 + +ALTER TABLE SALES_REQUEST_PART +ADD COLUMN IF NOT EXISTS PART_NO VARCHAR(100), -- 품번 (직접 입력용) +ADD COLUMN IF NOT EXISTS PART_NAME VARCHAR(200), -- 품명 (직접 입력용) +ADD COLUMN IF NOT EXISTS UNIT_PRICE VARCHAR(50), -- 단가 +ADD COLUMN IF NOT EXISTS TOTAL_PRICE VARCHAR(50), -- 총단가 +ADD COLUMN IF NOT EXISTS PROPOSAL_DATE DATE; -- 품의서작성일 + +-- 컬럼 설명 +COMMENT ON COLUMN SALES_REQUEST_PART.PART_NO IS '품번'; +COMMENT ON COLUMN SALES_REQUEST_PART.PART_NAME IS '품명'; +COMMENT ON COLUMN SALES_REQUEST_PART.UNIT_PRICE IS '단가'; +COMMENT ON COLUMN SALES_REQUEST_PART.TOTAL_PRICE IS '총단가'; +COMMENT ON COLUMN SALES_REQUEST_PART.PROPOSAL_DATE IS '품의서작성일'; + diff --git a/db/add_sales_request_part_purchase_columns.sql b/db/add_sales_request_part_purchase_columns.sql new file mode 100644 index 0000000..6d97c9d --- /dev/null +++ b/db/add_sales_request_part_purchase_columns.sql @@ -0,0 +1,39 @@ +-- SALES_REQUEST_PART 테이블에 구매관리 관련 컬럼 추가 +-- 실행 전 백업 권장 + +-- 사용여부 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS USE_YN VARCHAR(1) DEFAULT 'Y'; +COMMENT ON COLUMN SALES_REQUEST_PART.USE_YN IS '사용여부 (Y/N)'; + +-- 정미수량 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS NET_QTY NUMERIC DEFAULT 0; +COMMENT ON COLUMN SALES_REQUEST_PART.NET_QTY IS '정미수량'; + +-- 발주수량 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS PO_QTY NUMERIC DEFAULT 0; +COMMENT ON COLUMN SALES_REQUEST_PART.PO_QTY IS '발주수량'; + +-- 공급업체2 (기준정보에서 선택) +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS VENDOR_PM VARCHAR(255); +COMMENT ON COLUMN SALES_REQUEST_PART.VENDOR_PM IS '공급업체2 (기준정보_협력업체관리)'; + +-- 단가 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS UNIT_PRICE NUMERIC DEFAULT 0; +COMMENT ON COLUMN SALES_REQUEST_PART.UNIT_PRICE IS '단가'; + +-- 총단가 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS TOTAL_PRICE NUMERIC DEFAULT 0; +COMMENT ON COLUMN SALES_REQUEST_PART.TOTAL_PRICE IS '총단가 (발주수량 * 단가)'; + +-- 품의서작성일 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS PROPOSAL_DATE DATE; +COMMENT ON COLUMN SALES_REQUEST_PART.PROPOSAL_DATE IS '품의서작성일'; + +-- 수정자 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS EDITER VARCHAR(50); +COMMENT ON COLUMN SALES_REQUEST_PART.EDITER IS '수정자'; + +-- 수정일 +ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS EDIT_DATE TIMESTAMP; +COMMENT ON COLUMN SALES_REQUEST_PART.EDIT_DATE IS '수정일'; + diff --git a/src/com/pms/mapper/salesMng.xml b/src/com/pms/mapper/salesMng.xml index c74dadc..c752153 100644 --- a/src/com/pms/mapper/salesMng.xml +++ b/src/com/pms/mapper/salesMng.xml @@ -663,6 +663,20 @@ VALUES SRM.PROJECT_NO, PM.PROJECT_NO AS PROJECT_NUMBER, PM.PROJECT_NAME, + COALESCE( + PM.OBJID, + (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1) + ) AS PROJECT_MGMT_OBJID, + -- M-BOM 조회용: MBOM_HEADER에서 직접 OBJID 가져오기 + (SELECT MH.OBJID FROM MBOM_HEADER MH + WHERE MH.PROJECT_OBJID = COALESCE(PM.OBJID, (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)) + AND MH.STATUS = 'Y' + ORDER BY MH.REGDATE DESC LIMIT 1 + ) AS MBOM_HEADER_OBJID, + COALESCE( + PM.BOM_REPORT_OBJID, + (SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1) + ) AS BOM_REPORT_OBJID, PM.SETUP, SM.SUPPLY_NAME AS CUSTOMER_NAME, SM.OBJID::VARCHAR AS CUSTOMER_OBJID, -- 고객사 OBJID (드롭다운 선택용) @@ -705,7 +719,7 @@ VALUES FROM SALES_REQUEST_MASTER SRM - LEFT JOIN PROJECT_MGMT PM ON SRM.PROJECT_NO = PM.OBJID::VARCHAR + LEFT JOIN PROJECT_MGMT PM ON (SRM.PROJECT_NO = PM.OBJID::VARCHAR OR SRM.PROJECT_NO = PM.PROJECT_NO) LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID::VARCHAR LEFT JOIN SUPPLY_MNG SM ON CM.CUSTOMER_OBJID::VARCHAR = SM.OBJID::VARCHAR LEFT JOIN PURCHASE_ORDER_MASTER POM ON SRM.OBJID = POM.SALES_REQUEST_OBJID @@ -1242,31 +1256,51 @@ VALUES AND PM.OBJID = #{PROJECT_NO} + + + @@ -2775,18 +2809,19 @@ UPDATE SET + + + SELECT + SRP.OBJID, + SRP.SALES_REQUEST_MASTER_OBJID, + SRP.PART_OBJID, + COALESCE(PM.PART_NO, '') AS PART_NO, + COALESCE(PM.PART_NAME, '') AS PART_NAME, + SRP.QTY, + 0 AS ITEM_QTY, + -- 파일 개수 + (SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT, + (SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT, + (SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT, + COALESCE(PM.MATERIAL, '') AS MATERIAL, + COALESCE(PM.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS, + COALESCE(PM.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD, + COALESCE(PM.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT, + COALESCE(PM.MAKER, '') AS VENDOR, + (SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE) AS PART_TYPE_TITLE, + '' AS SUPPLY_TYPE, + '' AS RAW_MATERIAL, + '' AS SIZE, + '' AS RAW_MATERIAL_NO, + 0 AS REQUIRED_QTY, + 0 AS ORDER_QTY, + 0 AS ITEM_QTY2, + 0 AS PRODUCTION_QTY, + '' AS PROCESSING_VENDOR, + NULL AS PROCESSING_DEADLINE, + NULL AS GRINDING_DEADLINE, + -- 구매 관련 컬럼 (SALES_REQUEST_PART에서 조회) + COALESCE(SRP.USE_YN, 'Y') AS USE_YN, + COALESCE(SRP.NET_QTY, 0) AS NET_QTY, + COALESCE(SRP.PO_QTY, 0) AS PO_QTY, + COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID) AS VENDOR_PM, + COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE, + COALESCE(SRP.TOTAL_PRICE, 0) AS TOTAL_PRICE, + SRP.PROPOSAL_DATE, + 'SRP' AS DATA_SOURCE -- 데이터 소스 구분용 + FROM + SALES_REQUEST_PART SRP + LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR + WHERE + SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID} + ORDER BY + SRP.REGDATE + + + + + + + + + + + UPDATE MBOM_DETAIL SET + USE_YN = #{USE_YN}, + NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0), + PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0), + VENDOR = #{VENDOR_PM}, + UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0), + TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0), + PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END, + EDITER = #{EDITER}, + EDIT_DATE = NOW() + WHERE OBJID::VARCHAR = #{OBJID} + + + + + UPDATE SALES_REQUEST_PART SET + USE_YN = #{USE_YN}, + NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0), + PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0), + VENDOR_PM = #{VENDOR_PM}, + UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0), + TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0), + PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END, + WRITER = #{EDITER} + WHERE OBJID::VARCHAR = #{OBJID} + \ No newline at end of file diff --git a/src/com/pms/salesmgmt/controller/SalesMngController.java b/src/com/pms/salesmgmt/controller/SalesMngController.java index 30de9b2..61ee6fa 100644 --- a/src/com/pms/salesmgmt/controller/SalesMngController.java +++ b/src/com/pms/salesmgmt/controller/SalesMngController.java @@ -1095,23 +1095,90 @@ public class SalesMngController { */ @RequestMapping("/salesMng/purchaseListFormPopUp.do") public String purchaseListFormPopUp(HttpServletRequest request, @RequestParam Map paramMap){ + Map resultMap = new HashMap(); + try{ + String salesRequestMasterObjId = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID")); + String projectMgmtObjId = CommonUtils.checkNull(paramMap.get("PROJECT_MGMT_OBJID")); + + if(!"".equals(salesRequestMasterObjId)){ + // 기존 구매리스트 조회 + resultMap = salesMngService.getSalesRequestMasterInfo(request, paramMap); + }else if(!"".equals(projectMgmtObjId)){ + // M-BOM에서 새로 생성 + resultMap.put("OBJID", CommonUtils.createObjId()); + resultMap.put("STATUS", "create"); + }else{ + resultMap.put("OBJID", CommonUtils.createObjId()); + resultMap.put("STATUS", "create"); + } + }catch(Exception e){ + e.printStackTrace(); + } + + request.setAttribute("resultMap", resultMap); return "/salesMng/purchaseListFormPopUp"; } /** - * 구매리스트 데이터 조회 + * 구매리스트 상세 조회 (기존 구매리스트) * @param request * @param paramMap * @return */ @ResponseBody - @RequestMapping("/salesMng/getPurchaseListData.do") - public Map getPurchaseListData(HttpServletRequest request, @RequestParam Map paramMap){ + @RequestMapping("/salesMng/getPurchaseListDetail.do") + public Map getPurchaseListDetail(HttpServletRequest request, @RequestParam Map paramMap){ Map resultMap = new HashMap(); try{ - resultMap = salesMngService.getPurchaseListData(request, paramMap); + List list = salesMngService.getPurchaseListDetail(request, paramMap); + resultMap.put("list", list); }catch(Exception e){ e.printStackTrace(); + resultMap.put("list", new ArrayList()); + } + return resultMap; + } + + /** + * M-BOM에서 구매리스트 생성 + * @param request + * @param paramMap + * @return + */ + @ResponseBody + @RequestMapping("/salesMng/getMBomForPurchaseList.do") + public Map getMBomForPurchaseList(HttpServletRequest request, @RequestParam Map paramMap){ + Map resultMap = new HashMap(); + try{ + System.out.println("========== getMBomForPurchaseList 호출 =========="); + System.out.println("paramMap: " + paramMap); + System.out.println("PROJECT_MGMT_OBJID: " + paramMap.get("PROJECT_MGMT_OBJID")); + System.out.println("bomReportObjId: " + paramMap.get("bomReportObjId")); + + List list = salesMngService.getMBomForPurchaseList(request, paramMap); + + // 키를 대문자로 변환 + List> upperList = new ArrayList>(); + if(list != null) { + for(Map item : list) { + Map upperItem = new HashMap(); + for(Object key : item.keySet()) { + upperItem.put(key.toString().toUpperCase(), item.get(key)); + } + upperList.add(upperItem); + } + } + + System.out.println("결과 리스트 크기: " + upperList.size()); + if(!upperList.isEmpty()) { + System.out.println("첫번째 항목: " + upperList.get(0)); + } + + resultMap.put("list", upperList); + }catch(Exception e){ + System.out.println("getMBomForPurchaseList 오류 발생!"); + e.printStackTrace(); + resultMap.put("list", new ArrayList()); } return resultMap; } diff --git a/src/com/pms/salesmgmt/service/SalesMngService.java b/src/com/pms/salesmgmt/service/SalesMngService.java index 1a20022..2372db4 100644 --- a/src/com/pms/salesmgmt/service/SalesMngService.java +++ b/src/com/pms/salesmgmt/service/SalesMngService.java @@ -1736,15 +1736,23 @@ public class SalesMngService { try { sqlSession = SqlMapConfig.getInstance().getSqlSession(false); String salesRequestMasterObjid = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID")); - String partListJson = CommonUtils.checkNull(paramMap.get("partList")); + String purchaseListJson = CommonUtils.checkNull(paramMap.get("purchaseListData")); - // JSON 파싱 - 기존 코드 참고하여 간단하게 처리 - // partListJson이 이미 파싱된 상태일 수 있으므로 직접 처리 - List partList = new ArrayList(); - // TODO: JSON 파싱 로직 추가 필요 + System.out.println("========== savePurchaseList =========="); + System.out.println("salesRequestMasterObjid: " + salesRequestMasterObjid); + System.out.println("purchaseListJson length: " + purchaseListJson.length()); - if(partList == null || partList.isEmpty()) { - resultMap.put("result", "error"); + // JSON 파싱 + List purchaseList = new ArrayList(); + if(purchaseListJson != null && !purchaseListJson.isEmpty()) { + org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper(); + purchaseList = mapper.readValue(purchaseListJson, List.class); + } + + System.out.println("purchaseList size: " + purchaseList.size()); + + if(purchaseList == null || purchaseList.isEmpty()) { + resultMap.put("resultFlag", "F"); resultMap.put("message", "저장할 데이터가 없습니다."); return resultMap; } @@ -1754,29 +1762,36 @@ public class SalesMngService { PersonBean personBean = (PersonBean) session.getAttribute(Constants.PERSON_BEAN); String userId = personBean.getUserId(); - // 각 품목별로 구매리스트 정보 저장 - for(Map partData : partList) { - String objid = CommonUtils.checkNull(partData.get("OBJID")); + // 각 품목별로 데이터 소스에 따라 다른 테이블 업데이트 + for(Map itemData : purchaseList) { + String objid = CommonUtils.checkNull(itemData.get("OBJID")); + String dataSource = CommonUtils.checkNull(itemData.get("DATA_SOURCE")); if(objid.isEmpty()) { - objid = CommonUtils.createObjId(); + System.out.println("OBJID가 없는 항목 스킵"); + continue; } - partData.put("OBJID", objid); - partData.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid); - partData.put("WRITER", userId); + itemData.put("EDITER", userId); - // SALES_REQUEST_PART 테이블에 저장 - sqlSession.insert("salesMng.mergePurchaseListInfo", partData); + if("SRP".equals(dataSource)) { + // SALES_REQUEST_PART 테이블 업데이트 (구매요청서에서 수동 추가한 품목) + System.out.println("SALES_REQUEST_PART 업데이트: " + objid); + sqlSession.update("salesMng.updateSalesRequestPartForPurchase", itemData); + } else { + // MBOM_DETAIL 테이블 업데이트 (M-BOM에서 가져온 품목) + System.out.println("MBOM_DETAIL 업데이트: " + objid); + sqlSession.update("salesMng.updateMbomDetailForPurchase", itemData); + } } - resultMap.put("result", "success"); + resultMap.put("resultFlag", "S"); resultMap.put("message", "저장되었습니다."); sqlSession.commit(); } catch(Exception e) { if(sqlSession != null) sqlSession.rollback(); - resultMap.put("result", "error"); + resultMap.put("resultFlag", "F"); resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage()); e.printStackTrace(); } finally { @@ -1785,4 +1800,53 @@ public class SalesMngService { return resultMap; } + + /** + * 구매리스트 상세 조회 (기존 저장된 데이터) + * @param request + * @param paramMap + * @return + * @throws Exception + */ + public List getPurchaseListDetail(HttpServletRequest request, Map paramMap) throws Exception { + SqlSession sqlSession = null; + List resultList = new ArrayList(); + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + resultList = sqlSession.selectList("salesMng.getPurchaseListDetail", paramMap); + } catch(Exception e) { + e.printStackTrace(); + throw e; + } finally { + if(sqlSession != null) sqlSession.close(); + } + + return resultList; + } + + /** + * M-BOM에서 구매리스트 데이터 가져오기 + * @param request + * @param paramMap + * @return + * @throws Exception + */ + public List getMBomForPurchaseList(HttpServletRequest request, Map paramMap) throws Exception { + SqlSession sqlSession = null; + List resultList = new ArrayList(); + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + // M-BOM 데이터 조회 (레벨 구조 없이 평평하게) + resultList = sqlSession.selectList("salesMng.getMBomForPurchaseList", paramMap); + } catch(Exception e) { + e.printStackTrace(); + throw e; + } finally { + if(sqlSession != null) sqlSession.close(); + } + + return resultList; + } }