Compare commits
5 Commits
V202512180
...
V202512010
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ec25ecc27 | |||
| 546bea7b4c | |||
|
|
dfed125ee9 | ||
| d8620a484b | |||
|
|
874910231f |
@@ -1802,6 +1802,13 @@
|
||||
WHERE OBJID = #{OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 반제품검사 행 잠금 해제 (IS_LOCKED = 'N') -->
|
||||
<update id="unlockSemiProductInspection" parameterType="map">
|
||||
UPDATE PMS_QUALITY_SEMI_PRODUCT_INSPECTION
|
||||
SET IS_LOCKED = 'N'
|
||||
WHERE OBJID = #{OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 반제품검사 데이터 삭제 (OBJID로 단건 삭제) -->
|
||||
<delete id="deleteSemiProductInspectionByObjId" parameterType="map">
|
||||
DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
|
||||
|
||||
@@ -201,8 +201,12 @@ input.date_icon {
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var grid;
|
||||
// PDF 생성용 플래그
|
||||
window.dataLoaded = false;
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
@@ -526,6 +530,199 @@ var gridFn = {
|
||||
$("#TOTAL_PRICE_ALL").val(numberWithCommas(totalWithVat));
|
||||
}
|
||||
}
|
||||
|
||||
// 라이브러리 로드 완료 후 dataLoaded 플래그 설정
|
||||
$(window).on('load', function() {
|
||||
setTimeout(function() {
|
||||
if(typeof html2canvas !== 'undefined' && typeof jspdf !== 'undefined') {
|
||||
window.dataLoaded = true;
|
||||
console.log('발주서 일반양식 - dataLoaded = true');
|
||||
} else {
|
||||
// jsPDF 전역 객체 확인
|
||||
if(typeof html2canvas !== 'undefined' && typeof window.jspdf !== 'undefined') {
|
||||
window.dataLoaded = true;
|
||||
console.log('발주서 일반양식 - dataLoaded = true (jspdf)');
|
||||
} else {
|
||||
console.log('라이브러리 로드 대기중...');
|
||||
setTimeout(function() {
|
||||
window.dataLoaded = true;
|
||||
console.log('발주서 일반양식 - dataLoaded = true (지연)');
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// PDF를 Base64로 생성하여 콜백으로 전달하는 함수
|
||||
function fn_generateAndUploadPdf(callback) {
|
||||
console.log('fn_generateAndUploadPdf 호출됨 (일반 발주서)');
|
||||
|
||||
// 라이브러리 로드 확인
|
||||
if(typeof html2canvas === 'undefined') {
|
||||
console.error('html2canvas 라이브러리가 로드되지 않았습니다.');
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var jsPDF = window.jspdf ? window.jspdf.jsPDF : null;
|
||||
if(!jsPDF) {
|
||||
console.error('jsPDF 라이브러리가 로드되지 않았습니다.');
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 버튼 영역 임시 숨김
|
||||
$('#btnSave, #btnDown, input[value="닫기"]').closest('div').hide();
|
||||
|
||||
// select2 컨테이너 숨김 (중복 표시 방지)
|
||||
$('.select2-container').hide();
|
||||
|
||||
// input/select 값을 텍스트로 변환 (html2canvas가 input value를 캡처하지 못하는 문제 해결)
|
||||
var inputBackups = [];
|
||||
|
||||
// input 요소 처리 (form1 내부 + 그리드 포함)
|
||||
$('input[type="text"], input:not([type])').each(function(){
|
||||
var $input = $(this);
|
||||
var value = $input.val();
|
||||
if(value) {
|
||||
inputBackups.push({
|
||||
element: $input,
|
||||
html: $input[0].outerHTML,
|
||||
parent: $input.parent()
|
||||
});
|
||||
var $span = $('<span class="pdf-temp-span">').text(value).css({
|
||||
'display': 'inline-block',
|
||||
'white-space': 'nowrap',
|
||||
'text-align': $input.css('text-align') || 'left',
|
||||
'font-size': $input.css('font-size') || '12px',
|
||||
'font-weight': $input.css('font-weight') || 'normal',
|
||||
'padding': '2px 5px',
|
||||
'color': $input.css('color') || '#000',
|
||||
'background': 'transparent'
|
||||
});
|
||||
$input.replaceWith($span);
|
||||
inputBackups[inputBackups.length - 1].span = $span;
|
||||
}
|
||||
});
|
||||
|
||||
// select 요소 처리 (select2 포함)
|
||||
$('select').each(function(){
|
||||
var $select = $(this);
|
||||
var value = $select.find('option:selected').text();
|
||||
if(value && value.trim() !== '' && value !== '선택') {
|
||||
inputBackups.push({
|
||||
element: $select,
|
||||
html: $select[0].outerHTML,
|
||||
parent: $select.parent(),
|
||||
wasHidden: $select.is(':hidden')
|
||||
});
|
||||
var $span = $('<span class="pdf-temp-span">').text(value).css({
|
||||
'display': 'inline-block',
|
||||
'white-space': 'nowrap',
|
||||
'text-align': 'left',
|
||||
'font-size': '12px',
|
||||
'padding': '2px 5px',
|
||||
'color': '#000',
|
||||
'background': 'transparent'
|
||||
});
|
||||
$select.after($span).hide();
|
||||
inputBackups[inputBackups.length - 1].span = $span;
|
||||
}
|
||||
});
|
||||
|
||||
// 캡처할 영역 (form1)
|
||||
var captureElement = document.getElementById('form1');
|
||||
|
||||
// html2canvas로 캡처
|
||||
html2canvas(captureElement, {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
logging: false,
|
||||
backgroundColor: '#ffffff',
|
||||
windowWidth: captureElement.scrollWidth,
|
||||
windowHeight: captureElement.scrollHeight
|
||||
}).then(function(canvas) {
|
||||
console.log('Canvas 캡처 완료');
|
||||
|
||||
// 임시 span 제거 및 원본 복원
|
||||
$('.pdf-temp-span').remove();
|
||||
for(var i = 0; i < inputBackups.length; i++) {
|
||||
var backup = inputBackups[i];
|
||||
if(backup.element && backup.element.is('select')) {
|
||||
// select는 숨겨둔 것만 다시 표시
|
||||
backup.element.show();
|
||||
} else if(backup.span && backup.parent) {
|
||||
// input은 span을 원본으로 교체
|
||||
backup.span.replaceWith(backup.html);
|
||||
}
|
||||
}
|
||||
|
||||
// select2 컨테이너 다시 표시
|
||||
$('.select2-container').show();
|
||||
|
||||
// 버튼 영역 다시 표시
|
||||
$('#btnSave, #btnDown, input[value="닫기"]').closest('div').show();
|
||||
|
||||
try {
|
||||
// Canvas를 JPEG 이미지로 변환
|
||||
var imgData = canvas.toDataURL('image/jpeg', 0.85);
|
||||
console.log('이미지 변환 완료');
|
||||
|
||||
// PDF 생성
|
||||
var pdf = new jsPDF('p', 'mm', 'a4');
|
||||
var imgWidth = 210;
|
||||
var pageHeight = 297;
|
||||
var imgHeight = canvas.height * imgWidth / canvas.width;
|
||||
var heightLeft = imgHeight;
|
||||
var position = 0;
|
||||
|
||||
// 이미지 추가
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
|
||||
while (heightLeft >= 0) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
}
|
||||
|
||||
console.log('PDF 생성 완료');
|
||||
|
||||
// PDF를 Base64로 변환
|
||||
var pdfBase64 = pdf.output('dataurlstring').split(',')[1];
|
||||
console.log('PDF Base64 생성 완료, 길이:', pdfBase64.length);
|
||||
|
||||
// 콜백 함수 호출
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(pdfBase64);
|
||||
}
|
||||
} catch(pdfError) {
|
||||
console.error('PDF 생성 중 오류:', pdfError);
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
}).catch(function(error) {
|
||||
// span을 다시 input으로 복원
|
||||
for(var i = 0; i < inputBackups.length; i++) {
|
||||
var backup = inputBackups[i];
|
||||
if(backup.span) {
|
||||
backup.span.replaceWith(backup.html);
|
||||
}
|
||||
}
|
||||
$('#btnSave, #btnDown, input[value="닫기"]').closest('div').show();
|
||||
console.error('Canvas 캡처 오류:', error);
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -180,8 +180,12 @@ input.date_icon {
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var grid;
|
||||
// PDF 생성용 플래그
|
||||
window.dataLoaded = false;
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
@@ -484,6 +488,198 @@ var gridFn = {
|
||||
$("#TOTAL_SUPPLY_PRICE").val(numberWithCommas(totalSupplyPrice));
|
||||
}
|
||||
}
|
||||
|
||||
// 라이브러리 로드 완료 후 dataLoaded 플래그 설정
|
||||
$(window).on('load', function() {
|
||||
setTimeout(function() {
|
||||
if(typeof html2canvas !== 'undefined' && typeof jspdf !== 'undefined') {
|
||||
window.dataLoaded = true;
|
||||
console.log('발주서 외주양식 - dataLoaded = true');
|
||||
} else {
|
||||
if(typeof html2canvas !== 'undefined' && typeof window.jspdf !== 'undefined') {
|
||||
window.dataLoaded = true;
|
||||
console.log('발주서 외주양식 - dataLoaded = true (jspdf)');
|
||||
} else {
|
||||
console.log('라이브러리 로드 대기중...');
|
||||
setTimeout(function() {
|
||||
window.dataLoaded = true;
|
||||
console.log('발주서 외주양식 - dataLoaded = true (지연)');
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// PDF를 Base64로 생성하여 콜백으로 전달하는 함수
|
||||
function fn_generateAndUploadPdf(callback) {
|
||||
console.log('fn_generateAndUploadPdf 호출됨 (외주 발주서)');
|
||||
|
||||
// 라이브러리 로드 확인
|
||||
if(typeof html2canvas === 'undefined') {
|
||||
console.error('html2canvas 라이브러리가 로드되지 않았습니다.');
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var jsPDF = window.jspdf ? window.jspdf.jsPDF : null;
|
||||
if(!jsPDF) {
|
||||
console.error('jsPDF 라이브러리가 로드되지 않았습니다.');
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 버튼 영역 임시 숨김
|
||||
$('.btn-area, #btnSave, #btnDown, input[value="닫기"]').closest('div').hide();
|
||||
|
||||
// select2 컨테이너 숨김 (중복 표시 방지)
|
||||
$('.select2-container').hide();
|
||||
|
||||
// input/select 값을 텍스트로 변환 (html2canvas가 input value를 캡처하지 못하는 문제 해결)
|
||||
var inputBackups = [];
|
||||
|
||||
// input 요소 처리 (form1 내부 + 그리드 포함)
|
||||
$('input[type="text"], input:not([type])').each(function(){
|
||||
var $input = $(this);
|
||||
var value = $input.val();
|
||||
if(value) {
|
||||
inputBackups.push({
|
||||
element: $input,
|
||||
html: $input[0].outerHTML,
|
||||
parent: $input.parent()
|
||||
});
|
||||
var $span = $('<span class="pdf-temp-span">').text(value).css({
|
||||
'display': 'inline-block',
|
||||
'white-space': 'nowrap',
|
||||
'text-align': $input.css('text-align') || 'left',
|
||||
'font-size': $input.css('font-size') || '12px',
|
||||
'font-weight': $input.css('font-weight') || 'normal',
|
||||
'padding': '2px 5px',
|
||||
'color': $input.css('color') || '#000',
|
||||
'background': 'transparent'
|
||||
});
|
||||
$input.replaceWith($span);
|
||||
inputBackups[inputBackups.length - 1].span = $span;
|
||||
}
|
||||
});
|
||||
|
||||
// select 요소 처리 (select2 포함)
|
||||
$('select').each(function(){
|
||||
var $select = $(this);
|
||||
var value = $select.find('option:selected').text();
|
||||
if(value && value.trim() !== '' && value !== '선택') {
|
||||
inputBackups.push({
|
||||
element: $select,
|
||||
html: $select[0].outerHTML,
|
||||
parent: $select.parent(),
|
||||
wasHidden: $select.is(':hidden')
|
||||
});
|
||||
var $span = $('<span class="pdf-temp-span">').text(value).css({
|
||||
'display': 'inline-block',
|
||||
'white-space': 'nowrap',
|
||||
'text-align': 'left',
|
||||
'font-size': '12px',
|
||||
'padding': '2px 5px',
|
||||
'color': '#000',
|
||||
'background': 'transparent'
|
||||
});
|
||||
$select.after($span).hide();
|
||||
inputBackups[inputBackups.length - 1].span = $span;
|
||||
}
|
||||
});
|
||||
|
||||
// 캡처할 영역 (form1)
|
||||
var captureElement = document.getElementById('form1');
|
||||
|
||||
// html2canvas로 캡처
|
||||
html2canvas(captureElement, {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
logging: false,
|
||||
backgroundColor: '#ffffff',
|
||||
windowWidth: captureElement.scrollWidth,
|
||||
windowHeight: captureElement.scrollHeight
|
||||
}).then(function(canvas) {
|
||||
console.log('Canvas 캡처 완료');
|
||||
|
||||
// 임시 span 제거 및 원본 복원
|
||||
$('.pdf-temp-span').remove();
|
||||
for(var i = 0; i < inputBackups.length; i++) {
|
||||
var backup = inputBackups[i];
|
||||
if(backup.element && backup.element.is('select')) {
|
||||
// select는 숨겨둔 것만 다시 표시
|
||||
backup.element.show();
|
||||
} else if(backup.span && backup.parent) {
|
||||
// input은 span을 원본으로 교체
|
||||
backup.span.replaceWith(backup.html);
|
||||
}
|
||||
}
|
||||
|
||||
// select2 컨테이너 다시 표시
|
||||
$('.select2-container').show();
|
||||
|
||||
// 버튼 영역 다시 표시
|
||||
$('.btn-area, #btnSave, #btnDown, input[value="닫기"]').closest('div').show();
|
||||
|
||||
try {
|
||||
// Canvas를 JPEG 이미지로 변환
|
||||
var imgData = canvas.toDataURL('image/jpeg', 0.85);
|
||||
console.log('이미지 변환 완료');
|
||||
|
||||
// PDF 생성
|
||||
var pdf = new jsPDF('p', 'mm', 'a4');
|
||||
var imgWidth = 210;
|
||||
var pageHeight = 297;
|
||||
var imgHeight = canvas.height * imgWidth / canvas.width;
|
||||
var heightLeft = imgHeight;
|
||||
var position = 0;
|
||||
|
||||
// 이미지 추가
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
|
||||
while (heightLeft >= 0) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
}
|
||||
|
||||
console.log('PDF 생성 완료');
|
||||
|
||||
// PDF를 Base64로 변환
|
||||
var pdfBase64 = pdf.output('dataurlstring').split(',')[1];
|
||||
console.log('PDF Base64 생성 완료, 길이:', pdfBase64.length);
|
||||
|
||||
// 콜백 함수 호출
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(pdfBase64);
|
||||
}
|
||||
} catch(pdfError) {
|
||||
console.error('PDF 생성 중 오류:', pdfError);
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
}).catch(function(error) {
|
||||
// span을 다시 input으로 복원
|
||||
for(var i = 0; i < inputBackups.length; i++) {
|
||||
var backup = inputBackups[i];
|
||||
if(backup.span) {
|
||||
backup.span.replaceWith(backup.html);
|
||||
}
|
||||
}
|
||||
$('.btn-area, #btnSave, #btnDown, input[value="닫기"]').closest('div').show();
|
||||
console.error('Canvas 캡처 오류:', error);
|
||||
if(callback && typeof callback === 'function') {
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -190,12 +190,13 @@ String purchaseOrderObjId = request.getParameter("purchaseOrderObjId");
|
||||
</div>
|
||||
|
||||
<div class="attachment-status">
|
||||
<i class="fa fa-file-excel-o"></i>
|
||||
<strong>첨부파일:</strong> 발주서 및 도면 파일이 자동으로 첨부됩니다.
|
||||
<i class="fa fa-file-pdf-o"></i>
|
||||
<strong>첨부파일:</strong> 발주서(PDF) 및 도면 파일이 자동으로 첨부됩니다.
|
||||
</div>
|
||||
|
||||
<form id="mailForm">
|
||||
<input type="hidden" id="purchaseOrderObjId" name="purchaseOrderObjId" value="<%=purchaseOrderObjId%>"/>
|
||||
<input type="hidden" id="pdfSessionId" name="pdfSessionId" value=""/>
|
||||
|
||||
<!-- 공급업체 담당자 선택 -->
|
||||
<div class="form-group">
|
||||
@@ -261,6 +262,9 @@ function fn_loadPurchaseOrderInfo(){
|
||||
if(data.result === "success" && data.purchaseOrderInfo){
|
||||
purchaseOrderInfo = data.purchaseOrderInfo;
|
||||
|
||||
// 양식 타입 확인 (디버깅용)
|
||||
console.log("발주서 양식 타입 (FORM_TYPE):", purchaseOrderInfo.FORM_TYPE);
|
||||
|
||||
// 발주서 정보 표시
|
||||
$("#displayPoNo").text(fnc_checkNull(purchaseOrderInfo.PURCHASE_ORDER_NO) || '-');
|
||||
$("#displayPartnerName").text(fnc_checkNull(purchaseOrderInfo.PARTNER_NAME) || '-');
|
||||
@@ -471,24 +475,197 @@ function fn_sendMail(){
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed){
|
||||
fn_submitMailForm();
|
||||
// PDF 생성 및 발송 시작
|
||||
fn_generatePdfAndSend();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 메일 발송 요청
|
||||
function fn_submitMailForm(){
|
||||
// PDF 생성 및 발송
|
||||
function fn_generatePdfAndSend(){
|
||||
var purchaseOrderObjId = $("#purchaseOrderObjId").val();
|
||||
|
||||
Swal.fire({
|
||||
title: '발송 중...',
|
||||
text: '발주서 메일을 발송하고 있습니다.',
|
||||
title: 'PDF 생성 중...',
|
||||
text: '발주서를 PDF로 변환하고 있습니다.',
|
||||
allowOutsideClick: false,
|
||||
onOpen: () => {
|
||||
Swal.showLoading();
|
||||
}
|
||||
});
|
||||
|
||||
// 발주서 양식 타입 확인 (일반/외주)
|
||||
var formType = fnc_checkNull(purchaseOrderInfo.FORM_TYPE) || 'general';
|
||||
var url = "";
|
||||
|
||||
if(formType === 'outsourcing') {
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_outsourcing.do?actType=VIEW&PURCHASE_ORDER_MASTER_OBJID=" + purchaseOrderObjId;
|
||||
} else {
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_general.do?actType=VIEW&PURCHASE_ORDER_MASTER_OBJID=" + purchaseOrderObjId;
|
||||
}
|
||||
|
||||
// 숨겨진 iframe으로 발주서 페이지 로드
|
||||
var iframe = $('<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;
|
||||
|
||||
// 데이터 로딩 완료 대기 (최대 60초)
|
||||
var checkDataLoaded = function(attempts) {
|
||||
if(attempts > 600) {
|
||||
$('#pdfGeneratorFrame').remove();
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '타임아웃',
|
||||
text: '발주서 데이터 로딩 시간이 초과되었습니다. (60초)',
|
||||
icon: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if(iframeWindow.dataLoaded === true) {
|
||||
// PDF 생성 함수 호출
|
||||
if(typeof iframeWindow.fn_generateAndUploadPdf === 'function'){
|
||||
iframeWindow.fn_generateAndUploadPdf(function(pdfBase64){
|
||||
$('#pdfGeneratorFrame').remove();
|
||||
|
||||
if(pdfBase64){
|
||||
// PDF 업로드 후 메일 발송
|
||||
fn_uploadPdfAndSendMail(purchaseOrderObjId, pdfBase64);
|
||||
} else {
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: 'PDF 생성에 실패했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$('#pdfGeneratorFrame').remove();
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '발주서 페이지 로드에 실패했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
checkDataLoaded(attempts + 1);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
checkDataLoaded(0);
|
||||
} catch(e) {
|
||||
console.error('PDF 생성 오류:', e);
|
||||
$('#pdfGeneratorFrame').remove();
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: 'PDF 생성 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 타임아웃 설정 (120초)
|
||||
setTimeout(function(){
|
||||
if($('#pdfGeneratorFrame').length > 0){
|
||||
$('#pdfGeneratorFrame').remove();
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '타임아웃',
|
||||
text: 'PDF 생성 시간이 초과되었습니다. (120초)',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
}, 120000);
|
||||
}
|
||||
|
||||
// PDF 업로드 및 메일 발송
|
||||
function fn_uploadPdfAndSendMail(purchaseOrderObjId, pdfBase64){
|
||||
Swal.update({
|
||||
text: 'PDF 업로드 중...'
|
||||
});
|
||||
|
||||
// 청크 업로드
|
||||
var chunkSize = 100 * 1024;
|
||||
var totalChunks = Math.ceil(pdfBase64.length / chunkSize);
|
||||
var uploadedChunks = 0;
|
||||
var sessionId = 'pdf_po_' + purchaseOrderObjId + '_' + new Date().getTime();
|
||||
|
||||
function uploadChunk(chunkIndex) {
|
||||
var start = chunkIndex * chunkSize;
|
||||
var end = Math.min(start + chunkSize, pdfBase64.length);
|
||||
var chunk = pdfBase64.substring(start, end);
|
||||
|
||||
$.ajax({
|
||||
url: "/purchaseOrder/uploadPdfChunk.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
sessionId: sessionId,
|
||||
chunkIndex: chunkIndex,
|
||||
totalChunks: totalChunks,
|
||||
chunk: chunk
|
||||
},
|
||||
dataType: "json",
|
||||
timeout: 30000,
|
||||
success: function(data){
|
||||
if(data.result === "success"){
|
||||
uploadedChunks++;
|
||||
|
||||
var progress = Math.round((uploadedChunks / totalChunks) * 100);
|
||||
Swal.update({
|
||||
text: 'PDF 업로드 중... ' + progress + '%'
|
||||
});
|
||||
|
||||
if(chunkIndex + 1 < totalChunks){
|
||||
uploadChunk(chunkIndex + 1);
|
||||
} else {
|
||||
// 모든 청크 업로드 완료, 메일 발송
|
||||
$("#pdfSessionId").val(sessionId);
|
||||
fn_submitMailForm();
|
||||
}
|
||||
} else {
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '업로드 실패',
|
||||
text: 'PDF 업로드 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.close();
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: 'PDF 업로드 중 시스템 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uploadChunk(0);
|
||||
}
|
||||
|
||||
// 메일 발송 요청
|
||||
function fn_submitMailForm(){
|
||||
Swal.update({
|
||||
text: '메일 발송 중...'
|
||||
});
|
||||
|
||||
var formData = {
|
||||
objId: $("#purchaseOrderObjId").val(),
|
||||
pdfSessionId: $("#pdfSessionId").val(),
|
||||
toEmails: $("#toEmails").val(),
|
||||
ccEmails: $("#ccEmails").val(),
|
||||
subject: $("#subject").val(),
|
||||
|
||||
@@ -158,6 +158,20 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
|
||||
background: #2b6cb0;
|
||||
}
|
||||
|
||||
.btn_edit {
|
||||
padding: 6px 20px;
|
||||
background: #e67e22;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn_edit:hover {
|
||||
background: #d35400;
|
||||
}
|
||||
|
||||
.btn_close {
|
||||
padding: 6px 20px;
|
||||
background: #718096;
|
||||
@@ -232,7 +246,8 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
|
||||
<div class="btn_group">
|
||||
<button type="button" class="btn_add" id="btnAddLeft">+ 행 추가</button>
|
||||
<button type="button" class="btn_del" id="btnDelLeft">- 행 삭제</button>
|
||||
<button type="button" class="btn_save" id="btnSaveLeft" style="margin-left:10px;">저장</button>
|
||||
<button type="button" class="btn_save" id="btnSaveLeft" style="margin-left:10px;">행잠금</button>
|
||||
<button type="button" class="btn_edit" id="btnEditLeft" style="margin-left:5px;">잠금해제</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel_body">
|
||||
@@ -247,7 +262,9 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
|
||||
<div class="btn_group">
|
||||
<button type="button" class="btn_add" id="btnAddRight">+ 행 추가</button>
|
||||
<button type="button" class="btn_del" id="btnDelRight">- 행 삭제</button>
|
||||
<!-- 불량상세 저장버튼 주석처리
|
||||
<button type="button" class="btn_save" id="btnSaveRight" style="margin-left:10px;">저장</button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel_body" id="rightPanelBody">
|
||||
@@ -314,8 +331,9 @@ $(document).ready(function(){
|
||||
|
||||
// 버튼 이벤트
|
||||
$("#btnSave").click(fn_save); // 하단 저장: 전체 DB 저장
|
||||
$("#btnSaveLeft").click(fn_saveSelectedLeft); // 좌측 저장: UI 잠금만 (DB 저장 X)
|
||||
$("#btnSaveRight").click(fn_saveSelectedRight); // 우측 저장: UI 잠금만 (DB 저장 X)
|
||||
$("#btnSaveLeft").click(fn_saveSelectedLeft); // 좌측 행저장: 락 처리
|
||||
$("#btnEditLeft").click(fn_editSelectedLeft); // 좌측 행수정: 락 해제
|
||||
// $("#btnSaveRight").click(fn_saveSelectedRight); // 우측 저장: 주석처리
|
||||
$("#btnClose").click(function(){ window.close(); });
|
||||
$("#btnAddLeft").click(fn_addLeftRow);
|
||||
$("#btnDelLeft").click(fn_delLeftRow);
|
||||
@@ -478,9 +496,13 @@ function fn_initLeftGrid(){
|
||||
selectable: 1, // 단일 선택
|
||||
// 저장된 행 시각적 표시
|
||||
rowFormatter: function(row){
|
||||
if(row.getData().IS_SAVED){
|
||||
var data = row.getData();
|
||||
if(data.IS_SAVED || data.IS_LOCKED === 'Y'){
|
||||
row.getElement().style.backgroundColor = "#e8f5e9"; // 연한 초록색
|
||||
row.getElement().style.color = "#555";
|
||||
} else {
|
||||
row.getElement().style.backgroundColor = ""; // 원래 색상
|
||||
row.getElement().style.color = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -594,9 +616,13 @@ function fn_initRightGrid(){
|
||||
selectable: true,
|
||||
// 저장된 행 시각적 표시
|
||||
rowFormatter: function(row){
|
||||
if(row.getData().IS_SAVED){
|
||||
var data = row.getData();
|
||||
if(data.IS_SAVED || data.IS_LOCKED === 'Y'){
|
||||
row.getElement().style.backgroundColor = "#e8f5e9"; // 연한 초록색
|
||||
row.getElement().style.color = "#555";
|
||||
} else {
|
||||
row.getElement().style.backgroundColor = ""; // 원래 색상
|
||||
row.getElement().style.color = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -998,6 +1024,68 @@ function fn_loadData(objid, inspectionGroupId){
|
||||
});
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 좌측 행수정: 락이 걸린 행을 수정 가능하도록 해제
|
||||
// =====================================================
|
||||
function fn_editSelectedLeft(){
|
||||
console.log("===== fn_editSelectedLeft 호출됨 =====");
|
||||
|
||||
if(!selectedLeftRowId){
|
||||
Swal.fire({ icon: 'warning', title: '알림', text: '수정할 양품 정보를 선택해주세요.' });
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedRow = leftGrid.getSelectedRows()[0];
|
||||
if(!selectedRow){
|
||||
Swal.fire({ icon: 'warning', title: '알림', text: '수정할 양품 정보를 선택해주세요.' });
|
||||
return;
|
||||
}
|
||||
|
||||
var rowData = selectedRow.getData();
|
||||
|
||||
// 락이 걸려있지 않으면 이미 수정 가능 상태
|
||||
if(rowData.IS_LOCKED !== 'Y' && !rowData.IS_SAVED){
|
||||
Swal.fire({ icon: 'info', title: '알림', text: '이미 수정 가능한 상태입니다.' });
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
icon: 'question',
|
||||
title: '행수정',
|
||||
text: '선택한 행의 잠금을 해제하고 수정 가능하게 하시겠습니까?',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '확인',
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed){
|
||||
var objId = rowData.OBJID;
|
||||
|
||||
// DB에 잠금 해제 요청
|
||||
$.ajax({
|
||||
url: "/quality/unlockSemiProductInspection.do",
|
||||
type: "POST",
|
||||
data: { objIds: JSON.stringify([objId]) },
|
||||
dataType: "json",
|
||||
success: function(result){
|
||||
if(result.result){
|
||||
// UI에서 잠금 해제
|
||||
selectedRow.update({ IS_SAVED: false, IS_LOCKED: 'N' });
|
||||
// 행 스타일 원래대로 (초록색 -> 기본색)
|
||||
selectedRow.getElement().style.backgroundColor = "";
|
||||
selectedRow.getElement().style.color = "";
|
||||
Swal.fire({ icon: 'success', title: '완료', text: '잠금이 해제되어 수정 가능합니다.' });
|
||||
} else {
|
||||
Swal.fire({ icon: 'error', title: '오류', text: result.msg || '잠금 해제에 실패했습니다.' });
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
Swal.fire({ icon: 'error', title: '오류', text: '잠금 해제 중 오류가 발생했습니다.' });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 좌측 행 저장+잠금: 선택된 양품 행을 DB에 저장하고 수정 불가로 변경
|
||||
// =====================================================
|
||||
|
||||
@@ -461,7 +461,7 @@ public class Constants {
|
||||
}
|
||||
|
||||
//Mail 관련
|
||||
public class Mail{
|
||||
public static class Mail{
|
||||
public static final String TEMPLATE_FILE_PATH = applicationRootDir+"\\WebContent\\mailTemplate\\"; //메일내용 템플릿 위치
|
||||
public static final boolean sendMailSwitch = true; //메일발송 사용여부
|
||||
public static final boolean dbLogWrite = true; //메일발송시 DB로그 사용여부
|
||||
@@ -469,19 +469,67 @@ public class Constants {
|
||||
public static final String FILE_PATH = FILE_STORAGE+"\\MAIL";
|
||||
public static final String CHARSET = SYSTEM_CHARSET;
|
||||
|
||||
/* SMTP 메일정보 - RPS */
|
||||
public static final String SMTP_USER = "erp@rps-korea.com";//SMTP USER ID (전체 이메일 주소)
|
||||
public static final String SMTP_USER_PW = "Plmrps123!!"; //SMTP USER PASSWORD
|
||||
public static final String SMTP_HOST = "gwa.rps-korea.com";
|
||||
// public static final String SMTP_USER = "sales@rps-korea.com";//SMTP USER ID (전체 이메일 주소)
|
||||
// public static final String SMTP_USER_PW = "rpstech6125!!"; //SMTP USER PASSWORD
|
||||
// public static final String SMTP_HOST = "wblock.rps-korea.com"; //SMTP HOST (gw.rps-korea.com IP)
|
||||
//public static final String SMTP_HOST = "220.123.92.226"; //SMTP HOST (gw.rps-korea.com IP)
|
||||
public static final int SMTP_PORT = 25; //SMTP PORT (SSL 사용안함)
|
||||
// public static final String SMTP_USER = "admin@wsse.co.kr";//SMTP USER ID [mail.gdnsi.com]
|
||||
// public static final String SMTP_USER_PW = "admin123!@#"; //SMTP USER PASSWORD
|
||||
// public static final String SMTP_HOST = "smtps.hiworks.com"; //SMTP HOST
|
||||
// public static final int SMTP_PORT = 465; //SMTP PORT
|
||||
// SMTP 계정 타입
|
||||
public static final String ACCOUNT_TYPE_ERP = "ERP"; // 일반 (기본값)
|
||||
public static final String ACCOUNT_TYPE_SALES = "SALES"; // 영업팀 (견적서 등)
|
||||
public static final String ACCOUNT_TYPE_PURCHASE = "PURCHASE"; // 구매팀 (발주서 등)
|
||||
|
||||
/* SMTP 메일정보 - ERP (일반/기본) */
|
||||
public static final String SMTP_USER = "erp@rps-korea.com";
|
||||
public static final String SMTP_USER_PW = "Plmrps123!!";
|
||||
public static final String SMTP_HOST = "gwa.rps-korea.com";
|
||||
public static final int SMTP_PORT = 25;
|
||||
|
||||
/* SMTP 메일정보 - 영업팀 (견적서 등) */
|
||||
public static final String SMTP_USER_SALES = "sales@rps-korea.com";
|
||||
public static final String SMTP_USER_PW_SALES = "rpstech6125!!";
|
||||
public static final String SMTP_HOST_SALES = "wblock.rps-korea.com";
|
||||
public static final int SMTP_PORT_SALES = 25;
|
||||
|
||||
/* SMTP 메일정보 - 구매팀 (발주서 등) */
|
||||
public static final String SMTP_USER_PURCHASE = "erp@rps-korea.com";
|
||||
public static final String SMTP_USER_PW_PURCHASE = "Plmrps123!!";
|
||||
public static final String SMTP_HOST_PURCHASE = "gwa.rps-korea.com";
|
||||
public static final int SMTP_PORT_PURCHASE = 25;
|
||||
|
||||
/**
|
||||
* 계정 타입에 따른 SMTP 정보 반환
|
||||
*/
|
||||
public static String getSmtpUser(String accountType) {
|
||||
if (ACCOUNT_TYPE_SALES.equals(accountType)) {
|
||||
return SMTP_USER_SALES;
|
||||
} else if (ACCOUNT_TYPE_PURCHASE.equals(accountType)) {
|
||||
return SMTP_USER_PURCHASE;
|
||||
}
|
||||
return SMTP_USER; // 기본값: ERP
|
||||
}
|
||||
|
||||
public static String getSmtpUserPw(String accountType) {
|
||||
if (ACCOUNT_TYPE_SALES.equals(accountType)) {
|
||||
return SMTP_USER_PW_SALES;
|
||||
} else if (ACCOUNT_TYPE_PURCHASE.equals(accountType)) {
|
||||
return SMTP_USER_PW_PURCHASE;
|
||||
}
|
||||
return SMTP_USER_PW; // 기본값: ERP
|
||||
}
|
||||
|
||||
public static String getSmtpHost(String accountType) {
|
||||
if (ACCOUNT_TYPE_SALES.equals(accountType)) {
|
||||
return SMTP_HOST_SALES;
|
||||
} else if (ACCOUNT_TYPE_PURCHASE.equals(accountType)) {
|
||||
return SMTP_HOST_PURCHASE;
|
||||
}
|
||||
return SMTP_HOST; // 기본값: ERP
|
||||
}
|
||||
|
||||
public static int getSmtpPort(String accountType) {
|
||||
if (ACCOUNT_TYPE_SALES.equals(accountType)) {
|
||||
return SMTP_PORT_SALES;
|
||||
} else if (ACCOUNT_TYPE_PURCHASE.equals(accountType)) {
|
||||
return SMTP_PORT_PURCHASE;
|
||||
}
|
||||
return SMTP_PORT; // 기본값: ERP
|
||||
}
|
||||
}
|
||||
|
||||
//스마트공장 사후관리시스템 로그 수집 API key
|
||||
|
||||
@@ -545,7 +545,7 @@ public class MailUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일포함 메일전송
|
||||
* 파일포함 메일전송 (기본 ERP 계정 사용)
|
||||
* @author 악당밧밧이
|
||||
* @param fromUserId 보내는사람ID
|
||||
* @param fromEmail 보내는사람Email주소
|
||||
@@ -566,23 +566,58 @@ public class MailUtil {
|
||||
, ArrayList<HashMap> attachFileList
|
||||
, String mailType
|
||||
) {
|
||||
// 기본 ERP 계정 사용
|
||||
return sendMailWithAttachFile(fromUserId, fromEmail, toUserIdList, toEmailList, ccEmailList, bccEmailList,
|
||||
important, subject, contents, attachFileList, mailType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일포함 메일전송 (계정 타입 지정 가능)
|
||||
* @param fromUserId 보내는사람ID
|
||||
* @param fromEmail 보내는사람Email주소
|
||||
* @param toUserIdList 받는사람ID목록
|
||||
* @param toEmailList 받는사람Email목록
|
||||
* @param ccEmailList 참조Email목록
|
||||
* @param bccEmailList 숨은참조Email목록
|
||||
* @param important 메일중요구분(normal | ??? )
|
||||
* @param subject 메일제목
|
||||
* @param contents 메일내용
|
||||
* @param attachFileList 메일첨부파일목록
|
||||
* @param mailType 업무구분
|
||||
* @param accountType SMTP 계정 타입 (Constants.Mail.ACCOUNT_TYPE_ERP/SALES/PURCHASE)
|
||||
* @return
|
||||
*/
|
||||
public static boolean sendMailWithAttachFile(String fromUserId, String fromEmail
|
||||
, ArrayList<String> toUserIdList, ArrayList<String> toEmailList, ArrayList<String> ccEmailList, ArrayList<String> bccEmailList
|
||||
, String important, String subject, String contents
|
||||
, ArrayList<HashMap> attachFileList
|
||||
, String mailType
|
||||
, String accountType
|
||||
) {
|
||||
|
||||
if(Constants.Mail.sendMailSwitch == false){
|
||||
System.out.println("MailUtil.sendMailaddAttachFile ::: Constants.Mail.sendMailSwitch is FALSE");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 계정 타입에 따른 SMTP 정보 결정
|
||||
final String smtpUser = Constants.Mail.getSmtpUser(accountType);
|
||||
final String smtpUserPw = Constants.Mail.getSmtpUserPw(accountType);
|
||||
final String smtpHost = Constants.Mail.getSmtpHost(accountType);
|
||||
final int smtpPort = Constants.Mail.getSmtpPort(accountType);
|
||||
|
||||
try {
|
||||
/*변수 초기화*/
|
||||
fromUserId = CommonUtils.checkNull(fromUserId, "admin");
|
||||
fromEmail = Constants.Mail.SMTP_USER; //fromEmail : SMTP설정계정 외 다른주소 지정불가
|
||||
//fromEmail = CommonUtils.checkNull(fromEmail, Constants.Mail.SMTP_USER); //fromEmail : SMTP설정계정 외 다른주소 지정불가
|
||||
fromEmail = smtpUser; //fromEmail : SMTP설정계정 외 다른주소 지정불가
|
||||
important = CommonUtils.checkNull(important); //중요도
|
||||
subject = CommonUtils.checkNull(subject , "empty subject" ); //제목
|
||||
contents = CommonUtils.checkNull(contents, "empty contents"); //내용
|
||||
mailType = CommonUtils.checkNull(mailType, "empty mailType");
|
||||
|
||||
System.out.println("MailUtil.sendMailaddAttachFile()..");
|
||||
System.out.println("MailUtil.sendMailaddAttachFile(accountType ):"+accountType);
|
||||
System.out.println("MailUtil.sendMailaddAttachFile(smtpUser ):"+smtpUser);
|
||||
System.out.println("MailUtil.sendMailaddAttachFile(fromUserId ):"+fromUserId);
|
||||
System.out.println("MailUtil.sendMailaddAttachFile(fromEmail ):"+fromEmail);
|
||||
System.out.println("MailUtil.sendMailaddAttachFile(toUserIdList):"+toUserIdList);
|
||||
@@ -597,8 +632,8 @@ public class MailUtil {
|
||||
|
||||
//◆◆◆ 1. mail session ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆
|
||||
Properties prop = new Properties();
|
||||
prop.put("mail.smtp.host", Constants.Mail.SMTP_HOST);
|
||||
prop.put("mail.smtp.port", Constants.Mail.SMTP_PORT);
|
||||
prop.put("mail.smtp.host", smtpHost);
|
||||
prop.put("mail.smtp.port", smtpPort);
|
||||
prop.put("mail.smtp.auth" , "true");
|
||||
prop.put("mail.debug" , "true");
|
||||
prop.put("mail.transport.protocol" , "smtp");
|
||||
@@ -608,11 +643,11 @@ public class MailUtil {
|
||||
// hiworks SSL 설정 (포트 465)
|
||||
//prop.put("mail.smtp.ssl.enable" , "true");
|
||||
//prop.put("mail.smtp.socketFactory.class" , "javax.net.ssl.SSLSocketFactory");
|
||||
//prop.put("mail.smtp.socketFactory.port" , Constants.Mail.SMTP_PORT);
|
||||
//prop.put("mail.smtp.socketFactory.port" , smtpPort);
|
||||
|
||||
Session mailSession = Session.getInstance(prop, new javax.mail.Authenticator() {
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(Constants.Mail.SMTP_USER, Constants.Mail.SMTP_USER_PW);
|
||||
return new PasswordAuthentication(smtpUser, smtpUserPw);
|
||||
}
|
||||
});
|
||||
mailSession.setDebug(true);
|
||||
@@ -769,7 +804,7 @@ public class MailUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF-8 인코딩으로 메일 발송 (견적서 등 한글 내용이 많은 경우)
|
||||
* UTF-8 인코딩으로 메일 발송 (견적서 등 한글 내용이 많은 경우) - 기본 ERP 계정 사용
|
||||
* 기존 sendMailWithAttachFile과 동일하지만 UTF-8 인코딩 사용
|
||||
*/
|
||||
public static boolean sendMailWithAttachFileUTF8(String fromUserId, String fromEmail
|
||||
@@ -778,13 +813,13 @@ public class MailUtil {
|
||||
, ArrayList<HashMap> attachFileList
|
||||
, String mailType
|
||||
) {
|
||||
// 기본적으로 실제 제목을 mail_log에도 사용
|
||||
// 기본적으로 실제 제목을 mail_log에도 사용, 기본 ERP 계정 사용
|
||||
return sendMailWithAttachFileUTF8(fromUserId, fromEmail, toUserIdList, toEmailList, ccEmailList, bccEmailList,
|
||||
important, subject, contents, attachFileList, mailType, subject);
|
||||
important, subject, contents, attachFileList, mailType, subject, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 메일 발송 (UTF-8, 파일 첨부 가능) - mail_log용 제목 별도 지정 가능
|
||||
* 메일 발송 (UTF-8, 파일 첨부 가능) - mail_log용 제목 별도 지정 가능, 기본 ERP 계정 사용
|
||||
*/
|
||||
public static boolean sendMailWithAttachFileUTF8(String fromUserId, String fromEmail
|
||||
, ArrayList<String> toUserIdList, ArrayList<String> toEmailList, ArrayList<String> ccEmailList, ArrayList<String> bccEmailList
|
||||
@@ -793,16 +828,39 @@ public class MailUtil {
|
||||
, String mailType
|
||||
, String subjectForLog // mail_log에 저장될 제목 (OBJID 포함)
|
||||
) {
|
||||
// 기본 ERP 계정 사용
|
||||
return sendMailWithAttachFileUTF8(fromUserId, fromEmail, toUserIdList, toEmailList, ccEmailList, bccEmailList,
|
||||
important, subject, contents, attachFileList, mailType, subjectForLog, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 메일 발송 (UTF-8, 파일 첨부 가능) - 계정 타입 지정 가능
|
||||
* @param accountType SMTP 계정 타입 (Constants.Mail.ACCOUNT_TYPE_ERP/SALES/PURCHASE)
|
||||
*/
|
||||
public static boolean sendMailWithAttachFileUTF8(String fromUserId, String fromEmail
|
||||
, ArrayList<String> toUserIdList, ArrayList<String> toEmailList, ArrayList<String> ccEmailList, ArrayList<String> bccEmailList
|
||||
, String important, String subject, String contents
|
||||
, ArrayList<HashMap> attachFileList
|
||||
, String mailType
|
||||
, String subjectForLog // mail_log에 저장될 제목 (OBJID 포함)
|
||||
, String accountType // SMTP 계정 타입
|
||||
) {
|
||||
|
||||
if(Constants.Mail.sendMailSwitch == false){
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8 ::: Constants.Mail.sendMailSwitch is FALSE");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 계정 타입에 따른 SMTP 정보 결정
|
||||
final String smtpUser = Constants.Mail.getSmtpUser(accountType);
|
||||
final String smtpUserPw = Constants.Mail.getSmtpUserPw(accountType);
|
||||
final String smtpHost = Constants.Mail.getSmtpHost(accountType);
|
||||
final int smtpPort = Constants.Mail.getSmtpPort(accountType);
|
||||
|
||||
try {
|
||||
/*변수 초기화*/
|
||||
fromUserId = CommonUtils.checkNull(fromUserId, "admin");
|
||||
fromEmail = Constants.Mail.SMTP_USER;
|
||||
fromEmail = smtpUser;
|
||||
important = CommonUtils.checkNull(important);
|
||||
subject = CommonUtils.checkNull(subject , "empty subject" );
|
||||
contents = CommonUtils.checkNull(contents, "empty contents");
|
||||
@@ -814,6 +872,8 @@ public class MailUtil {
|
||||
}
|
||||
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8()..");
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8(accountType ):"+accountType);
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8(smtpUser ):"+smtpUser);
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8(fromUserId ):"+fromUserId);
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8(fromEmail ):"+fromEmail);
|
||||
System.out.println("MailUtil.sendMailWithAttachFileUTF8(toEmailList ):"+toEmailList);
|
||||
@@ -824,8 +884,8 @@ public class MailUtil {
|
||||
|
||||
//◆◆◆ 1. mail session ◆◆◆
|
||||
Properties prop = new Properties();
|
||||
prop.put("mail.smtp.host", Constants.Mail.SMTP_HOST);
|
||||
prop.put("mail.smtp.port", Constants.Mail.SMTP_PORT);
|
||||
prop.put("mail.smtp.host", smtpHost);
|
||||
prop.put("mail.smtp.port", smtpPort);
|
||||
prop.put("mail.smtp.auth" , "true");
|
||||
prop.put("mail.debug" , "true");
|
||||
prop.put("mail.transport.protocol" , "smtp");
|
||||
@@ -835,11 +895,11 @@ public class MailUtil {
|
||||
// hiworks SSL 설정 (포트 465)
|
||||
//prop.put("mail.smtp.ssl.enable" , "true");
|
||||
//prop.put("mail.smtp.socketFactory.class" , "javax.net.ssl.SSLSocketFactory");
|
||||
//prop.put("mail.smtp.socketFactory.port" , Constants.Mail.SMTP_PORT);
|
||||
//prop.put("mail.smtp.socketFactory.port" , smtpPort);
|
||||
|
||||
Session mailSession = Session.getInstance(prop, new javax.mail.Authenticator() {
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(Constants.Mail.SMTP_USER, Constants.Mail.SMTP_USER_PW);
|
||||
return new PasswordAuthentication(smtpUser, smtpUserPw);
|
||||
}
|
||||
});
|
||||
mailSession.setDebug(true);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.pms.controller;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -11,6 +12,7 @@ import javax.servlet.http.HttpSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@@ -2106,11 +2108,73 @@ public class PurchaseOrderController {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* PDF 청크 업로드 (AJAX)
|
||||
* @param request
|
||||
* @param paramMap - sessionId, chunkIndex, totalChunks, chunk
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value="/purchaseOrder/uploadPdfChunk.do", method=RequestMethod.POST)
|
||||
public Map uploadPdfChunk(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
String sessionId = CommonUtils.checkNull(paramMap.get("sessionId"));
|
||||
int chunkIndex = Integer.parseInt(CommonUtils.checkNull(paramMap.get("chunkIndex"), "0"));
|
||||
int totalChunks = Integer.parseInt(CommonUtils.checkNull(paramMap.get("totalChunks"), "1"));
|
||||
String chunk = CommonUtils.checkNull(paramMap.get("chunk"));
|
||||
|
||||
// 임시 디렉토리에 청크 저장
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
File chunkFile = new File(tempDir + File.separator + sessionId + "_chunk_" + chunkIndex);
|
||||
|
||||
// 청크 데이터 저장
|
||||
java.io.FileOutputStream fos = new java.io.FileOutputStream(chunkFile);
|
||||
fos.write(chunk.getBytes("UTF-8"));
|
||||
fos.close();
|
||||
|
||||
// 모든 청크가 업로드되면 합치기
|
||||
if(chunkIndex == totalChunks - 1) {
|
||||
StringBuilder fullBase64 = new StringBuilder();
|
||||
for(int i = 0; i < totalChunks; i++) {
|
||||
File cf = new File(tempDir + File.separator + sessionId + "_chunk_" + i);
|
||||
if(cf.exists()) {
|
||||
byte[] data = java.nio.file.Files.readAllBytes(cf.toPath());
|
||||
fullBase64.append(new String(data, "UTF-8"));
|
||||
cf.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Base64 디코딩하여 PDF 파일 생성 (Apache Commons Codec 사용 - Java 7 호환)
|
||||
byte[] pdfBytes = org.apache.commons.codec.binary.Base64.decodeBase64(fullBase64.toString());
|
||||
File pdfFile = new File(tempDir + File.separator + sessionId + ".pdf");
|
||||
java.io.FileOutputStream pdfFos = new java.io.FileOutputStream(pdfFile);
|
||||
pdfFos.write(pdfBytes);
|
||||
pdfFos.close();
|
||||
|
||||
pdfFile.deleteOnExit();
|
||||
|
||||
System.out.println("발주서 PDF 파일 생성 완료: " + pdfFile.getAbsolutePath() + " (" + pdfBytes.length + " bytes)");
|
||||
}
|
||||
|
||||
resultMap.put("result", "success");
|
||||
resultMap.put("chunkIndex", chunkIndex);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", "error");
|
||||
resultMap.put("message", "청크 업로드 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 발주서 메일 발송 (AJAX)
|
||||
* @param session
|
||||
* @param request
|
||||
* @param paramMap - objId, toEmails, ccEmails, subject, contents
|
||||
* @param paramMap - objId, pdfSessionId, toEmails, ccEmails, subject, contents
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
|
||||
@@ -696,6 +696,15 @@ public class QualityController {
|
||||
return service.lockSemiProductInspection(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 반제품검사 잠금 해제
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/quality/unlockSemiProductInspection.do")
|
||||
public Map unlockSemiProductInspection(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
return service.unlockSemiProductInspection(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 반제품검사 엑셀 다운로드 (JSP 방식)
|
||||
*/
|
||||
|
||||
@@ -1429,6 +1429,9 @@
|
||||
|
||||
-- 요청사항
|
||||
,POM.REQUEST_CONTENT
|
||||
|
||||
-- 양식 타입 (general/outsourcing)
|
||||
,COALESCE(POM.FORM_TYPE, 'general') AS FORM_TYPE
|
||||
FROM
|
||||
PURCHASE_ORDER_MASTER POM
|
||||
|
||||
|
||||
@@ -1802,6 +1802,13 @@
|
||||
WHERE OBJID = #{OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 반제품검사 행 잠금 해제 (IS_LOCKED = 'N') -->
|
||||
<update id="unlockSemiProductInspection" parameterType="map">
|
||||
UPDATE PMS_QUALITY_SEMI_PRODUCT_INSPECTION
|
||||
SET IS_LOCKED = 'N'
|
||||
WHERE OBJID = #{OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 반제품검사 데이터 삭제 (OBJID로 단건 삭제) -->
|
||||
<delete id="deleteSemiProductInspectionByObjId" parameterType="map">
|
||||
DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
|
||||
|
||||
@@ -1924,6 +1924,7 @@ public class ContractMgmtService {
|
||||
boolean mailSent = false;
|
||||
try {
|
||||
// UTF-8 인코딩 메서드 사용 (견적서는 한글 내용이 많음)
|
||||
// 영업팀 계정(SALES) 사용
|
||||
mailSent = MailUtil.sendMailWithAttachFileUTF8(
|
||||
fromUserId,
|
||||
null, // fromEmail (자동으로 SMTP 설정 사용)
|
||||
@@ -1936,7 +1937,8 @@ public class ContractMgmtService {
|
||||
contents,
|
||||
attachFileList.size() > 0 ? attachFileList : null, // PDF 첨부
|
||||
"CONTRACT_ESTIMATE",
|
||||
subjectForLog // mail_log용 제목 (OBJID 포함)
|
||||
subjectForLog, // mail_log용 제목 (OBJID 포함)
|
||||
Constants.Mail.ACCOUNT_TYPE_SALES // 영업팀 계정 사용
|
||||
);
|
||||
|
||||
System.out.println("메일 발송 결과: " + mailSent);
|
||||
@@ -3633,6 +3635,7 @@ private String encodeImageToBase64(String imagePath) {
|
||||
|
||||
boolean mailSent = false;
|
||||
try {
|
||||
// 영업팀 계정(SALES) 사용
|
||||
mailSent = MailUtil.sendMailWithAttachFileUTF8(
|
||||
fromUserId,
|
||||
null, // fromEmail (자동으로 SMTP 설정 사용)
|
||||
@@ -3645,7 +3648,8 @@ private String encodeImageToBase64(String imagePath) {
|
||||
htmlContents,
|
||||
attachFileList.size() > 0 ? attachFileList : null,
|
||||
"CONTRACT_ESTIMATE",
|
||||
subjectForLog // mail_log용 제목 (OBJID 포함)
|
||||
subjectForLog, // mail_log용 제목 (OBJID 포함)
|
||||
Constants.Mail.ACCOUNT_TYPE_SALES // 영업팀 계정 사용
|
||||
);
|
||||
|
||||
System.out.println("메일 발송 결과: " + mailSent);
|
||||
|
||||
@@ -2955,6 +2955,7 @@ public class PurchaseOrderService {
|
||||
|
||||
try {
|
||||
String targetObjId = CommonUtils.checkNull(paramMap.get("objId"));
|
||||
String pdfSessionId = CommonUtils.checkNull(paramMap.get("pdfSessionId")); // PDF 세션 ID 추가
|
||||
String toEmails = CommonUtils.checkNull(paramMap.get("toEmails"));
|
||||
String ccEmails = CommonUtils.checkNull(paramMap.get("ccEmails"));
|
||||
String subject = CommonUtils.checkNull(paramMap.get("subject"));
|
||||
@@ -2987,9 +2988,7 @@ public class PurchaseOrderService {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
String todayKor = frm.format(cal.getTime());
|
||||
String poNo = CommonUtils.checkNull((String)masterInfo.get("PURCHASE_ORDER_NO"));
|
||||
String excelName = "발주서_" + poNo + "_" + todayKor + ".xls";
|
||||
String zipName = "도면_" + poNo + "_" + todayKor + ".zip";
|
||||
masterInfo.put("EXCELFILE_NAME", excelName);
|
||||
masterInfo.put("APPR_COMPLETE_DATE", frm2.format(cal.getTime()));
|
||||
|
||||
// 발주서 테이블 내용 생성
|
||||
@@ -3029,11 +3028,30 @@ public class PurchaseOrderService {
|
||||
// 첨부파일 목록 생성
|
||||
ArrayList<HashMap> attachFileList = new ArrayList<HashMap>();
|
||||
|
||||
// 1. 발주서 PDF 파일 첨부
|
||||
if(!"".equals(pdfSessionId)) {
|
||||
File pdfFile = getPdfFromSession(pdfSessionId, poNo);
|
||||
if(pdfFile != null && pdfFile.exists()) {
|
||||
HashMap<String, String> pdfFileMap = new HashMap<String, String>();
|
||||
pdfFileMap.put(Constants.Db.COL_FILE_REAL_NAME, pdfFile.getName());
|
||||
pdfFileMap.put(Constants.Db.COL_FILE_SAVED_NAME, pdfFile.getName());
|
||||
pdfFileMap.put(Constants.Db.COL_FILE_PATH, pdfFile.getParent());
|
||||
attachFileList.add(pdfFileMap);
|
||||
System.out.println("발주서 PDF 파일 첨부 완료: " + pdfFile.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("발주서 PDF 파일을 찾을 수 없습니다: " + pdfSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/* 엑셀 첨부 주석처리 - PDF로 대체
|
||||
// 1. 발주서 엑셀 파일 첨부
|
||||
String excelName = "발주서_" + poNo + "_" + todayKor + ".xls";
|
||||
masterInfo.put("EXCELFILE_NAME", excelName);
|
||||
HashMap excelFile = this.makeMailAttachFileOrderSheet(masterInfo, contents_table);
|
||||
if(excelFile != null) {
|
||||
attachFileList.add(excelFile);
|
||||
}
|
||||
*/
|
||||
|
||||
// 2. 도면 파일 압축 첨부
|
||||
if(partFileList != null && partFileList.size() > 0) {
|
||||
@@ -3043,7 +3061,7 @@ public class PurchaseOrderService {
|
||||
hm.put(Constants.Db.COL_FILE_REAL_NAME, zf.getName());
|
||||
hm.put(Constants.Db.COL_FILE_SAVED_NAME, zf.getName());
|
||||
// 파일 경로에서 파일명을 제거하고 디렉토리 경로만 추출 (OS 독립적)
|
||||
hm.put(Constants.Db.COL_FILE_PATH, zf.getParent());
|
||||
hm.put(Constants.Db.COL_FILE_PATH, zf.getParent());
|
||||
attachFileList.add(hm);
|
||||
}
|
||||
}
|
||||
@@ -3058,7 +3076,8 @@ public class PurchaseOrderService {
|
||||
fromUser = CommonUtils.checkNull((String)masterInfo.get("WRITER"));
|
||||
}
|
||||
|
||||
boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER");
|
||||
// 구매팀 계정(PURCHASE) 사용
|
||||
boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_PURCHASE);
|
||||
|
||||
if(sendResult) {
|
||||
// 메일 발송 성공 시 DB 업데이트
|
||||
@@ -3119,6 +3138,7 @@ public class PurchaseOrderService {
|
||||
sb.append(userContents.replace("\n", "<br>"));
|
||||
sb.append("</div>");
|
||||
|
||||
/* 발주서 테이블 본문 표시 주석처리 - PDF 첨부로 대체
|
||||
// 구분선
|
||||
sb.append("<hr style='border: 1px solid #ddd; margin: 20px 0;'>");
|
||||
|
||||
@@ -3127,6 +3147,7 @@ public class PurchaseOrderService {
|
||||
sb.append("<h3 style='margin-bottom: 10px;'>[ 발주서 상세 ]</h3>");
|
||||
sb.append(poContentsTable);
|
||||
sb.append("</div>");
|
||||
*/
|
||||
|
||||
sb.append("<div style='margin-top: 20px; color: #666;'>※발신전용 메일입니다.</div>");
|
||||
sb.append("</body>");
|
||||
@@ -3177,4 +3198,45 @@ public class PurchaseOrderService {
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 ID로 저장된 PDF 파일 가져오기
|
||||
* @param sessionId PDF 세션 ID
|
||||
* @param poNo 발주번호 (파일명에 사용)
|
||||
* @return PDF 파일
|
||||
*/
|
||||
private File getPdfFromSession(String sessionId, String poNo) {
|
||||
try {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
File pdfFile = new File(tempDir + File.separator + sessionId + ".pdf");
|
||||
|
||||
if(pdfFile.exists()) {
|
||||
// 발주번호로 파일명 변경
|
||||
if("".equals(poNo)) poNo = "발주서";
|
||||
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String timestamp = sdf.format(new java.util.Date());
|
||||
String newFileName = "발주서_" + poNo + "_" + timestamp + ".pdf";
|
||||
File renamedFile = new File(tempDir + File.separator + newFileName);
|
||||
|
||||
// 파일 복사
|
||||
java.nio.file.Files.copy(pdfFile.toPath(), renamedFile.toPath(),
|
||||
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
renamedFile.deleteOnExit();
|
||||
|
||||
// 원본 파일 삭제
|
||||
pdfFile.delete();
|
||||
|
||||
return renamedFile;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch(Exception e) {
|
||||
System.out.println("PDF 파일 가져오기 중 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1086,6 +1086,46 @@ public class QualityService extends BaseService{
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 반제품검사 행 잠금 해제 (IS_LOCKED = 'N')
|
||||
*/
|
||||
public Map unlockSemiProductInspection(Map paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
SqlSession sqlSession = null;
|
||||
try{
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
String objIdsJson = CommonUtils.checkNull(paramMap.get("objIds"));
|
||||
|
||||
if(!objIdsJson.equals("") && !objIdsJson.equals("[]")){
|
||||
org.json.simple.parser.JSONParser parser = new org.json.simple.parser.JSONParser();
|
||||
org.json.simple.JSONArray objIdArr = (org.json.simple.JSONArray) parser.parse(objIdsJson);
|
||||
|
||||
for(int i = 0; i < objIdArr.size(); i++){
|
||||
String objId = CommonUtils.checkNull(objIdArr.get(i));
|
||||
if(!objId.equals("")){
|
||||
Map unlockParam = new HashMap();
|
||||
unlockParam.put("OBJID", objId);
|
||||
sqlSession.update("quality.unlockSemiProductInspection", unlockParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
resultMap.put("result", true);
|
||||
resultMap.put("msg", "잠금 해제되었습니다.");
|
||||
|
||||
}catch(Exception e){
|
||||
resultMap.put("result", false);
|
||||
resultMap.put("msg", "잠금 해제에 실패했습니다.");
|
||||
if(sqlSession != null) sqlSession.rollback();
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 반제품검사 삭제 (OBJID 목록으로 삭제)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user