diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp index 389ac82..50547d7 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp @@ -24,8 +24,23 @@ $(document).ready(function(){ //날짜 _fnc_datepick(); + // jQuery 및 select2 로드 확인 + console.log('jQuery loaded:', typeof $ !== 'undefined'); + console.log('jQuery.fn exists:', typeof $.fn !== 'undefined'); + console.log('select2 loaded:', typeof $.fn !== 'undefined' && typeof $.fn.select2 !== 'undefined'); - $('.select2').select2(); + // select2가 로드되었을 때만 초기화 + if(typeof $.fn !== 'undefined' && typeof $.fn.select2 === 'function') { + $('.select2').select2(); + + // 품번/품명 Select2 AJAX 초기화 (common.js의 새 함수 사용) + initPartSelect2Ajax("#search_partNo", "#search_partName", "#search_partObjId", { + debug: true // 디버깅 모드 활성화 + }); + } else { + console.error('select2 라이브러리가 로드되지 않았습니다.'); + console.error('$.fn:', $.fn); + } $("#btnSearch").click(function(){ $("#page").val("1"); @@ -178,7 +193,7 @@ $(document).ready(function(){ // 메일 발송 확인 Swal.fire({ title: '견적서 메일 발송', - text: "최종 차수의 견적서를 PDF로 발송하시겠습니까?", + text: "최종 차수의 견적서를 발송하시겠습니까?", icon: 'question', showCancelButton: true, confirmButtonText: '발송', @@ -381,6 +396,20 @@ var columns = [ //var grid; function fn_search(){ + // Select2 값을 실제 input/select에 명시적으로 설정 + var partObjId = $("#search_partObjId").val(); + + // 디버깅: 검색 조건 확인 + console.log("품번:", $("#search_partNo").val()); + console.log("품명:", $("#search_partName").val()); + console.log("품목 OBJID:", partObjId); + + // 품목 OBJID가 있으면 hidden 필드에 확실히 설정 + if(partObjId && partObjId !== '') { + // 폼 데이터에 명시적으로 추가 + console.log("품목 검색 조건 설정됨:", partObjId); + } + _tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/contractMgmt/contractGridList.do", columns, true); } @@ -495,6 +524,7 @@ function fn_showEstimateList(contractObjId){ html += '견적번호'; html += '작성일'; html += '작성자'; + html += '결재상태'; html += ''; data.list.forEach(function(item){ @@ -508,6 +538,19 @@ function fn_showEstimateList(contractObjId){ var estimateNo = item.ESTIMATE_NO || item.estimate_no || item.estimateNo || '-'; var regdate = item.REGDATE || item.regdate || ''; var writer = item.WRITER || item.writer || ''; + var apprStatus = item.APPR_STATUS || item.appr_status || item.apprStatus || '-'; + + // 결재상태별 색상 지정 + var statusColor = '#333'; + if(apprStatus === '결재완료') { + statusColor = 'green'; + } else if(apprStatus === '결재중') { + statusColor = 'blue'; + } else if(apprStatus === '반려') { + statusColor = 'red'; + } else if(apprStatus === '작성중') { + statusColor = '#999'; + } html += ''; html += '' + revision + '차'; @@ -515,6 +558,7 @@ function fn_showEstimateList(contractObjId){ html += '' + estimateNo + ''; html += '' + regdate + ''; html += '' + writer + ''; + html += '' + apprStatus + ''; html += ''; }); @@ -855,18 +899,23 @@ function openProjectFormPopUp(objId){ - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp index e13c313..342c1bb 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp @@ -224,6 +224,7 @@ var g_contractObjId = "<%=objId%>"; var g_templateObjId = "<%=templateObjId%>"; var g_exchangeRate = 1; // 환율 (기본값 1) var g_currencyName = "KRW"; // 통화명 (기본값 원화) +var g_apprStatus = ""; // 결재상태 $(function(){ @@ -293,6 +294,33 @@ $(function(){ } }); +// 결재상태에 따라 버튼 표시 제어 +function fn_controlButtons() { + if(g_apprStatus === "결재완료") { + // 결재완료된 경우 행추가, 저장 버튼 숨김 + $("#btnAddItem").hide(); + $("#btnSave").hide(); + + // 모든 입력 필드를 읽기 전용으로 변경 + $("input, textarea").attr("readonly", true); + $("input, textarea").css("background-color", "#f5f5f5"); + + // 삭제 버튼 숨김 + $(".btn-delete-row").hide(); + } else { + // 결재완료가 아닌 경우 버튼 표시 + $("#btnAddItem").show(); + $("#btnSave").show(); + + // 입력 필드 활성화 + $("input, textarea").attr("readonly", false); + $("input, textarea").css("background-color", ""); + + // 삭제 버튼 표시 + $(".btn-delete-row").show(); + } +} + // 금액 계산 function fn_calculateAmount(row) { var qty = row.find(".item-qty").val().replace(/,/g, "") || "0"; @@ -376,12 +404,17 @@ function fn_loadData() { g_exchangeRate = parseFloat(data.estimate.EXCHANGE_RATE || "1"); g_currencyName = data.estimate.CONTRACT_CURRENCY_NAME || "KRW"; - // 데이터 바인딩 - $("#executor").val(data.estimate.EXECUTOR || ""); - $("#recipient").val(data.estimate.RECIPIENT || ""); - $("#estimate_no").val(data.estimate.ESTIMATE_NO || ""); - $("#contact_person").val(data.estimate.CONTACT_PERSON || ""); - $("#greeting_text").val(data.estimate.GREETING_TEXT || "견적을 요청해 주셔서 대단히 감사합니다.\n하기와 같이 견적서를 제출합니다."); + // 결재상태 저장 + g_apprStatus = data.estimate.APPR_STATUS || "작성중"; + + // 데이터 바인딩 + $("#executor").val(data.estimate.EXECUTOR || ""); + $("#recipient").val(data.estimate.RECIPIENT || ""); + $("#estimate_no").val(data.estimate.ESTIMATE_NO || ""); + $("#contact_person").val(data.estimate.CONTACT_PERSON || ""); + $("#greeting_text").val(data.estimate.GREETING_TEXT || "견적을 요청해 주셔서 대단히 감사합니다.\n하기와 같이 견적서를 제출합니다."); + $("#manager_name").val(data.estimate.MANAGER_NAME || "영업부"); + $("#manager_contact").val(data.estimate.MANAGER_CONTACT || ""); // 품목 데이터 로드 if(data.items && data.items.length > 0) { @@ -423,18 +456,24 @@ function fn_loadData() { itemsHtml += ''; itemsHtml += ''; - $("#itemsTableBody").html(itemsHtml); - - // 합계 계산 - fn_calculateTotal(); - } + $("#itemsTableBody").html(itemsHtml); - // 비고 로드 - $("#note1").val(data.estimate.NOTE1 || "1. 견적유효기간: 일"); - $("#note2").val(data.estimate.NOTE2 || "2. 납품기간: 발주 후 1주 이내"); - $("#note3").val(data.estimate.NOTE3 || "3. VAT 별도"); - $("#note4").val(data.estimate.NOTE4 || "4. 결제 조건 : 기존 결제조건에 따름."); + // 비고 로드 (테이블 생성 직후) + $("#note_remarks").val(data.estimate.NOTE_REMARKS || ""); + + // 합계 계산 + fn_calculateTotal(); } + + // 하단 비고 로드 + $("#note1").val(data.estimate.NOTE1 || "1. 견적유효기간: 일"); + $("#note2").val(data.estimate.NOTE2 || "2. 납품기간: 발주 후 1주 이내"); + $("#note3").val(data.estimate.NOTE3 || "3. VAT 별도"); + $("#note4").val(data.estimate.NOTE4 || "4. 결제 조건 : 기존 결제조건에 따름."); + + // 결재상태에 따라 버튼 제어 + fn_controlButtons(); + } }, error: function() { Swal.fire("데이터를 불러오는데 실패했습니다."); @@ -461,33 +500,45 @@ function fn_loadTemplateData(templateObjId){ g_contractObjId = contractObjId; } - // 환율 정보 저장 - g_exchangeRate = parseFloat(template.EXCHANGE_RATE || template.exchange_rate || template.exchangeRate || "1"); - g_currencyName = template.CONTRACT_CURRENCY_NAME || template.contract_currency_name || template.contractCurrencyName || "KRW"; - - // 대문자/소문자 모두 지원 + // 환율 정보 저장 + g_exchangeRate = parseFloat(template.EXCHANGE_RATE || template.exchange_rate || template.exchangeRate || "1"); + g_currencyName = template.CONTRACT_CURRENCY_NAME || template.contract_currency_name || template.contractCurrencyName || "KRW"; + + // 결재상태 저장 + g_apprStatus = template.APPR_STATUS || template.appr_status || template.apprStatus || "작성중"; + + // 대문자/소문자 모두 지원 var executor = template.EXECUTOR || template.executor || ""; var recipient = template.RECIPIENT || template.recipient || ""; var estimateNo = template.ESTIMATE_NO || template.estimate_no || template.estimateNo || ""; var contactPerson = template.CONTACT_PERSON || template.contact_person || template.contactPerson || ""; var greetingText = template.GREETING_TEXT || template.greeting_text || template.greetingText || ""; - var note1 = template.NOTE1 || template.note1 || ""; - var note2 = template.NOTE2 || template.note2 || ""; - var note3 = template.NOTE3 || template.note3 || ""; - var note4 = template.NOTE4 || template.note4 || ""; - - // 기본 정보 채우기 - $("#executor").val(executor); - $("#recipient").val(recipient); - $("#estimate_no").val(estimateNo); - $("#contact_person").val(contactPerson); - $("#greeting_text").val(greetingText); - $("#note1").val(note1); - $("#note2").val(note2); - $("#note3").val(note3); - $("#note4").val(note4); - - // 품목 데이터 채우기 + var note1 = template.NOTE1 || template.note1 || ""; + var note2 = template.NOTE2 || template.note2 || ""; + var note3 = template.NOTE3 || template.note3 || ""; + var note4 = template.NOTE4 || template.note4 || ""; + var managerName = template.MANAGER_NAME || template.manager_name || template.managerName || "영업부"; + var managerContact = template.MANAGER_CONTACT || template.manager_contact || template.managerContact || ""; + + // 기본 정보 채우기 + $("#executor").val(executor); + $("#recipient").val(recipient); + $("#estimate_no").val(estimateNo); + $("#contact_person").val(contactPerson); + $("#greeting_text").val(greetingText); + $("#manager_name").val(managerName); + $("#manager_contact").val(managerContact); + + // 하단 비고 로드 + $("#note1").val(note1); + $("#note2").val(note2); + $("#note3").val(note3); + $("#note4").val(note4); + + // 테이블 내 비고는 나중에 설정 (textarea 생성 후) + var noteRemarks = template.NOTE_REMARKS || template.note_remarks || template.noteRemarks || ""; + + // 품목 데이터 채우기 if(data.items && data.items.length > 0){ $("#itemsTableBody").empty(); data.items.forEach(function(item, idx){ @@ -530,26 +581,32 @@ function fn_loadTemplateData(templateObjId){ $("#itemsTableBody").append(totalKRWRow); // 비고 행 추가 - var remarksRow = $(""); - remarksRow.append('' + - '
<비고>
' + - '' + - ''); - $("#itemsTableBody").append(remarksRow); - - // 합계 계산 - fn_calculateTotal(); - } - } else { - console.error("데이터 로드 실패:", data); - Swal.fire("데이터를 불러오는데 실패했습니다."); + var remarksRow = $(""); + remarksRow.append('' + + '
<비고>
' + + '' + + ''); + $("#itemsTableBody").append(remarksRow); + + // 테이블 내 비고 값 설정 (textarea 생성 직후) + $("#note_remarks").val(noteRemarks); + + // 합계 계산 + fn_calculateTotal(); + + // 결재상태에 따라 버튼 제어 + fn_controlButtons(); } - }, - error: function(xhr, status, error){ - console.error("AJAX 오류:", xhr, status, error); + } else { + console.error("데이터 로드 실패:", data); Swal.fire("데이터를 불러오는데 실패했습니다."); } - }); + }, + error: function(xhr, status, error){ + console.error("AJAX 오류:", xhr, status, error); + Swal.fire("데이터를 불러오는데 실패했습니다."); + } +}); } // 저장 @@ -596,6 +653,9 @@ function fn_save() { greeting_text: $("#greeting_text").val(), total_amount: totalAmount, // 합계 total_amount_krw: totalAmountKRW, // 원화환산 공급가액 + manager_name: $("#manager_name").val(), // 담당자 + manager_contact: $("#manager_contact").val(), // 연락처 + note_remarks: $("#note_remarks").val(), // 테이블 내 비고 note1: $("#note1").val(), note2: $("#note2").val(), note3: $("#note3").val(), @@ -665,10 +725,10 @@ function fn_save() {
㈊알피에스
RPS CO., LTD
대표이사이동준
-
- 담당자 : 영업부
- 연락처 : -
+
+ 담당자 :
+ 연락처 : +
diff --git a/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp b/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp index 9e0c037..ffb6178 100644 --- a/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/orderMgmtList.jsp @@ -27,6 +27,11 @@ $(document).ready(function(){ $('.select2').select2(); + // 품번/품명 Select2 AJAX 초기화 (common.js의 새 함수 사용) + initPartSelect2Ajax("#search_partNo", "#search_partName", "#search_partObjId", { + debug: false // 디버깅 모드 비활성화 + }); + $("#btnSearch").click(function(){ $("#page").val("1"); fn_search(); @@ -599,18 +604,23 @@ function openProjectFormPopUp(objId){ - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/WebContent/js/common.js b/WebContent/js/common.js index 52d2fa6..ca10246 100644 --- a/WebContent/js/common.js +++ b/WebContent/js/common.js @@ -3255,4 +3255,182 @@ function fnc_tabulCallbackFnc(objid, docType, columnField, fileCnt){ }); } -//tabulator용 Function 종료 \ No newline at end of file +//tabulator용 Function 종료 + +/** + * 품번/품명 Select2 AJAX 검색 함수 (견적 목록 전용) + * @param {string} partNoSelectId - 품번 셀렉트 박스 ID (예: "#search_partNo") + * @param {string} partNameSelectId - 품명 셀렉트 박스 ID (예: "#search_partName") + * @param {string} partObjIdInputId - 품목 OBJID hidden 필드 ID (예: "#search_partObjId") + * @param {object} options - 추가 옵션 (placeholder, minimumInputLength 등) + */ +function initPartSelect2Ajax(partNoSelectId, partNameSelectId, partObjIdInputId, options) { + options = options || {}; + var partNoPlaceholder = options.partNoPlaceholder || "품번 입력하여 검색..."; + var partNamePlaceholder = options.partNamePlaceholder || "품명 입력하여 검색..."; + var minimumInputLength = options.minimumInputLength || 1; + var searchUrl = options.searchUrl || '/contractMgmt/searchPartList.do'; + var debug = options.debug || false; + + // 품번 Select2 AJAX 설정 + $(partNoSelectId).select2({ + placeholder: partNoPlaceholder, + allowClear: true, + width: '100%', + minimumInputLength: minimumInputLength, + language: { + inputTooShort: function() { + return "최소 " + minimumInputLength + "글자 이상 입력하세요"; + }, + searching: function() { + return "검색 중..."; + }, + noResults: function() { + return "검색 결과가 없습니다"; + } + }, + ajax: { + url: searchUrl, + dataType: 'json', + type: 'POST', + contentType: 'application/x-www-form-urlencoded; charset=UTF-8', + delay: 250, + data: function(params) { + return { + searchTerm: params.term + }; + }, + processResults: function(data) { + var results = $.map(data, function(item) { + var objId = item.OBJID || item.objid || item.objId; + var partNo = item.PART_NO || item.part_no || item.partNo; + var partName = item.PART_NAME || item.part_name || item.partName; + + return { + id: partNo, + text: partNo, + objId: objId, + partName: partName, + partNo: partNo + }; + }); + + return { + results: results + }; + }, + cache: true + } + }); + + // 품명 Select2 AJAX 설정 + $(partNameSelectId).select2({ + placeholder: partNamePlaceholder, + allowClear: true, + width: '100%', + minimumInputLength: minimumInputLength, + language: { + inputTooShort: function() { + return "최소 " + minimumInputLength + "글자 이상 입력하세요"; + }, + searching: function() { + return "검색 중..."; + }, + noResults: function() { + return "검색 결과가 없습니다"; + } + }, + ajax: { + url: searchUrl, + dataType: 'json', + type: 'POST', + contentType: 'application/x-www-form-urlencoded; charset=UTF-8', + delay: 250, + data: function(params) { + return { + searchTerm: params.term + }; + }, + processResults: function(data) { + var results = $.map(data, function(item) { + var objId = item.OBJID || item.objid || item.objId; + var partNo = item.PART_NO || item.part_no || item.partNo; + var partName = item.PART_NAME || item.part_name || item.partName; + + return { + id: partName, + text: partName, + objId: objId, + partName: partName, + partNo: partNo + }; + }); + + return { + results: results + }; + }, + cache: true + } + }); + + // 품번 변경 이벤트 핸들러 + var partNoChangeHandler = function() { + var selectedData = $(this).select2('data')[0]; + if(debug) console.log("품번 변경됨:", selectedData); + + if(selectedData && selectedData.objId) { + if(debug) console.log("품목 OBJID 설정:", selectedData.objId); + $(partObjIdInputId).val(selectedData.objId); + + // 품명 셀렉트박스도 동기화 + var $partNameSelect = $(partNameSelectId); + $partNameSelect.off('change'); + if($partNameSelect.find("option[value='" + selectedData.partName + "']").length === 0) { + var newOption = new Option(selectedData.partName, selectedData.partName, true, true); + $partNameSelect.append(newOption); + } else { + $partNameSelect.val(selectedData.partName); + } + $partNameSelect.trigger('change.select2'); + + setTimeout(function() { + $partNameSelect.on('change', partNameChangeHandler); + }, 100); + } else { + $(partObjIdInputId).val(""); + } + }; + + // 품명 변경 이벤트 핸들러 + var partNameChangeHandler = function() { + var selectedData = $(this).select2('data')[0]; + if(debug) console.log("품명 변경됨:", selectedData); + + if(selectedData && selectedData.objId) { + if(debug) console.log("품목 OBJID 설정:", selectedData.objId); + $(partObjIdInputId).val(selectedData.objId); + + // 품번 셀렉트박스도 동기화 + var $partNoSelect = $(partNoSelectId); + $partNoSelect.off('change'); + if($partNoSelect.find("option[value='" + selectedData.partNo + "']").length === 0) { + var newOption = new Option(selectedData.partNo, selectedData.partNo, true, true); + $partNoSelect.append(newOption); + } else { + $partNoSelect.val(selectedData.partNo); + } + $partNoSelect.trigger('change.select2'); + + setTimeout(function() { + $partNoSelect.on('change', partNoChangeHandler); + }, 100); + } else { + $(partObjIdInputId).val(""); + } + }; + + // 이벤트 연결 + $(partNoSelectId).on('change', partNoChangeHandler); + $(partNameSelectId).on('change', partNameChangeHandler); +} \ No newline at end of file diff --git a/database/add_manager_info_to_estimate_template.sql b/database/add_manager_info_to_estimate_template.sql new file mode 100644 index 0000000..1632c2f --- /dev/null +++ b/database/add_manager_info_to_estimate_template.sql @@ -0,0 +1,16 @@ +-- ESTIMATE_TEMPLATE 테이블에 담당자 정보 및 테이블 내 비고 컬럼 추가 + +ALTER TABLE ESTIMATE_TEMPLATE +ADD COLUMN IF NOT EXISTS MANAGER_NAME VARCHAR(100); + +ALTER TABLE ESTIMATE_TEMPLATE +ADD COLUMN IF NOT EXISTS MANAGER_CONTACT VARCHAR(100); + +ALTER TABLE ESTIMATE_TEMPLATE +ADD COLUMN IF NOT EXISTS NOTE_REMARKS TEXT; + +-- 컬럼 설명 추가 +COMMENT ON COLUMN ESTIMATE_TEMPLATE.MANAGER_NAME IS '담당자 이름'; +COMMENT ON COLUMN ESTIMATE_TEMPLATE.MANAGER_CONTACT IS '담당자 연락처'; +COMMENT ON COLUMN ESTIMATE_TEMPLATE.NOTE_REMARKS IS '테이블 내 비고 (품목 하단)'; + diff --git a/database/add_part_objid_to_project_mgmt.sql b/database/add_part_objid_to_project_mgmt.sql new file mode 100644 index 0000000..c24d7f8 --- /dev/null +++ b/database/add_part_objid_to_project_mgmt.sql @@ -0,0 +1,27 @@ +-- PROJECT_MGMT 테이블에 품목 관련 컬럼 추가 +-- 품목별 프로젝트 생성을 위한 컬럼들 + +ALTER TABLE PROJECT_MGMT +ADD COLUMN IF NOT EXISTS PART_OBJID VARCHAR(50); + +ALTER TABLE PROJECT_MGMT +ADD COLUMN IF NOT EXISTS PART_NO VARCHAR(100); + +ALTER TABLE PROJECT_MGMT +ADD COLUMN IF NOT EXISTS PART_NAME VARCHAR(200); + +ALTER TABLE PROJECT_MGMT +ADD COLUMN IF NOT EXISTS QUANTITY VARCHAR(50); + +-- 컬럼 설명 추가 +COMMENT ON COLUMN PROJECT_MGMT.PART_OBJID IS '품목 OBJID (품목별 프로젝트 생성 시 사용)'; +COMMENT ON COLUMN PROJECT_MGMT.PART_NO IS '품번'; +COMMENT ON COLUMN PROJECT_MGMT.PART_NAME IS '품명'; +COMMENT ON COLUMN PROJECT_MGMT.QUANTITY IS '수주수량'; + +-- 기존 인덱스 확인 후 추가 (성능 향상) +CREATE INDEX IF NOT EXISTS idx_project_mgmt_contract_part +ON PROJECT_MGMT(CONTRACT_OBJID, PART_OBJID); + +COMMENT ON INDEX idx_project_mgmt_contract_part IS '계약-품목별 프로젝트 조회 성능 향상'; + diff --git a/src/com/pms/common/utils/MailUtil.java b/src/com/pms/common/utils/MailUtil.java index 0720cfe..ac05603 100644 --- a/src/com/pms/common/utils/MailUtil.java +++ b/src/com/pms/common/utils/MailUtil.java @@ -691,6 +691,7 @@ public class MailUtil { //◆◆◆ 3. db log & send mail ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ SqlSession sqlSession = null; + boolean mailSendSuccess = false; // 메일 발송 성공 여부 Map paramMap = new HashMap(); try{ @@ -715,6 +716,7 @@ public class MailUtil { //◆◆◆ send mail ◆◆◆ Transport.send(message); + mailSendSuccess = true; // 메일 발송 성공 if(Constants.Mail.dbLogWrite){ System.out.println("메일 발송후 paramMap >> "+paramMap); @@ -722,6 +724,7 @@ public class MailUtil { } }catch(Exception sqle){ + mailSendSuccess = false; // 메일 발송 실패 if(Constants.Mail.dbLogWrite){ paramMap.put("errorLog", sqle.getMessage()); System.out.println("메일 발송 오류 paramMap >> "+paramMap); @@ -735,7 +738,7 @@ public class MailUtil { } } - return true; + return mailSendSuccess; // 실제 발송 성공 여부 반환 }catch(Exception e) { e.printStackTrace(); return false; diff --git a/src/com/pms/mapper/project.xml b/src/com/pms/mapper/project.xml index 65bda68..439bf4d 100644 --- a/src/com/pms/mapper/project.xml +++ b/src/com/pms/mapper/project.xml @@ -7362,16 +7362,20 @@ SELECT ,EST_USER_ID ,EST_COMP_DATE ,EST_RESULT_CD - ,AREA_CD - ,MECHANICAL_TYPE - ,OVERHAUL_ORDER - ,IS_TEMP - ) + ,AREA_CD + ,MECHANICAL_TYPE + ,OVERHAUL_ORDER + ,IS_TEMP + ,PART_OBJID + ,PART_NO + ,PART_NAME + ,QUANTITY + ) ( SELECT #{OBJID} - ,#{objId} + ,#{objId} ,CATEGORY_CD ,CUSTOMER_OBJID ,PRODUCT @@ -7390,29 +7394,71 @@ SELECT ,CHG_USER_ID ,PLAN_DATE ,COMPLETE_DATE - ,RESULT_CD - - - ,#{overhaul_project_no} - - - ,MECHANICAL_TYPE || '-' || - - (SELECT CASE - WHEN PROJECT_NO ~ '[-\s][0-9]+$' - THEN REGEXP_REPLACE(PROJECT_NO, '.*[-\s]([0-9]+)$', '\1')::integer+1 - ELSE NULL - END AS extracted_number - FROM PROJECT_MGMT - WHERE PROJECT_NO NOT LIKE '%\_%' ESCAPE '\' - ORDER BY extracted_number DESC NULLS LAST - LIMIT 1) - - - - + ,RESULT_CD + + + + ,( + SELECT + -- 주문유형 코드 (CATEGORY_CD를 영문 약어로 매핑) + CASE CODE_NAME(CATEGORY_CD) + WHEN '오버홀' THEN 'O' + WHEN '개조' THEN 'M' + WHEN '개발' THEN 'D' + WHEN '견적' THEN 'Q' + WHEN '수리' THEN 'R' + WHEN '판매' THEN 'S' + ELSE 'T' + END || '-' || + -- 제품구분 코드 (PRODUCT의 CODE_NAME에서 슬래시 제거) + REPLACE(CODE_NAME(PRODUCT), '/', '') || '-' || + -- 날짜 (YYMMDD) + TO_CHAR(CURRENT_DATE, 'YYMMDD') || '-' || + -- 순번 (001, 002, ...) + LPAD( + COALESCE( + ( + SELECT MAX(SUBSTRING(PROJECT_NO FROM '\d{3}$')::INTEGER) + 1 + FROM PROJECT_MGMT + WHERE PROJECT_NO LIKE + CASE CODE_NAME(CATEGORY_CD) + WHEN '오버홀' THEN 'O' + WHEN '개조' THEN 'M' + WHEN '개발' THEN 'D' + WHEN '견적' THEN 'Q' + WHEN '수리' THEN 'R' + WHEN '판매' THEN 'S' + ELSE 'T' + END || '-' || + REPLACE(CODE_NAME(PRODUCT), '/', '') || '-' || + TO_CHAR(CURRENT_DATE, 'YYMMDD') || '-%' + ), + 1 + )::TEXT, + 3, + '0' + ) + FROM CONTRACT_MGMT + WHERE OBJID = #{objId} + ) ,PM_USER_ID ,#{contract_price} ,#{contract_price_currency} @@ -7437,12 +7483,16 @@ SELECT ,EST_USER_ID ,EST_COMP_DATE ,EST_RESULT_CD - ,AREA_CD - ,MECHANICAL_TYPE - ,#{overhaul_order} - ,#{is_temp} - FROM CONTRACT_MGMT - WHERE OBJID=#{objId} + ,AREA_CD + ,MECHANICAL_TYPE + ,#{overhaul_order} + ,#{is_temp} + ,#{part_objid} + ,#{part_no} + ,#{part_name} + ,#{quantity} + FROM CONTRACT_MGMT + WHERE OBJID=#{objId} ) @@ -7549,7 +7599,12 @@ SELECT ,REQ_DEL_DATE = #{req_del_date} ,CONTRACT_COMPANY = #{contract_company} ,MANUFACTURE_PLANT = #{manufacture_plant} + ,PART_OBJID = #{part_objid} + ,PART_NO = #{part_no} + ,PART_NAME = #{part_name} + ,QUANTITY = #{quantity} WHERE CONTRACT_OBJID = #{objId} + AND PART_OBJID = #{part_objid} diff --git a/src/com/pms/salesmgmt/mapper/contractMgmt.xml b/src/com/pms/salesmgmt/mapper/contractMgmt.xml index 7e796db..844c376 100644 --- a/src/com/pms/salesmgmt/mapper/contractMgmt.xml +++ b/src/com/pms/salesmgmt/mapper/contractMgmt.xml @@ -463,8 +463,9 @@ ,TO_CHAR(REGDATE,'YYYY-MM-DD') AS REG_DATE ,WRITER ,(SELECT USER_NAME FROM USER_INFO AS O WHERE O.USER_ID = T.WRITER ) AS WRITER_NAME - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE='contractMgmt01' AND UPPER(STATUS) = 'ACTIVE') AS CU01_CNT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE='contractMgmt02' AND UPPER(STATUS) = 'ACTIVE') AS CU02_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE='ORDER_DOC' AND UPPER(STATUS) = 'ACTIVE') AS CU01_CNT + ,(CASE WHEN (RESULT_CD is null or RESULT_CD ='') and (SPEC_RESULT_CD is null or RESULT_CD ='') and (EST_RESULT_CD is null or RESULT_CD ='') then '0' ELSE 1 END @@ -477,6 +478,7 @@ ,CODE_NAME(CONTRACT_COMPANY) AS CONTRACT_COMPANY_NAME ,CONTRACT_DATE ,PO_NO + ,ORDER_DATE ,MANUFACTURE_PLANT ,CODE_NAME(MANUFACTURE_PLANT) AS MANUFACTURE_PLANT_NAME ,CONTRACT_RESULT @@ -753,12 +755,15 @@ AND PAID_TYPE = #{paid_type} - - AND UPPER(PART_NO) LIKE UPPER('%${search_partNo}%') - - - - AND UPPER(PART_NAME) LIKE UPPER('%${search_partName}%') + + + AND EXISTS ( + SELECT 1 + FROM CONTRACT_ITEM CI + WHERE CI.CONTRACT_OBJID = T.OBJID + AND CI.STATUS = 'ACTIVE' + AND CI.PART_OBJID = #{search_partObjId} + ) @@ -779,9 +784,9 @@ AND TO_DATE(DUE_DATE,'YYYY-MM-DD') TO_DATE(#{due_end_date}, 'YYYY-MM-DD') ORDER BY REGDATE DESC - - - + + + + + SELECT - OBJID AS "OBJID", - CONTRACT_OBJID AS "CONTRACT_OBJID", - TEMPLATE_TYPE AS "TEMPLATE_TYPE", + ET.OBJID AS "OBJID", + ET.CONTRACT_OBJID AS "CONTRACT_OBJID", + ET.TEMPLATE_TYPE AS "TEMPLATE_TYPE", CASE - WHEN TEMPLATE_TYPE = '1' THEN '일반 견적서' - WHEN TEMPLATE_TYPE = '2' THEN '장비 견적서' - ELSE TEMPLATE_TYPE + WHEN ET.TEMPLATE_TYPE = '1' THEN '일반 견적서' + WHEN ET.TEMPLATE_TYPE = '2' THEN '장비 견적서' + ELSE ET.TEMPLATE_TYPE END AS "TEMPLATE_TYPE_NAME", - ESTIMATE_NO AS "ESTIMATE_NO", - WRITER AS "WRITER", - TO_CHAR(REGDATE, 'YYYY-MM-DD HH24:MI') AS "REGDATE", - CHG_USER_ID AS "CHG_USER_ID", - TO_CHAR(CHGDATE, 'YYYY-MM-DD HH24:MI') AS "CHGDATE", - ROW_NUMBER() OVER (PARTITION BY TEMPLATE_TYPE ORDER BY REGDATE) AS "REVISION" + ET.ESTIMATE_NO AS "ESTIMATE_NO", + ET.WRITER AS "WRITER", + TO_CHAR(ET.REGDATE, 'YYYY-MM-DD HH24:MI') AS "REGDATE", + ET.CHG_USER_ID AS "CHG_USER_ID", + TO_CHAR(ET.CHGDATE, 'YYYY-MM-DD HH24:MI') AS "CHGDATE", + ROW_NUMBER() OVER (PARTITION BY ET.TEMPLATE_TYPE ORDER BY ET.REGDATE) AS "REVISION", + COALESCE( + (SELECT CASE + WHEN A.STATUS = 'complete' THEN '결재완료' + WHEN A.STATUS = 'cancel' THEN '취소' + WHEN A.STATUS = 'reject' THEN '반려' + WHEN A.STATUS = 'inProcess' THEN '결재중' + ELSE '작성중' + END + FROM APPROVAL A + WHERE A.TARGET_OBJID::VARCHAR = ET.OBJID + AND A.TARGET_TYPE = 'CONTRACT_ESTIMATE' + ORDER BY A.REGDATE DESC + LIMIT 1), + '작성중' + ) AS "APPR_STATUS" FROM - ESTIMATE_TEMPLATE + ESTIMATE_TEMPLATE ET WHERE - CONTRACT_OBJID = #{objId} - ORDER BY TEMPLATE_TYPE, REGDATE DESC + ET.CONTRACT_OBJID = #{objId} + ORDER BY ET.TEMPLATE_TYPE, ET.REGDATE DESC @@ -3848,24 +3883,42 @@ ORDER BY ASM.SUPPLY_NAME ET.NOTE2, ET.NOTE3, ET.NOTE4, + ET.NOTE_REMARKS, ET.TOTAL_AMOUNT, ET.TOTAL_AMOUNT_KRW, + ET.MANAGER_NAME, + ET.MANAGER_CONTACT, ET.WRITER, ET.REGDATE, ET.CHG_USER_ID, ET.CHGDATE, CM.EXCHANGE_RATE, - CODE_NAME(CM.CONTRACT_CURRENCY) AS CONTRACT_CURRENCY_NAME + CODE_NAME(CM.CONTRACT_CURRENCY) AS CONTRACT_CURRENCY_NAME, + COALESCE( + (SELECT CASE + WHEN A.STATUS = 'complete' THEN '결재완료' + WHEN A.STATUS = 'cancel' THEN '취소' + WHEN A.STATUS = 'reject' THEN '반려' + WHEN A.STATUS = 'inProcess' THEN '결재중' + ELSE '작성중' + END + FROM APPROVAL A + WHERE A.TARGET_OBJID::VARCHAR = ET.OBJID + AND A.TARGET_TYPE = 'CONTRACT_ESTIMATE' + ORDER BY A.REGDATE DESC + LIMIT 1), + '작성중' + ) AS APPR_STATUS FROM ESTIMATE_TEMPLATE ET LEFT JOIN CONTRACT_MGMT CM ON ET.CONTRACT_OBJID = CM.OBJID WHERE ET.CONTRACT_OBJID = #{objId} - - AND ET.TEMPLATE_TYPE = #{template_type} - - ORDER BY ET.REGDATE DESC - LIMIT 1 + + AND ET.TEMPLATE_TYPE = #{template_type} + + ORDER BY ET.REGDATE DESC + LIMIT 1 @@ -3886,14 +3939,32 @@ ORDER BY ASM.SUPPLY_NAME ET.NOTE2, ET.NOTE3, ET.NOTE4, + ET.NOTE_REMARKS, ET.TOTAL_AMOUNT, ET.TOTAL_AMOUNT_KRW, + ET.MANAGER_NAME, + ET.MANAGER_CONTACT, ET.WRITER, TO_CHAR(ET.REGDATE, 'YYYY-MM-DD HH24:MI') AS REGDATE, ET.CHG_USER_ID, TO_CHAR(ET.CHGDATE, 'YYYY-MM-DD HH24:MI') AS CHGDATE, CM.EXCHANGE_RATE, - CODE_NAME(CM.CONTRACT_CURRENCY) AS CONTRACT_CURRENCY_NAME + CODE_NAME(CM.CONTRACT_CURRENCY) AS CONTRACT_CURRENCY_NAME, + COALESCE( + (SELECT CASE + WHEN A.STATUS = 'complete' THEN '결재완료' + WHEN A.STATUS = 'cancel' THEN '취소' + WHEN A.STATUS = 'reject' THEN '반려' + WHEN A.STATUS = 'inProcess' THEN '결재중' + ELSE '작성중' + END + FROM APPROVAL A + WHERE A.TARGET_OBJID::VARCHAR = ET.OBJID + AND A.TARGET_TYPE = 'CONTRACT_ESTIMATE' + ORDER BY A.REGDATE DESC + LIMIT 1), + '작성중' + ) AS APPR_STATUS FROM ESTIMATE_TEMPLATE ET LEFT JOIN CONTRACT_MGMT CM ON ET.CONTRACT_OBJID = CM.OBJID @@ -3963,39 +4034,45 @@ ORDER BY ASM.SUPPLY_NAME MODEL_NAME, MODEL_CODE, EXECUTOR_DATE, - NOTE1, - NOTE2, - NOTE3, - NOTE4, - TOTAL_AMOUNT, - TOTAL_AMOUNT_KRW, - WRITER, - REGDATE, - CHG_USER_ID, - CHGDATE - ) VALUES ( - #{template_objid}, - #{objId}, - #{template_type}, - #{executor}, - #{recipient}, - #{estimate_no}, - #{contact_person}, - #{greeting_text}, - #{model_name}, - #{model_code}, - #{executor_date}, - #{note1}, - #{note2}, - #{note3}, - #{note4}, - #{total_amount}, - #{total_amount_krw}, - #{writer}, - NOW(), - #{chg_user_id}, - NOW() - ) + NOTE1, + NOTE2, + NOTE3, + NOTE4, + NOTE_REMARKS, + TOTAL_AMOUNT, + TOTAL_AMOUNT_KRW, + MANAGER_NAME, + MANAGER_CONTACT, + WRITER, + REGDATE, + CHG_USER_ID, + CHGDATE +) VALUES ( + #{template_objid}, + #{objId}, + #{template_type}, + #{executor}, + #{recipient}, + #{estimate_no}, + #{contact_person}, + #{greeting_text}, + #{model_name}, + #{model_code}, + #{executor_date}, + #{note1}, + #{note2}, + #{note3}, + #{note4}, + #{note_remarks}, + #{total_amount}, + #{total_amount_krw}, + #{manager_name}, + #{manager_contact}, + #{writer}, + NOW(), + #{chg_user_id}, + NOW() +) @@ -4010,16 +4087,19 @@ ORDER BY ASM.SUPPLY_NAME MODEL_NAME = #{model_name}, MODEL_CODE = #{model_code}, EXECUTOR_DATE = #{executor_date}, - NOTE1 = #{note1}, - NOTE2 = #{note2}, - NOTE3 = #{note3}, - NOTE4 = #{note4}, - TOTAL_AMOUNT = #{total_amount}, - TOTAL_AMOUNT_KRW = #{total_amount_krw}, - CHG_USER_ID = #{chg_user_id}, - CHGDATE = NOW() - WHERE - OBJID = #{template_objid} + NOTE1 = #{note1}, + NOTE2 = #{note2}, + NOTE3 = #{note3}, + NOTE4 = #{note4}, + NOTE_REMARKS = #{note_remarks}, + TOTAL_AMOUNT = #{total_amount}, + TOTAL_AMOUNT_KRW = #{total_amount_krw}, + MANAGER_NAME = #{manager_name}, + MANAGER_CONTACT = #{manager_contact}, + CHG_USER_ID = #{chg_user_id}, + CHGDATE = NOW() +WHERE + OBJID = #{template_objid} @@ -4095,8 +4175,11 @@ ORDER BY ASM.SUPPLY_NAME ET.NOTE2 AS "NOTE2", ET.NOTE3 AS "NOTE3", ET.NOTE4 AS "NOTE4", + ET.NOTE_REMARKS AS "NOTE_REMARKS", ET.TOTAL_AMOUNT AS "TOTAL_AMOUNT", ET.TOTAL_AMOUNT_KRW AS "TOTAL_AMOUNT_KRW", + ET.MANAGER_NAME AS "MANAGER_NAME", + ET.MANAGER_CONTACT AS "MANAGER_CONTACT", ET.WRITER AS "WRITER", TO_CHAR(ET.REGDATE, 'YYYY-MM-DD HH24:MI') AS "REGDATE", ET.CHG_USER_ID AS "CHG_USER_ID", @@ -4104,11 +4187,11 @@ ORDER BY ASM.SUPPLY_NAME ET.CATEGORIES_JSON AS "CATEGORIES_JSON", CM.EXCHANGE_RATE AS "EXCHANGE_RATE", CODE_NAME(CM.CONTRACT_CURRENCY) AS "CONTRACT_CURRENCY_NAME" - FROM - ESTIMATE_TEMPLATE ET - LEFT JOIN CONTRACT_MGMT CM ON ET.CONTRACT_OBJID = CM.OBJID - WHERE - ET.CONTRACT_OBJID = #{objId} +FROM + ESTIMATE_TEMPLATE ET +LEFT JOIN CONTRACT_MGMT CM ON ET.CONTRACT_OBJID = CM.OBJID +WHERE + ET.CONTRACT_OBJID = #{objId} ORDER BY ET.TEMPLATE_TYPE, ET.REGDATE DESC diff --git a/src/com/pms/salesmgmt/service/ContractMgmtService.java b/src/com/pms/salesmgmt/service/ContractMgmtService.java index 323cb51..820df4c 100644 --- a/src/com/pms/salesmgmt/service/ContractMgmtService.java +++ b/src/com/pms/salesmgmt/service/ContractMgmtService.java @@ -1621,18 +1621,24 @@ private String makeEstimateMailContents(Map contractInfo, Map estimateTemplate, contents.append(""); contents.append(""); contents.append(""); @@ -1656,14 +1662,77 @@ private String makeEstimateMailContents(Map contractInfo, Map estimateTemplate, String executorDate = CommonUtils.checkNull(estimateTemplate.get("executor_date")); if("".equals(executorDate)) executorDate = CommonUtils.checkNull(estimateTemplate.get("EXECUTOR_DATE")); - // 기본 정보 테이블 + // 담당자 정보 + String managerName = CommonUtils.checkNull(estimateTemplate.get("manager_name")); + if("".equals(managerName)) managerName = CommonUtils.checkNull(estimateTemplate.get("MANAGER_NAME")); + if("".equals(managerName)) managerName = "영업부"; + + String managerContact = CommonUtils.checkNull(estimateTemplate.get("manager_contact")); + if("".equals(managerContact)) managerContact = CommonUtils.checkNull(estimateTemplate.get("MANAGER_CONTACT")); + + // 헤더 섹션 (왼쪽: 기본정보, 오른쪽: 회사정보) + contents.append("
"); + + // 왼쪽: 기본 정보 테이블 + contents.append("
"); contents.append(""); contents.append(""); contents.append(""); contents.append(""); contents.append(""); - contents.append(""); contents.append("
수신처" + recipient + "
수신인" + contactPerson + "
견적번호" + estimateNo + "
영업번호" + CommonUtils.checkNull(contractInfo.get("contract_no")) + "
발행일" + executorDate + "
"); + contents.append("
"); + + // 오른쪽: 회사 정보 + contents.append("
"); + contents.append("
"); + + // 회사 도장 이미지 경로 + String projectRoot = System.getProperty("user.dir"); + String companyStampPath = projectRoot + "/WebContent/images/company_stamp.png"; + + // Docker 환경인 경우 다른 경로 시도 + File stampFile = new File(companyStampPath); + if(!stampFile.exists()) { + companyStampPath = "/usr/local/tomcat/webapps/ROOT/images/company_stamp.png"; + stampFile = new File(companyStampPath); + if(!stampFile.exists()) { + companyStampPath = ""; + } + } + + String stampBase64 = !"".equals(companyStampPath) ? encodeImageToBase64(companyStampPath) : ""; + + if(!"".equals(stampBase64)) { + // 이미지가 있으면 Base64로 인코딩된 이미지만 표시 + contents.append("회사 도장"); + } else { + // 이미지가 없으면 텍스트로 표시 + contents.append("
"); + contents.append("
"); + contents.append("(주)알피에스
대표이사
이 종 현"); + contents.append("
"); + contents.append("
"); + contents.append("
RPS CO., LTD
"); + contents.append("
대 표 이 사 이 종 현
"); + contents.append("
"); + contents.append("
대전광역시 유성구 국제과학10로 8
"); + contents.append("
TEL:(042)602-3300 FAX:(042)672-3399
"); + contents.append("
"); + } + + // 담당자 정보는 항상 표시 + contents.append("
"); + contents.append("
담당자 : " + managerName + "
"); + if(!"".equals(managerContact)) { + contents.append("
연락처 : " + managerContact + "
"); + } + contents.append("
"); + + contents.append("
"); // company-info 닫기 + contents.append("
"); // header-right 닫기 + + contents.append("
"); // header-section 닫기 // 견적 품목 if(estimateItems != null && !estimateItems.isEmpty()){ @@ -1704,17 +1773,51 @@ private String makeEstimateMailContents(Map contractInfo, Map estimateTemplate, contents.append(""); } - // 합계 + // 계 (총 합계) + String totalAmountStr = CommonUtils.checkNull(estimateTemplate.get("total_amount")); + if("".equals(totalAmountStr)) totalAmountStr = CommonUtils.checkNull(estimateTemplate.get("TOTAL_AMOUNT")); + + // DB에 저장된 합계가 없으면 계산한 값 사용 + if("".equals(totalAmountStr)){ + totalAmountStr = String.format("%,d", totalAmount); + } + contents.append(""); - contents.append("합계"); - contents.append("₩" + String.format("%,d", totalAmount) + ""); + contents.append("계"); + contents.append("" + totalAmountStr + ""); contents.append(""); contents.append(""); + + // 원화환산 공급가액 + String totalAmountKrw = CommonUtils.checkNull(estimateTemplate.get("total_amount_krw")); + if("".equals(totalAmountKrw)) totalAmountKrw = CommonUtils.checkNull(estimateTemplate.get("TOTAL_AMOUNT_KRW")); + + if(!"".equals(totalAmountKrw)){ + contents.append(""); + contents.append("원화환산 공급가액 (KRW)"); + contents.append("" + totalAmountKrw + ""); + contents.append(""); + contents.append(""); + } + + // 테이블 내 비고 + String noteRemarks = CommonUtils.checkNull(estimateTemplate.get("note_remarks")); + if("".equals(noteRemarks)) noteRemarks = CommonUtils.checkNull(estimateTemplate.get("NOTE_REMARKS")); + + if(!"".equals(noteRemarks)){ + contents.append(""); + contents.append(""); + contents.append("
<비고>
"); + contents.append("
" + noteRemarks + "
"); + contents.append(""); + contents.append(""); + } + contents.append(""); contents.append(""); } - // 비고 (대소문자 모두 체크) + // 참조사항 (NOTE1~4) String note1 = CommonUtils.checkNull(estimateTemplate.get("note1")); if("".equals(note1)) note1 = CommonUtils.checkNull(estimateTemplate.get("NOTE1")); @@ -1729,11 +1832,23 @@ private String makeEstimateMailContents(Map contractInfo, Map estimateTemplate, if(!"".equals(note1) || !"".equals(note2) || !"".equals(note3) || !"".equals(note4)){ contents.append("
"); - contents.append("

※ 비고

"); - if(!"".equals(note1)) contents.append("
1. " + note1 + "
"); - if(!"".equals(note2)) contents.append("
2. " + note2 + "
"); - if(!"".equals(note3)) contents.append("
3. " + note3 + "
"); - if(!"".equals(note4)) contents.append("
4. " + note4 + "
"); + contents.append("

※ 참조사항

"); + int noteNum = 1; + if(!"".equals(note1)) { + contents.append("
" + noteNum + ". " + note1 + "
"); + noteNum++; + } + if(!"".equals(note2)) { + contents.append("
" + noteNum + ". " + note2 + "
"); + noteNum++; + } + if(!"".equals(note3)) { + contents.append("
" + noteNum + ". " + note3 + "
"); + noteNum++; + } + if(!"".equals(note4)) { + contents.append("
" + noteNum + ". " + note4 + "
"); + } contents.append("
"); } @@ -1744,6 +1859,42 @@ private String makeEstimateMailContents(Map contractInfo, Map estimateTemplate, return contents.toString(); } +/** + * 이미지 파일을 Base64로 인코딩 + * @param imagePath 이미지 파일 경로 + * @return Base64 인코딩된 문자열 (data:image/png;base64,...) + */ +private String encodeImageToBase64(String imagePath) { + try { + File imageFile = new File(imagePath); + if(!imageFile.exists()) { + return ""; + } + + java.io.FileInputStream fis = new java.io.FileInputStream(imageFile); + byte[] imageBytes = new byte[(int) imageFile.length()]; + fis.read(imageBytes); + fis.close(); + + // Apache Commons Codec 사용 (Java 7 호환) + String base64 = org.apache.commons.codec.binary.Base64.encodeBase64String(imageBytes); + + // 파일 확장자로 MIME 타입 결정 + String mimeType = "image/png"; + if(imagePath.toLowerCase().endsWith(".jpg") || imagePath.toLowerCase().endsWith(".jpeg")) { + mimeType = "image/jpeg"; + } else if(imagePath.toLowerCase().endsWith(".gif")) { + mimeType = "image/gif"; + } + + return "data:" + mimeType + ";base64," + base64; + } catch(Exception e) { + System.out.println("이미지 Base64 인코딩 실패: " + e.getMessage()); + e.printStackTrace(); + return ""; + } +} + /** * 영업정보 조회 (수주등록용) * @param contractObjId @@ -1907,51 +2058,96 @@ private String makeEstimateMailContents(Map contractInfo, Map estimateTemplate, //paramMap.put("contract_price_currency", contract_price_currency/project_cnt + ""); //paramMap.put("contract_price", contract_price/project_cnt + ""); - if("0000964".equals(result_cd) || "0000968".equals(result_cd)){ - resultList = sqlSession.selectOne("contractMgmt.getProjectListBycontractObjid", paramMap); - System.out.println("resultList:::"+resultList); - //resultList = sqlSession.selectOne("contractMgmt.getProjectCnt", paramMap); - if(null==resultList){ - -// for (int i=0; i contractItems = getContractItems(paramMap); + + if(contractItems != null && !contractItems.isEmpty()) { + System.out.println("품목 개수: " + contractItems.size() + "개 - 품목별 프로젝트 생성 시작"); + + for(Map item : contractItems) { + // 품목별 프로젝트 존재 여부 확인 + Map projectCheckParam = new HashMap(); + projectCheckParam.put("contractObjId", contract_objid); + projectCheckParam.put("part_objid", item.get("PART_OBJID")); + + resultList = sqlSession.selectOne("contractMgmt.getProjectListByContractAndPartObjid", projectCheckParam); + + if(null == resultList) { + // 새 프로젝트 생성 + 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")); + projectParam.put("quantity", item.get("ORDER_QUANTITY") != null ? item.get("ORDER_QUANTITY") : item.get("QUANTITY")); + projectParam.put("due_date", item.get("DUE_DATE")); - paramMap.put("OBJID", CommonUtils.createObjId()); - paramMap.put("is_temp", '1'); - //paramMap.put("facility_qty", '1'); if("0000170".equals(category_cd) || "0000171".equals(category_cd)){ - paramMap.put("overhaul_project_no", target_project_no); - //paramMap.put("overhaul_order", overhaul_order+i); - }else{ + projectParam.put("overhaul_project_no", target_project_no); } - //프로젝트 등록 - cnt = sqlSession.update("project.createProject", paramMap); - //프로젝트 TASK 등록 - cnt = sqlSession.insert("contractMgmt.insertProjectTask", paramMap); - //프로젝트 SETUP_TASK 등록 - cnt = sqlSession.insert("contractMgmt.insertProjectSetupTask", paramMap); - //project_no - unit 폴더 생성 - //paramMap.put("OBJID", paramMap.get("OBJID")); - Map projectInfo = (Map)sqlSession.selectOne("project.getProjectMngInfo", paramMap); - - paramMap.put("contract_objid", paramMap.get("contractObjId")); - paramMap.put("customer_product", paramMap.get("mechanical_type")); - List> taskUnitList = (ArrayList)sqlSession.selectList("project.getWbsTaskListByProject", paramMap); - 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(); + System.out.println("프로젝트 생성 - PART_OBJID: " + item.get("PART_OBJID") + ", 품번: " + item.get("PART_NO") + ", 품명: " + item.get("PART_NAME")); + + // 프로젝트 등록 + 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("part_no", item.get("PART_NO")); + updateParam.put("part_name", item.get("PART_NAME")); + updateParam.put("quantity", item.get("ORDER_QUANTITY") != null ? item.get("ORDER_QUANTITY") : item.get("QUANTITY")); + updateParam.put("due_date", item.get("DUE_DATE")); + + System.out.println("프로젝트 업데이트 - PART_OBJID: " + item.get("PART_OBJID") + ", 품번: " + item.get("PART_NO")); + sqlSession.update("project.ModifyProjectByContract", updateParam); + } + } + } else { + System.out.println("품목이 없습니다 - 기존 방식으로 프로젝트 생성"); + // 품목이 없는 경우 기존 방식대로 처리 + resultList = sqlSession.selectOne("contractMgmt.getProjectListBycontractObjid", paramMap); + if(null==resultList){ + 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); } } + } // if(cnt > 0){ //계약완료 일시 메일 // if("0000964".equals(CommonUtils.checkNull(paramMap.get("contract_result")))){