diff --git a/WebContent/WEB-INF/dispatcher-servlet.xml b/WebContent/WEB-INF/dispatcher-servlet.xml index 8a5b95d..0769b0a 100644 --- a/WebContent/WEB-INF/dispatcher-servlet.xml +++ b/WebContent/WEB-INF/dispatcher-servlet.xml @@ -42,6 +42,17 @@ + + + + + + + + + + + diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp index 1948ab4..bf768b7 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp @@ -668,21 +668,169 @@ function fn_sendEstimateMail(contractObjId){ return; } + // 1단계: 견적서 템플릿 정보 조회 Swal.fire({ - title: '메일 발송 중...', + title: '견적서 조회 중...', text: '잠시만 기다려주세요.', allowOutsideClick: false, - didOpen: () => { + onOpen: () => { Swal.showLoading(); } }); $.ajax({ - url: "/contractMgmt/sendEstimateMail.do", + url: "/contractMgmt/getEstimateTemplateList.do", type: "POST", data: { objId: contractObjId }, dataType: "json", success: function(data){ + if(data.result === "success" && data.list && data.list.length > 0){ + // 최종 차수 견적서 찾기 + var latestEstimate = data.list[0]; // 이미 차수 내림차순으로 정렬되어 있음 + var templateObjId = latestEstimate.OBJID || latestEstimate.objid; + var templateType = latestEstimate.TEMPLATE_TYPE || latestEstimate.template_type || latestEstimate.templateType; + + // 2단계: 견적서 페이지를 새 창으로 열고 PDF 생성 + fn_generatePdfAndSendMail(contractObjId, templateObjId, templateType); + } else { + Swal.close(); + Swal.fire({ + title: '오류', + text: '견적서를 찾을 수 없습니다.', + icon: 'error' + }); + } + }, + error: function(xhr, status, error){ + Swal.close(); + console.error("견적서 조회 오류:", xhr, status, error); + Swal.fire({ + title: '오류', + text: '견적서 조회 중 오류가 발생했습니다.', + icon: 'error' + }); + } + }); +} + +// PDF 생성 및 메일 발송 +function fn_generatePdfAndSendMail(contractObjId, templateObjId, templateType){ + Swal.fire({ + title: 'PDF 생성 중...', + text: '견적서를 PDF로 변환하고 있습니다.', + allowOutsideClick: false, + onOpen: () => { + Swal.showLoading(); + } + }); + + // 견적서 페이지 URL 생성 + var url = ""; + if(templateType === "1"){ + url = "/contractMgmt/estimateTemplate1.do?templateObjId=" + templateObjId; + } else if(templateType === "2"){ + url = "/contractMgmt/estimateTemplate2.do?templateObjId=" + templateObjId; + } + + // 숨겨진 iframe으로 페이지 로드 + var iframe = $('', { + id: 'pdfGeneratorFrame', + src: url, + style: 'position:absolute;width:0;height:0;border:none;' + }).appendTo('body'); + + // iframe 로드 완료 대기 + iframe.on('load', function(){ + try { + var iframeWindow = this.contentWindow; + + // iframe 내의 PDF 생성 함수 호출 + if(typeof iframeWindow.fn_generateAndUploadPdf === 'function'){ + iframeWindow.fn_generateAndUploadPdf(function(pdfBlob){ + // iframe 제거 + $('#pdfGeneratorFrame').remove(); + + if(pdfBlob){ + // PDF Blob과 함께 메일 발송 요청 + fn_sendMailWithPdf(contractObjId, pdfBlob); + } else { + Swal.close(); + Swal.fire({ + title: '오류', + text: 'PDF 생성에 실패했습니다.', + icon: 'error' + }); + } + }); + } else { + // iframe 제거 + $('#pdfGeneratorFrame').remove(); + + Swal.close(); + Swal.fire({ + title: '오류', + text: '견적서 페이지 로드에 실패했습니다.', + icon: 'error' + }); + } + } catch(e) { + console.error('PDF 생성 오류:', e); + $('#pdfGeneratorFrame').remove(); + + Swal.close(); + Swal.fire({ + title: '오류', + text: 'PDF 생성 중 오류가 발생했습니다.', + icon: 'error' + }); + } + }); + + // 타임아웃 설정 (30초) + setTimeout(function(){ + if($('#pdfGeneratorFrame').length > 0){ + $('#pdfGeneratorFrame').remove(); + Swal.close(); + Swal.fire({ + title: '타임아웃', + text: 'PDF 생성 시간이 초과되었습니다.', + icon: 'error' + }); + } + }, 30000); +} + +// PDF Blob과 함께 메일 발송 (FormData 사용) +function fn_sendMailWithPdf(contractObjId, pdfBlob){ + console.log('===== 메일 발송 시작 ====='); + console.log('contractObjId:', contractObjId); + console.log('PDF Blob 크기:', pdfBlob ? pdfBlob.size : 0, 'bytes'); + console.log('========================'); + + Swal.fire({ + title: '메일 발송 중...', + text: '잠시만 기다려주세요.', + allowOutsideClick: false, + onOpen: () => { + Swal.showLoading(); + } + }); + + // FormData 생성 + var formData = new FormData(); + formData.append('objId', contractObjId); + formData.append('pdfFile', pdfBlob, 'estimate.pdf'); + + $.ajax({ + url: "/contractMgmt/sendEstimateMail.do", + type: "POST", + data: formData, + processData: false, // FormData 사용 시 필수 + contentType: false, // FormData 사용 시 필수 + dataType: "json", + timeout: 60000, // 60초 타임아웃 + success: function(data){ + console.log('메일 발송 응답:', data); Swal.close(); if(data.result === "success"){ Swal.fire({ @@ -706,9 +854,10 @@ function fn_sendEstimateMail(contractObjId){ error: function(xhr, status, error){ Swal.close(); console.error("메일 발송 오류:", xhr, status, error); + console.error("xhr.responseText:", xhr.responseText); Swal.fire({ title: '오류', - text: '메일 발송 중 시스템 오류가 발생했습니다.', + text: '메일 발송 중 시스템 오류가 발생했습니다: ' + status, icon: 'error', confirmButtonText: '확인' }); diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp index 361887f..66c3bd7 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp @@ -165,9 +165,10 @@ body { .items-table th, .items-table td { border: 1px solid #000; - padding: 6px 8px; + padding: 3px 5px; text-align: center; font-size: 9pt; + line-height: 1.3; } .items-table th { @@ -265,11 +266,12 @@ textarea { textarea { resize: vertical; - min-height: 30px; + min-height: 25px; + padding: 2px; } .editable { - background-color: #fffef0; + background-color: transparent; } @media print { @@ -462,8 +464,8 @@ function fn_calculateAmount(row) { function fn_calculateTotal() { var total = 0; - // 품목 행만 순회 (계 행, 원화환산 행, 비고 행 제외) - $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row").each(function(){ + // 품목 행만 순회 (계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외) + $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row").each(function(){ var amount = $(this).find(".item-amount").val() || "0"; // 콤마와 통화 기호 제거 후 숫자로 변환 amount = amount.replace(/,/g, "").replace(/₩/g, "").replace(/\$/g, "").replace(/€/g, "").replace(/¥/g, ""); @@ -580,8 +582,8 @@ function fn_initItemDescSelect(itemId) { // 행 추가 함수 function fn_addItemRow() { - // 계 행, 원화환산 행, 비고 행 제외하고 품목 행 개수 계산 - var itemRows = $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row"); + // 계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외하고 품목 행 개수 계산 + var itemRows = $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row"); var nextNo = itemRows.length + 1; // 새 행 생성 @@ -856,12 +858,6 @@ function fn_loadTemplateData(templateObjId){ $("#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 || ""; @@ -930,6 +926,24 @@ function fn_loadTemplateData(templateObjId){ itemsHtml += ''; itemsHtml += ''; + // 참조사항 행 추가 + itemsHtml += ''; + itemsHtml += ''; + itemsHtml += '<참조사항>'; + itemsHtml += ''; + itemsHtml += ''; + itemsHtml += ''; + itemsHtml += ''; + itemsHtml += ''; + itemsHtml += ''; + + // 하단 회사명 행 추가 + itemsHtml += ''; + itemsHtml += ''; + itemsHtml += '㈜알피에스'; + itemsHtml += ''; + itemsHtml += ''; + // HTML 삽입 $("#itemsTableBody").html(itemsHtml); @@ -976,11 +990,17 @@ function fn_loadTemplateData(templateObjId){ fn_initItemDescSelect(itemId); } - // 테이블 내 비고 값 설정 (textarea 생성 직후) - $("#note_remarks").val(noteRemarks); - - // 합계 계산 - fn_calculateTotal(); + // 테이블 내 비고 값 설정 (textarea 생성 직후) + $("#note_remarks").val(noteRemarks); + + // 참조사항 값 설정 (input 생성 직후) + $("#note1").val(note1 || "1. 견적유효기간: 일"); + $("#note2").val(note2 || "2. 납품기간: 발주 후 1주 이내"); + $("#note3").val(note3 || "3. VAT 별도"); + $("#note4").val(note4 || "4. 결제 조건 : 기존 결제조건에 따름."); + + // 합계 계산 + fn_calculateTotal(); // 결재상태에 따라 버튼 제어 fn_controlButtons(); @@ -1025,8 +1045,8 @@ function fn_loadCustomerContact(customerObjId) { function fn_save() { var items = []; - // 계 행, 원화환산 행, 비고 행 제외하고 품목 행만 저장 - $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row").each(function(idx) { + // 계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외하고 품목 행만 저장 + $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row").each(function(idx) { var row = $(this); var quantity = row.find(".item-qty").val() || ""; var unitPrice = row.find(".item-price").val() || ""; @@ -1128,6 +1148,7 @@ function fn_save() { + @@ -1135,6 +1156,7 @@ function fn_save() { + ㈊알피에스RPS CO., LTD대표이사이동준 - - 담당자 : - 연락처 : - + @@ -1173,15 +1192,19 @@ function fn_save() { - + + + 견적을 요청해 주셔서 대단히 감사합니다. 하기와 같이 견적서를 제출합니다. - - - - 부가세 별도 + + + 담당자 : + 연락처 : + 부가세 별도 + @@ -1245,31 +1268,224 @@ function fn_save() { + + + + <참조사항> + + + + + + + + + + ㈜알피에스 + + - - - - <참조사항> - - - - - - - - 행 추가 인쇄 + PDF 다운로드 저장 닫기 + + + + +