Compare commits

...

5 Commits

14 changed files with 1011 additions and 49 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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(),

View File

@@ -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에 저장하고 수정 불가로 변경
// =====================================================

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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 방식)
*/

View File

@@ -1429,6 +1429,9 @@
-- 요청사항
,POM.REQUEST_CONTENT
-- 양식 타입 (general/outsourcing)
,COALESCE(POM.FORM_TYPE, 'general') AS FORM_TYPE
FROM
PURCHASE_ORDER_MASTER POM

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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 목록으로 삭제)
*/