From 8b3c8b182c8e95a243b3d4d72599d37b2e2be558 Mon Sep 17 00:00:00 2001 From: leeheejin Date: Mon, 10 Nov 2025 12:17:16 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A4=91=EA=B0=84=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WEB-INF/view/common/FileRegistPopup.jsp | 30 +- WebContent/WEB-INF/view/common/download.jsp | 52 ++- .../contractMgmt/orderRegistFormPopup.jsp | 99 ++-- .../view/contractMgmt/supplyMngList.jsp | 82 +++- .../view/contractMgmt/supplyMngList_back.jsp | 158 +++++-- .../view/contractMgmt/supplyRegistPopUp.jsp | 433 ++++++++++++++++-- compile_only.sh | 5 +- .../add_manager_columns_to_supply_mng.sql | 24 + src/com/pms/common/FileRenameClass.java | 28 +- .../controller/ContractMgmtController.java | 18 +- src/com/pms/salesmgmt/mapper/contractMgmt.xml | 221 +++++---- .../service/ContractMgmtService.java | 80 ++++ 12 files changed, 986 insertions(+), 244 deletions(-) create mode 100644 database/add_manager_columns_to_supply_mng.sql diff --git a/WebContent/WEB-INF/view/common/FileRegistPopup.jsp b/WebContent/WEB-INF/view/common/FileRegistPopup.jsp index 6d5edb4..feadfb1 100644 --- a/WebContent/WEB-INF/view/common/FileRegistPopup.jsp +++ b/WebContent/WEB-INF/view/common/FileRegistPopup.jsp @@ -49,6 +49,11 @@ function refeshAttachFileArea(){ } } +// PDF 미리보기 - 브라우저 새 탭에서 직접 열기 +function fnc_viewPdfFile(fileObjId){ + window.open("/common/downloadFile.do?objId="+fileObjId, "_blank"); +} + //형상 영역을 display 한다. function srAreaDraw(){ fn_fileCallback("sr","${docType}"); @@ -113,17 +118,22 @@ function fn_fileCallback(areaId,fileType){ appendText +=" "; appendText +=" "; */ - appendText+= ""; - appendText+= " "+[i+1]+""; + appendText+= ""; + appendText+= " "+[i+1]+""; + // PDF 파일이면 뷰어로, 아니면 다운로드 + if(fileExt == 'PDF'){ + appendText+= "   "+data[i].REAL_FILE_NAME+""; + }else{ appendText+= "   "+data[i].REAL_FILE_NAME+""; - if(data[i].WRITER=="${connectUserId}" || 'plm_admin'== "${connectUserId}" || DOC_TYPE.indexOf("CAD") > -1){ //240409 설계파일 권한 해제 fileExt == 'DWG' && - appendText+= "
"; - } - - appendText+= ""; - appendText+= " "+data[i].REGDATE+"" - appendText+= " "+data[i].FILE_SIZE+"" - appendText+= ""; + } + if(data[i].WRITER=="${connectUserId}" || 'plm_admin'== "${connectUserId}" || DOC_TYPE.indexOf("CAD") > -1){ //240409 설계파일 권한 해제 fileExt == 'DWG' && + appendText+= "
"; + } + + appendText+= ""; + appendText+= " "+data[i].REGDATE+"" + appendText+= " "+data[i].FILE_SIZE+"" + appendText+= ""; fileList.push(fileName); } diff --git a/WebContent/WEB-INF/view/common/download.jsp b/WebContent/WEB-INF/view/common/download.jsp index 20e401b..acbe1e5 100644 --- a/WebContent/WEB-INF/view/common/download.jsp +++ b/WebContent/WEB-INF/view/common/download.jsp @@ -1,7 +1,4 @@ -<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%> -<%@ page import="java.util.*, java.io.*" %> -<%@include file= "/init.jsp" %> -<% +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ page import="java.util.*, java.io.*"%><%@include file="/init.jsp"%><% HashMap map = (HashMap)request.getAttribute("FILE_MAP"); if(map == null) map = new HashMap(); @@ -20,10 +17,32 @@ if(!"".equals(realFileName)){ realFileName = (java.net.URLEncoder.encode(realFileName, "UTF-8")).replaceAll("\\+", " "); } -String fullFilePath = filePath+"\\"+savedFileName; +// 파일 경로 생성 +// savedFileName이 구분자로 시작하면 그대로 합치고, 아니면 구분자 추가 +String fullFilePath = ""; +if(savedFileName.startsWith("/") || savedFileName.startsWith("\\")){ + fullFilePath = filePath + savedFileName; +} else { + fullFilePath = filePath + File.separator + savedFileName; +} System.out.println("fullFilePath : "+fullFilePath); +System.out.println("filePath : "+filePath); +System.out.println("savedFileName : "+savedFileName); +System.out.println("realFileName : "+realFileName); -File f = new File(fullFilePath); +File f = new File(fullFilePath); + +// 파일이 없으면 기존 방식(역슬래시 포함)으로 시도 +if(!f.exists()){ + String legacyFilePath = filePath + "\\" + savedFileName; + System.out.println("Trying legacy path : "+legacyFilePath); + File legacyFile = new File(legacyFilePath); + if(legacyFile.exists()){ + f = legacyFile; + fullFilePath = legacyFilePath; + System.out.println("Found with legacy path!"); + } +} if(f.exists()){ int filesize = (int)f.length(); @@ -36,8 +55,15 @@ if(f.exists()){ //response.setContentType("text/plain; charset=EUC_KR"); //response.setContentType("application/x-msdownload"); - response.setContentType("application/octet-stream;charset=euc-kr"); - response.setHeader("Content-Disposition", "attachment; filename="+ realFileName); + + // PDF 파일이면 미리보기 모드로 + if("PDF".equalsIgnoreCase(fileExt)){ + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition", "inline; filename="+ realFileName); + }else{ + response.setContentType("application/octet-stream;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment; filename="+ realFileName); + } FileInputStream fin = new java.io.FileInputStream(f); BufferedInputStream bis = new BufferedInputStream(fin); ServletOutputStream fout = response.getOutputStream(); @@ -62,13 +88,11 @@ if(f.exists()){ //file download log 2015-12-22 jmpark end } catch( IOException e){ - response.setContentType("text/html; charset=EUC_KR"); + response.setContentType("text/html; charset=UTF-8"); out.println("Error : "+e.getMessage()); } }else{ - response.setContentType("text/html; charset=EUC_KR"); + response.setContentType("text/html; charset=UTF-8"); out.println("File Not Found : " + fullFilePath); -} - - -%> +} +%> \ No newline at end of file diff --git a/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp b/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp index 1d6eb60..c3cce38 100644 --- a/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp @@ -48,16 +48,23 @@ var itemList = []; $(function() { + // console.log("===== 수주등록 팝업 로드됨 ====="); + // console.log("useEstimateTemplate 값:", "${useEstimateTemplate}"); + // 숫자 입력 필드에 콤마 자동 추가 및 금액 계산 $(document).on("keyup", "input:text[numberOnly]", function() { $(this).val(addComma($(this).val().replace(/[^0-9]/g, ""))); - // 수주수량 또는 수주단가가 변경되면 자동 계산 - if($(this).hasClass("item-quantity") || $(this).hasClass("item-unit-price")) { - var itemId = $(this).closest("tr").attr("id"); - if(itemId) { + var itemId = $(this).closest("tr").attr("id"); + if(itemId) { + // 수주수량 또는 수주단가가 변경되면 공급가액, 부가세, 총액 모두 재계산 + if($(this).hasClass("item-quantity") || $(this).hasClass("item-unit-price")) { fn_calculateItemAmount(itemId); } + // 수주부가세만 변경되면 총액만 재계산 + else if($(this).hasClass("item-vat")) { + fn_calculateTotalFromVat(itemId); + } } }); @@ -136,33 +143,60 @@ }); } - // 품목별 금액 계산 (수량 × 단가 = 공급가액, 공급가액 × 10% = 부가세, 공급가액 + 부가세 = 총액) + // 품목별 금액 계산 + // 수량 × 단가 = 공급가액 (자동) + // 부가세 입력 가능 (기본값: 공급가액 × 10%) + // 공급가액 + 부가세 = 총액 (자동) function fn_calculateItemAmount(itemId) { var quantity = parseInt(removeComma($("#" + itemId + " .item-quantity").val())) || 0; var unitPrice = parseInt(removeComma($("#" + itemId + " .item-unit-price").val())) || 0; + // 공급가액 계산 var supplyPrice = quantity * unitPrice; - var vat = Math.round(supplyPrice * 0.1); - var totalAmount = supplyPrice + vat; - $("#" + itemId + " .item-supply-price").val(addComma(supplyPrice)); + + // 부가세 자동 계산 (공급가액의 10%) + var vat = Math.round(supplyPrice * 0.1); $("#" + itemId + " .item-vat").val(addComma(vat)); + + // 총액 계산 + var totalAmount = supplyPrice + vat; + $("#" + itemId + " .item-total-amount").val(addComma(totalAmount)); + } + + // 부가세 직접 입력 시 총액만 재계산 + function fn_calculateTotalFromVat(itemId) { + var supplyPrice = parseInt(removeComma($("#" + itemId + " .item-supply-price").val())) || 0; + var vat = parseInt(removeComma($("#" + itemId + " .item-vat").val())) || 0; + + // 총액 계산 + var totalAmount = supplyPrice + vat; $("#" + itemId + " .item-total-amount").val(addComma(totalAmount)); } - // 기존 품목 데이터 로드 (CONTRACT_ITEM 테이블에서) + // 기존 품목 데이터 로드 (결재완료 시 ESTIMATE_TEMPLATE_ITEM, 아니면 CONTRACT_ITEM) function fn_loadContractItems() { var contractObjId = $("#contractObjId").val(); if(!contractObjId || contractObjId === '') { return; } + // 결재완료 상태인지 확인 + var useEstimateTemplate = "${useEstimateTemplate}"; + // console.log("=== 품목 로드 디버깅 ==="); + // console.log("contractObjId:", contractObjId); + // console.log("useEstimateTemplate:", useEstimateTemplate); + $.ajax({ url: "/contractMgmt/getContractItems.do", type: "POST", - data: { contractObjId: contractObjId }, + data: { + contractObjId: contractObjId, + useEstimateTemplate: useEstimateTemplate + }, dataType: "json", success: function(data) { + // console.log("품목 데이터:", data); if(data && data.items && data.items.length > 0) { $("#noItemRow").remove(); @@ -180,22 +214,22 @@ } } - var html = ''; - html += '' + (i + 1) + ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += '-'; // 삭제 불가 - html += ''; - html += ''; // CONTRACT_ITEM의 OBJID - html += ''; - html += ''; // 전체 S/N - html += ''; + var html = ''; + html += '' + (i + 1) + ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; // readonly 제거 + html += ''; + html += '-'; // 삭제 불가 + html += ''; + html += ''; // CONTRACT_ITEM의 OBJID + html += ''; + html += ''; // 전체 S/N + html += ''; $("#itemListBody").append(html); @@ -208,9 +242,14 @@ // 이벤트 바인딩 (클로저 문제 해결) (function(id) { + // 수량, 단가 변경 시 → 전체 재계산 $("#" + id + " .item-quantity, #" + id + " .item-unit-price").on("change keyup", function() { fn_calculateItemAmount(id); }); + // 부가세 변경 시 → 총액만 재계산 + $("#" + id + " .item-vat").on("change keyup", function() { + fn_calculateTotalFromVat(id); + }); })(itemId); // S/N 클릭 시 전체 S/N 보기 @@ -366,10 +405,10 @@ ${code_map.contract_result} - - - - + + + + diff --git a/WebContent/WEB-INF/view/contractMgmt/supplyMngList.jsp b/WebContent/WEB-INF/view/contractMgmt/supplyMngList.jsp index fdf1d4b..86d4488 100644 --- a/WebContent/WEB-INF/view/contractMgmt/supplyMngList.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/supplyMngList.jsp @@ -64,15 +64,26 @@ var columns = [ openOEMPopUp(objid); } }, - {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : '고객구분', field : 'SUPPLY_CODE_NAME' }, - {headerHozAlign : 'center', hozAlign : 'left', width : '110', title : '지역', field : 'AREA_CD_NAME' }, + //{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : '고객구분', field : 'SUPPLY_CODE_NAME' }, + //{headerHozAlign : 'center', hozAlign : 'left', width : '110', title : '지역', field : 'AREA_CD_NAME' }, {headerHozAlign : 'center', hozAlign : 'left ', width : '200', title : '고객사', field : 'SUPPLY_NAME' }, {headerHozAlign : 'center', hozAlign : 'left', width : '120', title : '대표자명', field : 'CHARGE_USER_NAME' }, + {headerHozAlign : 'center', hozAlign : 'left', width : '120', title : '담당자', field : 'MANAGER1_NAME' }, +// {headerHozAlign : 'center', hozAlign : 'left', width : '180', title : '담당자 이메일', field : 'MANAGER1_EMAIL' }, {headerHozAlign : 'center', hozAlign : 'center', width : '130', title : '사업자등록번호', field : 'BUS_REG_NO' }, {headerHozAlign : 'center', hozAlign : 'left', /* width : '300', */ title : '주소', field : 'SUPPLY_ADDRESS' }, {headerHozAlign : 'center', hozAlign : 'center', width : '110', title : '연락처', field : 'SUPPLY_TEL_NO' }, {headerHozAlign : 'center', hozAlign : 'left', width : '240', title : 'E-MAIL', field : 'EMAIL' }, - {headerHozAlign : 'center', hozAlign : 'center', width : '110', title : '등록일', field : 'REGDATE' } + {headerHozAlign : 'center', hozAlign : 'center', width : '110', title : '등록일', field : 'REGDATE' }, + {headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '사업자등록증', field : 'BUS_REG_FILE_CNT', + formatter: function(cell, formatterParams){ + var objid = cell.getData().OBJID; + var fileCnt = cell.getData().BUS_REG_FILE_CNT || 0; + var imgSrc = fileCnt > 0 ? '/images/folder_blue.png' : '/images/file_empty.png'; + var title = fileCnt > 0 ? '사업자등록증 보기 ('+fileCnt+'개)' : '등록된 파일 없음'; + return ""; + } + } ]; //var grid; @@ -134,8 +145,8 @@ function fn_excel() { form.submit(); } function openOEMPopUp(objid){ - var popup_width = 850; - var popup_height = 330; + var popup_width = 900; + var popup_height = 700; var target = "openOEMPopUp"; fn_centerPopup(popup_width, popup_height, url, target); @@ -175,6 +186,67 @@ function fn_excel() { } } + // 사업자등록증 보기 + function viewBusRegCert(supplyObjId){ + // 파일 목록 가져오기 + $.ajax({ + url: "/common/getFileList.do", + type: "POST", + data: { + targetObjId: supplyObjId, + docType: "BUS_REG_CERT" + }, + dataType: "json", + success: function(data){ + if(data && data.length > 0){ + // 파일이 1개면 바로 새 탭에서 열기 + if(data.length === 1){ + window.open("/common/downloadFile.do?objId="+data[0].OBJID, "_blank"); + } else { + // 파일이 여러 개면 선택 팝업 표시 + showFileSelectPopup(data); + } + } else { + Swal.fire("등록된 사업자등록증이 없습니다."); + } + }, + error: function(){ + Swal.fire("파일 목록을 불러오는데 실패했습니다."); + } + }); + } + + // 여러 파일 선택 팝업 + function showFileSelectPopup(files){ + var fileListHtml = "
"; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + + $.each(files, function(i, file){ + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + }); + + fileListHtml += "
파일명등록일보기
"+file.REAL_FILE_NAME+""+file.REGDATE+""; + fileListHtml += ""; + fileListHtml += "
"; + + Swal.fire({ + title: '사업자등록증 ('+files.length+'개)', + html: fileListHtml, + width: '700px', + showCloseButton: true, + showConfirmButton: false + }); + } + diff --git a/WebContent/WEB-INF/view/contractMgmt/supplyMngList_back.jsp b/WebContent/WEB-INF/view/contractMgmt/supplyMngList_back.jsp index c38a3d2..30906b9 100644 --- a/WebContent/WEB-INF/view/contractMgmt/supplyMngList_back.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/supplyMngList_back.jsp @@ -121,8 +121,8 @@ function fn_delete(){ } function openOEMPopUp(objid){ - var popup_width = 850; - var popup_height = 330; + var popup_width = 900; + var popup_height = 700; var target = "openOEMPopUp"; fn_centerPopup(popup_width, popup_height, url, target); @@ -163,6 +163,67 @@ function fn_delete(){ } } +// 사업자등록증 보기 +function viewBusRegCert(supplyObjId){ + // 파일 목록 가져오기 + $.ajax({ + url: "/common/getFileList.do", + type: "POST", + data: { + targetObjId: supplyObjId, + docType: "BUS_REG_CERT" + }, + dataType: "json", + success: function(data){ + if(data && data.length > 0){ + // 파일이 1개면 바로 새 탭에서 열기 + if(data.length === 1){ + window.open("/common/downloadFile.do?objId="+data[0].OBJID, "_blank"); + } else { + // 파일이 여러 개면 선택 팝업 표시 + showFileSelectPopup(data); + } + } else { + Swal.fire("등록된 사업자등록증이 없습니다."); + } + }, + error: function(){ + Swal.fire("파일 목록을 불러오는데 실패했습니다."); + } + }); +} + +// 여러 파일 선택 팝업 +function showFileSelectPopup(files){ + var fileListHtml = "
"; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + + $.each(files, function(i, file){ + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + fileListHtml += ""; + }); + + fileListHtml += "
파일명등록일보기
"+file.REAL_FILE_NAME+""+file.REGDATE+""; + fileListHtml += ""; + fileListHtml += "
"; + + Swal.fire({ + title: '사업자등록증 ('+files.length+'개)', + html: fileListHtml, + width: '700px', + showCloseButton: true, + showConfirmButton: false + }); +} + function fn_search(){ var form = document.form1; form.action="/contractMgmt/supplyMngPagingList.do"; @@ -190,23 +251,23 @@ function fn_delete(){ - - - - - - - - - - - + + + + + + +<%-- ${code_map.supply_code} --%> + + + + + + + +<%-- ${code_map.area_cd} --%> + + @@ -238,19 +299,22 @@ function fn_delete(){ - - - 고객번호 - 고객구분 - 지역 - 고객사 - 대표자명 - 사업자등록번호 - 주소 - 연락처 - E-MAIL - 등록일 - + + + 고객번호 + + + 고객사 + 대표자명 + 담당자 + + 사업자등록번호 + 주소 + 연락처 + E-MAIL + 등록일 + 사업자등록증 + @@ -258,17 +322,33 @@ function fn_delete(){ - - ${oemInfo.CUS_NO} - ${oemInfo.SUPPLY_CODE_NAME} - ${oemInfo.AREA_CD_NAME} - ${oemInfo.SUPPLY_NAME} - ${oemInfo.CHARGE_USER_NAME} - ${oemInfo.BUS_REG_NO} + + ${oemInfo.CUS_NO} +<%-- ${oemInfo.SUPPLY_CODE_NAME} --%> +<%-- ${oemInfo.AREA_CD_NAME} --%> + ${oemInfo.SUPPLY_NAME} + ${oemInfo.CHARGE_USER_NAME} + ${oemInfo.MANAGER1_NAME} +<%-- ${oemInfo.MANAGER1_EMAIL} --%> + ${oemInfo.BUS_REG_NO} ${oemInfo.SUPPLY_ADDRESS} ${oemInfo.SUPPLY_TEL_NO} ${oemInfo.EMAIL} ${oemInfo.REGDATE} + + + + + + + + + + + + + + diff --git a/WebContent/WEB-INF/view/contractMgmt/supplyRegistPopUp.jsp b/WebContent/WEB-INF/view/contractMgmt/supplyRegistPopUp.jsp index fcea563..778a025 100644 --- a/WebContent/WEB-INF/view/contractMgmt/supplyRegistPopUp.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/supplyRegistPopUp.jsp @@ -16,7 +16,265 @@ self.close(); opener.fn_search(); }); + + // 사업자등록증 파일 목록 로드 + loadBusRegFile(); + + // 파일 선택 시 즉시 업로드 및 뷰어 열기 + $("#bus_reg_file").change(function(){ + var fileInput = this; + if(fileInput.files.length > 0){ + // 1개만 허용 + if(fileInput.files.length > 1){ + Swal.fire("사업자등록증은 1개만 업로드 가능합니다."); + $(this).val(""); + return; + } + + // PDF 파일만 허용 + var file = fileInput.files[0]; + if(file.type !== "application/pdf"){ + Swal.fire("PDF 파일만 업로드 가능합니다."); + $(this).val(""); + return; + } + + // 즉시 업로드 + uploadBusRegFileInstant(file); + } }); + }); + + // 선택된 파일 미리보기 + function showSelectedFiles(){ + var fileInput = $("#bus_reg_file")[0]; + var files = fileInput.files; + + if(files.length > 0){ + var selectedHtml = "
선택된 파일 ("+files.length+"개) * 저장 버튼을 눌러야 업로드됩니다
"; + for(var i = 0; i < files.length; i++){ + selectedHtml += "
"; + selectedHtml += "📄"; + selectedHtml += ""+files[i].name+""; + selectedHtml += "
"; + } + + // 기존 등록된 파일도 함께 표시 + var targetObjId = $("#objid").val(); + if(targetObjId){ + $.ajax({ + url: "/common/getFileList.do", + type: "POST", + data: { + targetObjId: targetObjId, + docType: "BUS_REG_CERT" + }, + dataType: "json", + async: false, + success: function(data){ + if(data && data.length > 0){ + selectedHtml += "
기존 등록된 파일 ("+data.length+"개)
"; + $.each(data, function(i, file){ + selectedHtml += "
"; + selectedHtml += "
"; + selectedHtml += "📄"; + selectedHtml += ""+file.REAL_FILE_NAME+""; + selectedHtml += "
"; + selectedHtml += "삭제"; + selectedHtml += "
"; + }); + } + } + }); + } + + $("#busRegFileArea").html(selectedHtml); + }else{ + loadBusRegFile(); + } + } + + // 사업자등록증 즉시 업로드 및 뷰어 열기 + function uploadBusRegFileInstant(file){ + var targetObjId = $("#objid").val(); + if(!targetObjId){ + Swal.fire("고객 정보를 먼저 저장해주세요."); + $("#bus_reg_file").val(""); + return; + } + + Swal.fire({ + title: '업로드 중...', + text: '파일을 업로드하고 있습니다.', + allowOutsideClick: false, + didOpen: () => { + Swal.showLoading(); + } + }); + + var formData = new FormData(); + formData.append("file1", file); + formData.append("targetObjId", targetObjId); + formData.append("docType", "BUS_REG_CERT"); + formData.append("docTypeName", "사업자등록증"); + + $.ajax({ + url: "/common/fileUploadProc.do", + type: "POST", + data: formData, + processData: false, + contentType: false, + success: function(response){ + Swal.close(); + $("#bus_reg_file").val(""); + + // 파일 목록 새로고침 + loadBusRegFile(); + + // 업로드 완료 메시지 (자동으로 새 탭 열지 않음) + Swal.fire({ + icon: 'success', + title: '업로드 완료', + text: '파일이 업로드되었습니다. 파일명을 클릭하면 미리보기할 수 있습니다.', + timer: 2000, + showConfirmButton: false + }); + + // 부모 창 새로고침 + if(opener && typeof opener.fn_search == "function"){ + opener.fn_search(); + } + if(opener && opener._tabulGrid){ + opener._tabulGrid.replaceData(); + } + }, + error: function(){ + Swal.fire("파일 업로드에 실패했습니다."); + $("#bus_reg_file").val(""); + } + }); + } + + // 사업자등록증 파일 업로드 (저장 시 호출) - 여러 파일 지원 + function uploadBusRegFile(callback){ + var fileInput = $("#bus_reg_file")[0]; + + // 파일이 선택되지 않았으면 콜백만 실행 + if(fileInput.files.length == 0){ + if(callback) callback(); + return; + } + + var files = fileInput.files; + var uploadCount = 0; + var totalFiles = files.length; + + // 모든 파일이 PDF인지 확인 + for(var i = 0; i < files.length; i++){ + var fileName = files[i].name; + var fileExt = fileName.substring(fileName.lastIndexOf('.')+1).toLowerCase(); + if(fileExt != 'pdf'){ + Swal.fire("PDF 파일만 업로드 가능합니다: " + fileName); + return; + } + } + + // 각 파일을 순차적으로 업로드 + function uploadNext(index){ + if(index >= totalFiles){ + // 모든 파일 업로드 완료 + $("#bus_reg_file").val(""); + loadBusRegFile(); + if(callback) callback(); + return; + } + + var formData = new FormData(); + formData.append("file", files[index]); + formData.append("targetObjId", $("#objid").val()); + formData.append("docType", "BUS_REG_CERT"); + formData.append("docTypeName", "사업자등록증"); + + $.ajax({ + url: "/common/fileUploadProc.do", + type: "POST", + data: formData, + processData: false, + contentType: false, + success: function(data){ + uploadCount++; + uploadNext(index + 1); // 다음 파일 업로드 + }, + error: function(){ + Swal.fire("파일 업로드 중 오류가 발생했습니다: " + files[index].name); + } + }); + } + + // 첫 번째 파일부터 업로드 시작 + uploadNext(0); + } + + // 사업자등록증 파일 목록 로드 + function loadBusRegFile(){ + var targetObjId = $("#objid").val(); + if(!targetObjId) return; + + $.ajax({ + url: "/common/getFileList.do", + type: "POST", + data: { + targetObjId: targetObjId, + docType: "BUS_REG_CERT" + }, + dataType: "json", + success: function(data){ + $("#busRegFileArea").empty(); + if(data && data.length > 0){ + var fileListHtml = "
등록된 파일 ("+data.length+"개) * 파일명 클릭 시 미리보기
"; + $.each(data, function(i, file){ + fileListHtml += "
"; + fileListHtml += "
"; + fileListHtml += "📄"; + fileListHtml += ""+file.REAL_FILE_NAME+""; + fileListHtml += "("+file.REGDATE+")"; + fileListHtml += "
"; + fileListHtml += "삭제"; + fileListHtml += "
"; + }); + $("#busRegFileArea").html(fileListHtml); + }else{ + $("#busRegFileArea").html("
등록된 파일이 없습니다.
"); + } + } + }); + } + + // 사업자등록증 파일 보기 + function viewBusRegFile(fileObjId){ + window.open("/common/downloadFile.do?objId="+fileObjId, "_blank"); + } + + // 사업자등록증 파일 삭제 + function deleteBusRegFile(fileObjId){ + if(!confirm("파일을 삭제하시겠습니까?")){ + return; + } + + $.ajax({ + url: "/common/deleteFile.do", + type: "POST", + data: {objId: fileObjId}, + dataType: "json", + success: function(data){ + Swal.fire("삭제되었습니다."); + loadBusRegFile(); + }, + error: function(){ + Swal.fire("삭제 중 오류가 발생했습니다."); + } + }); + } function saveOEMInfo(){ if(fnc_valitate("oemForm")){ @@ -36,22 +294,25 @@ // 만약 Promise리턴을 받으면, if (result.isConfirmed) { // 만약 모달창에서 confirm 버튼을 눌렀다면 - $.ajax({ - url:"/contractMgmt/saveSupMgmtInfo.do", - type:"POST", - data:$("#oemForm").serialize(), - dataType:"json", - async:true, - success:function(data){ - if(data.result!=''){ - alert('저장되었습니다'); - } - opener.fn_search(); - self.close(); - }, - error: function(jqxhr, status, error){ - } - }); + // 먼저 사업자등록증 파일 업로드 후 저장 + uploadBusRegFile(function(){ + $.ajax({ + url:"/contractMgmt/saveSupMgmtInfo.do", + type:"POST", + data:$("#oemForm").serialize(), + dataType:"json", + async:true, + success:function(data){ + if(data.result!=''){ + alert('저장되었습니다'); + } + opener.fn_search(); + self.close(); + }, + error: function(jqxhr, status, error){ + } + }); + }); } }); @@ -148,40 +409,18 @@ - - - - + + + + +<%-- ${code_map.supply_code} --%> + + - - - - - - - - - - - - - - - - - - - @@ -189,6 +428,25 @@ + + + + + +<%-- ${code_map.area_cd} --%> + + + + + + + + + + + + + @@ -237,6 +495,91 @@ + + + +

담당자 정보

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 📎 사업자등록증 + + + + + + +
+ +
+
+ 💡 PDF 파일 1개만 가능 | 선택 시 자동 업로드 및 미리보기 +
+ +
+ +
+ + + <%-- diff --git a/compile_only.sh b/compile_only.sh index fba2da3..46c789a 100755 --- a/compile_only.sh +++ b/compile_only.sh @@ -53,7 +53,10 @@ echo "DEBUG: Effective classpath for javac: $EFFECTIVE_CLASSPATH" # src 폴더 내의 모든 .java 파일 컴파일 echo "Compiling Java files for development..." -find src -name "*.java" -print0 | xargs -0 javac -encoding UTF-8 -source 1.7 -target 1.7 -d WebContent/WEB-INF/classes -cp "$EFFECTIVE_CLASSPATH" +# Java 7 호환 바이트코드 생성을 위한 추가 옵션 +# -source 1.7 -target 1.7: Java 7 문법 및 바이트코드 버전 사용 +# -Xlint:-options: 경고 메시지 억제 +find src -name "*.java" -print0 | xargs -0 javac -encoding UTF-8 -source 1.7 -target 1.7 -Xlint:-options -d WebContent/WEB-INF/classes -cp "$EFFECTIVE_CLASSPATH" if [ $? -ne 0 ]; then echo "Java compilation failed. Exiting script." exit 1 diff --git a/database/add_manager_columns_to_supply_mng.sql b/database/add_manager_columns_to_supply_mng.sql new file mode 100644 index 0000000..5f3ec65 --- /dev/null +++ b/database/add_manager_columns_to_supply_mng.sql @@ -0,0 +1,24 @@ +-- 공급업체 관리 테이블에 담당자 5명 정보 컬럼 추가 + +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER1_NAME VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER1_EMAIL VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER2_NAME VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER2_EMAIL VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER3_NAME VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER3_EMAIL VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER4_NAME VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER4_EMAIL VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER5_NAME VARCHAR(100); +ALTER TABLE SUPPLY_MNG ADD COLUMN IF NOT EXISTS MANAGER5_EMAIL VARCHAR(100); + +COMMENT ON COLUMN SUPPLY_MNG.MANAGER1_NAME IS '담당자1 이름'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER1_EMAIL IS '담당자1 이메일'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER2_NAME IS '담당자2 이름'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER2_EMAIL IS '담당자2 이메일'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER3_NAME IS '담당자3 이름'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER3_EMAIL IS '담당자3 이메일'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER4_NAME IS '담당자4 이름'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER4_EMAIL IS '담당자4 이메일'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER5_NAME IS '담당자5 이름'; +COMMENT ON COLUMN SUPPLY_MNG.MANAGER5_EMAIL IS '담당자5 이메일'; + diff --git a/src/com/pms/common/FileRenameClass.java b/src/com/pms/common/FileRenameClass.java index bff7207..400c903 100644 --- a/src/com/pms/common/FileRenameClass.java +++ b/src/com/pms/common/FileRenameClass.java @@ -52,21 +52,21 @@ public class FileRenameClass implements FileRenamePolicy { int counter = 0; boolean fExist = true; - long currentTime = System.currentTimeMillis(); - - String fullFileName = parentDir + "\\" + fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; - String savedFileName = fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; - - while (fExist) { - if (new File(fullFileName).exists()) { - counter = counter + 1; -// fullFileName = parentDir + "\\" + fname + "(" + counter + ")"+ fileExt; - fullFileName = parentDir + "\\" + fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; - savedFileName = fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; - } else { - fExist = false; - } + long currentTime = System.currentTimeMillis(); + + String fullFileName = parentDir + File.separator + fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; + String savedFileName = fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; + + while (fExist) { + if (new File(fullFileName).exists()) { + counter = counter + 1; +// fullFileName = parentDir + File.separator + fname + "(" + counter + ")"+ fileExt; + fullFileName = parentDir + File.separator + fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; + savedFileName = fname.replaceAll(" ", "") + "_" +currentTime+""+ fileExt; + } else { + fExist = false; } + } Map fileMap = new HashMap(); fileMap.put("realFileName", fname+fileExt); fileMap.put("savedFileName", savedFileName); diff --git a/src/com/pms/salesmgmt/controller/ContractMgmtController.java b/src/com/pms/salesmgmt/controller/ContractMgmtController.java index 0026744..3232df4 100644 --- a/src/com/pms/salesmgmt/controller/ContractMgmtController.java +++ b/src/com/pms/salesmgmt/controller/ContractMgmtController.java @@ -2218,12 +2218,17 @@ public class ContractMgmtController { // 환종 코드 code_map.put("contract_currency", commonService.bizMakeOptionList("0001533", CommonUtils.nullToEmpty((String)info.get("CONTRACT_CURRENCY")), "common.getCodeselect")); + // 결재상태 확인 (결재완료 시 견적서 템플릿 사용) + String apprStatus = CommonUtils.nullToEmpty((String)info.get("APPR_STATUS")); + boolean useEstimateTemplate = "결재완료".equals(apprStatus); + request.setAttribute("code_map", code_map); request.setAttribute("info", info); request.setAttribute("contractInfo", contractInfo); request.setAttribute("contractObjId", objId); request.setAttribute("objId", objId); request.setAttribute("actionType", actionType); + request.setAttribute("useEstimateTemplate", useEstimateTemplate ? "Y" : "N"); } catch(Exception e) { e.printStackTrace(); @@ -2262,7 +2267,18 @@ public class ContractMgmtController { Map resultMap = new HashMap(); try { - List items = contractMgmtService.getContractItems(paramMap); + // 결재완료 상태인 경우 최종 견적서 템플릿에서 품목 조회 + String useEstimateTemplate = CommonUtils.checkNull(paramMap.get("useEstimateTemplate")); + List items = null; + + if("Y".equals(useEstimateTemplate)) { + // 최종 견적서 템플릿의 품목 조회 + items = contractMgmtService.getEstimateTemplateItemsForOrder(paramMap); + } else { + // 기존 방식: CONTRACT_ITEM에서 조회 + items = contractMgmtService.getContractItems(paramMap); + } + resultMap.put("result", "success"); resultMap.put("items", items); diff --git a/src/com/pms/salesmgmt/mapper/contractMgmt.xml b/src/com/pms/salesmgmt/mapper/contractMgmt.xml index 4717863..968bf98 100644 --- a/src/com/pms/salesmgmt/mapper/contractMgmt.xml +++ b/src/com/pms/salesmgmt/mapper/contractMgmt.xml @@ -1405,70 +1405,70 @@ @@ -2227,8 +2242,11 @@ SELECT ,SUPPLY_TEL_NO ,REG_ID ,TO_CHAR(REG_DATE,'YYYY-MM-DD') REGDATE - ,STATUS - ,CHARGE_USER_NAME + ,STATUS + ,CHARGE_USER_NAME + ,COALESCE(NULLIF(MANAGER1_NAME, ''), NULLIF(MANAGER2_NAME, ''), NULLIF(MANAGER3_NAME, ''), NULLIF(MANAGER4_NAME, ''), MANAGER5_NAME) AS MANAGER1_NAME + ,COALESCE(NULLIF(MANAGER1_EMAIL, ''), NULLIF(MANAGER2_EMAIL, ''), NULLIF(MANAGER3_EMAIL, ''), NULLIF(MANAGER4_EMAIL, ''), MANAGER5_EMAIL) AS MANAGER1_EMAIL + ,(SELECT COUNT(*) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = SUPPLY_MNG.OBJID::VARCHAR AND DOC_TYPE = 'BUS_REG_CERT' AND UPPER(STATUS) = 'ACTIVE') AS BUS_REG_FILE_CNT ,case UPPER(STATUS) when 'ACTIVE' then '활성화' when 'INACTIVE' then '비활성화' @@ -2279,10 +2297,13 @@ SELECT ,SUPPLY_BUSNAME ,SUPPLY_STOCKNAME ,SUPPLY_TEL_NO - ,REG_ID - ,TO_CHAR(REG_DATE,'YYYY-MM-DD') REGDATE - ,STATUS - ,CHARGE_USER_NAME + ,REG_ID + ,TO_CHAR(REG_DATE,'YYYY-MM-DD') REGDATE + ,STATUS + ,COALESCE(NULLIF(MANAGER1_NAME, ''), NULLIF(MANAGER2_NAME, ''), NULLIF(MANAGER3_NAME, ''), NULLIF(MANAGER4_NAME, ''), MANAGER5_NAME) AS MANAGER1_NAME + ,COALESCE(NULLIF(MANAGER1_EMAIL, ''), NULLIF(MANAGER2_EMAIL, ''), NULLIF(MANAGER3_EMAIL, ''), NULLIF(MANAGER4_EMAIL, ''), MANAGER5_EMAIL) AS MANAGER1_EMAIL + ,(SELECT COUNT(*) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = SUPPLY_MNG.OBJID::VARCHAR AND DOC_TYPE = 'BUS_REG_CERT' AND UPPER(STATUS) = 'ACTIVE') AS BUS_REG_FILE_CNT + ,CHARGE_USER_NAME ,case UPPER(STATUS) when 'ACTIVE' then '활성화' when 'INACTIVE' then '비활성화' @@ -2357,6 +2378,16 @@ SELECT ,OFFICE_NO ,EMAIL ,CUS_NO + ,MANAGER1_NAME + ,MANAGER1_EMAIL + ,MANAGER2_NAME + ,MANAGER2_EMAIL + ,MANAGER3_NAME + ,MANAGER3_EMAIL + ,MANAGER4_NAME + ,MANAGER4_EMAIL + ,MANAGER5_NAME + ,MANAGER5_EMAIL ) VALUES ( @@ -2379,25 +2410,45 @@ SELECT ,#{office_no } ,#{email } ,(SELECT 'CUS-' || LPAD((SELECT MAX(SUBSTR(CUS_NO,5,8))::INTEGER+1 FROM SUPPLY_MNG)::VARCHAR,4,'0')) + ,#{manager1_name } + ,#{manager1_email } + ,#{manager2_name } + ,#{manager2_email } + ,#{manager3_name } + ,#{manager3_email } + ,#{manager4_name } + ,#{manager4_email } + ,#{manager5_name } + ,#{manager5_email } ) ON CONFLICT (OBJID) DO UPDATE SET - SUPPLY_CODE =#{supply_code } - ,SUPPLY_NAME =#{supply_name } - ,REG_NO =#{reg_no } - ,SUPPLY_ADDRESS =#{supply_address } - ,SUPPLY_BUSNAME =#{supply_busname } - ,SUPPLY_STOCKNAME =#{supply_stockname } - ,SUPPLY_TEL_NO =#{supply_tel_no } - ,SUPPLY_FAX_NO =#{supply_fax_no } - ,CHARGE_USER_NAME =#{charge_user_name } - ,PAYMENT_METHOD =#{payment_method } - ,REG_ID =#{reg_id } - ,AREA_CD =#{area_cd } - ,BUS_REG_NO =#{bus_reg_no } - ,OFFICE_NO =#{office_no } - ,EMAIL =#{email } + SUPPLY_CODE =#{supply_code } + ,SUPPLY_NAME =#{supply_name } + ,REG_NO =#{reg_no } + ,SUPPLY_ADDRESS =#{supply_address } + ,SUPPLY_BUSNAME =#{supply_busname } + ,SUPPLY_STOCKNAME =#{supply_stockname } + ,SUPPLY_TEL_NO =#{supply_tel_no } + ,SUPPLY_FAX_NO =#{supply_fax_no } + ,CHARGE_USER_NAME =#{charge_user_name } + ,PAYMENT_METHOD =#{payment_method } + ,REG_ID =#{reg_id } + ,AREA_CD =#{area_cd } + ,BUS_REG_NO =#{bus_reg_no } + ,OFFICE_NO =#{office_no } + ,EMAIL =#{email } + ,MANAGER1_NAME =#{manager1_name } + ,MANAGER1_EMAIL =#{manager1_email } + ,MANAGER2_NAME =#{manager2_name } + ,MANAGER2_EMAIL =#{manager2_email } + ,MANAGER3_NAME =#{manager3_name } + ,MANAGER3_EMAIL =#{manager3_email } + ,MANAGER4_NAME =#{manager4_name } + ,MANAGER4_EMAIL =#{manager4_email } + ,MANAGER5_NAME =#{manager5_name } + ,MANAGER5_EMAIL =#{manager5_email } diff --git a/src/com/pms/salesmgmt/service/ContractMgmtService.java b/src/com/pms/salesmgmt/service/ContractMgmtService.java index 99c6c34..d6edc9f 100644 --- a/src/com/pms/salesmgmt/service/ContractMgmtService.java +++ b/src/com/pms/salesmgmt/service/ContractMgmtService.java @@ -2041,6 +2041,86 @@ private String encodeImageToBase64(String imagePath) { return items; } + /** + * 견적서 템플릿 품목 조회 (수주등록용) + * 최종 견적서의 품목 정보를 수주등록 형식으로 변환하여 반환 + * @param paramMap - contractObjId + * @return + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public List getEstimateTemplateItemsForOrder(Map paramMap){ + SqlSession sqlSession = null; + List items = new ArrayList(); + + try{ + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + + // 1. 최종 견적서 템플릿 조회 + Map templateParam = new HashMap(); + templateParam.put("objId", paramMap.get("contractObjId")); + Map template = sqlSession.selectOne("contractMgmt.getEstimateTemplateData", templateParam); + + if(template != null) { + // 2. 견적서 템플릿의 품목 조회 + Map itemParam = new HashMap(); + itemParam.put("templateObjId", template.get("objid")); + List templateItems = sqlSession.selectList("contractMgmt.getEstimateTemplateItemsByTemplateObjId", itemParam); + + // 3. 수주등록 형식으로 변환 + for(Map templateItem : templateItems) { + Map orderItem = new HashMap(); + + // ESTIMATE_TEMPLATE_ITEM -> CONTRACT_ITEM 형식으로 매핑 + orderItem.put("OBJID", templateItem.get("objid")); // 템플릿 품목 OBJID (참고용) + orderItem.put("CONTRACT_OBJID", paramMap.get("contractObjId")); + orderItem.put("PART_OBJID", templateItem.get("part_objid")); + orderItem.put("PART_NO", templateItem.get("description")); // 품명 + orderItem.put("PART_NAME", templateItem.get("description")); // 품명 + orderItem.put("SERIAL_NO", ""); // S/N은 비워둠 + orderItem.put("QUANTITY", templateItem.get("quantity")); // 수량 + orderItem.put("DUE_DATE", ""); + orderItem.put("CUSTOMER_REQUEST", ""); + orderItem.put("RETURN_REASON", ""); + + // 수주 정보는 견적서 값으로 초기화 + orderItem.put("ORDER_QUANTITY", templateItem.get("quantity")); + orderItem.put("ORDER_UNIT_PRICE", templateItem.get("unit_price")); + + // 공급가액 계산 (수량 * 단가) + Object quantity = templateItem.get("quantity"); + Object unitPrice = templateItem.get("unit_price"); + long supplyPrice = 0; + + if(quantity != null && unitPrice != null) { + try { + long qty = Long.parseLong(quantity.toString().replaceAll("[^0-9]", "")); + long price = Long.parseLong(unitPrice.toString().replaceAll("[^0-9]", "")); + supplyPrice = qty * price; + } catch(Exception e) { + // 계산 실패 시 0 + } + } + + orderItem.put("ORDER_SUPPLY_PRICE", supplyPrice); + orderItem.put("ORDER_VAT", Math.round(supplyPrice * 0.1)); // 부가세 10% + orderItem.put("ORDER_TOTAL_AMOUNT", supplyPrice + Math.round(supplyPrice * 0.1)); + + items.add(orderItem); + } + + // 대문자 변환 + items = CommonUtils.keyChangeUpperList(items); + } + + }catch(Exception e){ + e.printStackTrace(); + }finally{ + if(sqlSession != null) sqlSession.close(); + } + + return items; + } + @SuppressWarnings({ "rawtypes", "unchecked" }) public Map saveOrderInfo(HttpServletRequest request, Map paramMap){ Map resultMap = new HashMap();