Merge pull request 'V20260210' (#185) from V20260210 into main
Reviewed-on: #185
This commit was merged in pull request #185.
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -33,3 +33,9 @@ Thumbs.db
|
||||
|
||||
# Cursor files
|
||||
.cursor/
|
||||
|
||||
# Claude Code
|
||||
CLAUDE.md
|
||||
.claude/
|
||||
.playwright-mcp/
|
||||
.omc/
|
||||
|
||||
150
WebContent/WEB-INF/view/contractMgmt/addEstimatePdfPopup.jsp
Normal file
150
WebContent/WEB-INF/view/contractMgmt/addEstimatePdfPopup.jsp
Normal file
@@ -0,0 +1,150 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ page import="com.pms.common.utils.*"%>
|
||||
<%@ page import="java.util.*" %>
|
||||
<%@include file= "/init.jsp" %>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
<style>
|
||||
.pdf-only-notice { font-size:12px; color:#888; margin-bottom:6px; }
|
||||
.file-input-row { display:flex; align-items:center; gap:8px; margin-top:6px; }
|
||||
</style>
|
||||
</head>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
$("#btn_close").click(function(){
|
||||
if(opener && opener.fn_search){ opener.fn_search(); }
|
||||
self.close();
|
||||
});
|
||||
|
||||
fnc_setFileDropZone("pdfDropZone", "${param.targetObjId}", "estimate02", "추가견적PDF", "pdfAreaDraw", false, null, null, "pdf", null);
|
||||
pdfAreaDraw();
|
||||
|
||||
$("#btnUploadPdf").click(function(){
|
||||
var files = $("#filePdf")[0].files;
|
||||
if(files.length > 0){
|
||||
var valid = true;
|
||||
for(var i = 0; i < files.length; i++){
|
||||
if(!files[i].name.toLowerCase().endsWith('.pdf')){
|
||||
Swal.fire("PDF 파일만 첨부할 수 있습니다.\n(" + files[i].name + ")");
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(valid){
|
||||
fnc_fileMultiUpload(files, null, "${param.targetObjId}", "estimate02", "추가견적PDF", null, "pdfAreaDraw", "pdf", null);
|
||||
$("#filePdf").val("");
|
||||
}
|
||||
} else {
|
||||
Swal.fire("선택된 파일이 없습니다.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function pdfAreaDraw(){
|
||||
var param = {"targetObjId":"${param.targetObjId}", "docType":"estimate02"};
|
||||
$.ajax({
|
||||
url:"/common/getFileList.do",
|
||||
type:"POST",
|
||||
data:param,
|
||||
dataType:"json",
|
||||
async:false,
|
||||
success:function(data){
|
||||
$("#pdfFileArea").empty();
|
||||
if(data.length > 0){
|
||||
$.each(data, function(i){
|
||||
var displayNum = data.length - i;
|
||||
var appendText = "<tr>";
|
||||
appendText += "<td style='text-align:center;'>" + displayNum + "차</td>";
|
||||
appendText += "<td class='align_l'><a href='javascript:fnc_downloadFile(\""+data[i].OBJID+"\")'> " + data[i].REAL_FILE_NAME + "</a>";
|
||||
if(data[i].WRITER === "${connectUserId}" || 'plm_admin' === "${connectUserId}"){
|
||||
appendText += "<a href='javascript:pdfFileDelete(\""+data[i].OBJID+"\")'><div class='delete_btn'></div></a>";
|
||||
}
|
||||
appendText += "</td>";
|
||||
appendText += "<td style='text-align:center;'>" + data[i].REGDATE + "</td>";
|
||||
appendText += "<td style='text-align:center;'>" + data[i].FILE_SIZE + "</td>";
|
||||
appendText += "</tr>";
|
||||
$("#pdfFileArea").append(appendText);
|
||||
});
|
||||
} else {
|
||||
$("#pdfFileArea").append("<tr><td colspan='4' style='text-align:center;color:#999;'>첨부된 PDF 파일이 없습니다.</td></tr>");
|
||||
}
|
||||
}
|
||||
});
|
||||
// 부모 창의 그리드 새로고침 (ADD_EST_CNT 카운트 업데이트)
|
||||
if(opener && typeof opener.fn_search == "function"){
|
||||
opener.fn_search();
|
||||
}
|
||||
}
|
||||
|
||||
function pdfFileDelete(fileObjId){
|
||||
if(confirm("파일을 삭제하시겠습니까?")){
|
||||
$.ajax({
|
||||
url:"/common/deleteFileInfo.do",
|
||||
type:"POST",
|
||||
data:{"objId":fileObjId},
|
||||
dataType:"json",
|
||||
async:false,
|
||||
success:function(){ pdfAreaDraw(); }
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<form name="form1" action="" method="post">
|
||||
<section class="business_staff_popup_min_width">
|
||||
<div class="plm_menu_name">
|
||||
<h2><span>추가견적 PDF 첨부</span></h2>
|
||||
</div>
|
||||
<div id="businessPopupFormWrap">
|
||||
<table class="pmsPopupForm">
|
||||
<tr>
|
||||
<td class="input_title align_c">PDF 파일</td>
|
||||
<td colspan="8">
|
||||
<div style="width:100%; overflow:hidden; box-sizing:border-box;">
|
||||
<p class="pdf-only-notice">* PDF 파일만 첨부 가능합니다. (추후 메일 발송 시 견적서 PDF와 합쳐 발송될 예정입니다)</p>
|
||||
<div id="pdfDropZone" class="dropzone" style="width:100% !important; max-width:100%; box-sizing:border-box; margin-bottom:5px;">
|
||||
Drag & Drop PDF Files Here
|
||||
</div>
|
||||
<div class="file-input-row">
|
||||
<input type="file" name="filePdf" id="filePdf" accept=".pdf" multiple>
|
||||
<input type="button" id="btnUploadPdf" value="Upload" class="upload_btns">
|
||||
</div>
|
||||
<div class="spec_data_in_table" style="margin-top:8px;">
|
||||
<div style="height:180px; overflow-y:auto; border:1px solid #cacaca;">
|
||||
<table class="fileListscrollTbody" style="width:100%; table-layout:fixed;">
|
||||
<colgroup>
|
||||
<col style="width:55px;">
|
||||
<col style="width:calc(100% - 215px);">
|
||||
<col style="width:90px;">
|
||||
<col style="width:70px;">
|
||||
</colgroup>
|
||||
<thead style="position:sticky; top:0; background-color:#9e9e9e; z-index:1;">
|
||||
<tr>
|
||||
<td style="text-align:center;">No</td>
|
||||
<td style="text-align:center;">파일명</td>
|
||||
<td style="text-align:center;">등록일</td>
|
||||
<td style="text-align:center;">Size</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="pdfFileArea"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="btn_wrap">
|
||||
<div class="plm_btn_wrap_center">
|
||||
<input type="button" value="닫기" id="btn_close" class="plm_btns">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -74,7 +74,7 @@
|
||||
$(this).val(fnc_addComma($(this).val().replace(/[^0-9.]/g, "")));
|
||||
}
|
||||
});
|
||||
$("input:text[numberOnly]").on("blur", function() {
|
||||
$(document).on("blur", "input:text[numberOnly]", function() {
|
||||
var val = $(this).val();
|
||||
if(val && val !== '') {
|
||||
if($(this).hasClass("item-order-quantity") || $(this).attr("id") === "facility_qty") {
|
||||
@@ -133,6 +133,13 @@
|
||||
function addComma(data) {
|
||||
return formatMoney(data);
|
||||
}
|
||||
|
||||
function addCommaInt(data) {
|
||||
if(!data && data !== 0) return '';
|
||||
var num = Math.round(Number(String(data).replace(/,/g, '')));
|
||||
if(isNaN(num)) return '';
|
||||
return num.toLocaleString();
|
||||
}
|
||||
|
||||
function removeComma(data) {
|
||||
if(!data) return '';
|
||||
@@ -331,30 +338,30 @@
|
||||
// 수주수량 (Machine이고 프로젝트가 있으면 readonly)
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
if(isMachine && hasProject) {
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." />';
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." />';
|
||||
} else {
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px;" required numberOnly />';
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right;" required numberOnly />';
|
||||
}
|
||||
html += '</td>';
|
||||
|
||||
|
||||
// 수주단가
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:90%; padding:5px;" numberOnly />';
|
||||
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:90%; padding:5px; text-align:right;" numberOnly />';
|
||||
html += '</td>';
|
||||
|
||||
|
||||
// 수주공급가액 (자동계산 + 수정가능)
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:90%; padding:5px;" numberOnly />';
|
||||
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:90%; padding:5px; text-align:right;" numberOnly />';
|
||||
html += '</td>';
|
||||
|
||||
|
||||
// 수주부가세 (자동계산 + 수정가능)
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:90%; padding:5px;" numberOnly />';
|
||||
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:90%; padding:5px; text-align:right;" numberOnly />';
|
||||
html += '</td>';
|
||||
|
||||
|
||||
// 수주총액 (자동계산 + 수정가능)
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:90%; padding:5px;" numberOnly />';
|
||||
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:90%; padding:5px; text-align:right;" numberOnly />';
|
||||
html += '</td>';
|
||||
|
||||
// 삭제 버튼
|
||||
@@ -401,7 +408,8 @@
|
||||
} else if($(this).hasClass("item-order-vat")) {
|
||||
fn_calculateTotalFromVat(itemId);
|
||||
}
|
||||
// 총액 직접 수정시에는 재계산 안함
|
||||
// 총액 직접 수정시에도 합계는 갱신
|
||||
fn_calculateTotal();
|
||||
});
|
||||
|
||||
// 품목 정보 저장
|
||||
@@ -543,22 +551,22 @@
|
||||
// 수주 정보 (Machine이고 프로젝트가 있으면 수량 readonly)
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
if(isMachine && hasProject) {
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
|
||||
} else {
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px;" required numberOnly value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
|
||||
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right;" required numberOnly value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
|
||||
}
|
||||
html += '</td>';
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:90%; padding:5px;" numberOnly value="' + (orderUnitPrice ? addComma(orderUnitPrice) : '') + '" />';
|
||||
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderUnitPrice ? addComma(orderUnitPrice) : '') + '" />';
|
||||
html += '</td>';
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:90%; padding:5px;" numberOnly value="' + (orderSupplyPrice ? addComma(orderSupplyPrice) : '') + '" />';
|
||||
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderSupplyPrice ? addComma(orderSupplyPrice) : '') + '" />';
|
||||
html += '</td>';
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:90%; padding:5px;" numberOnly value="' + (orderVat ? addComma(orderVat) : '') + '" />';
|
||||
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderVat ? addComma(orderVat) : '') + '" />';
|
||||
html += '</td>';
|
||||
html += '<td style="padding:5px; border:1px solid #ddd;">';
|
||||
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:90%; padding:5px;" numberOnly value="' + (orderTotalAmount ? addComma(orderTotalAmount) : '') + '" />';
|
||||
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderTotalAmount ? addComma(orderTotalAmount) : '') + '" />';
|
||||
html += '</td>';
|
||||
|
||||
html += '<td style="text-align:center; padding:5px; border:1px solid #ddd;">';
|
||||
@@ -624,6 +632,8 @@
|
||||
} else if($(this).hasClass("item-order-vat")) {
|
||||
fn_calculateTotalFromVat(itemId);
|
||||
}
|
||||
// 총액 직접 수정시에도 합계는 갱신
|
||||
fn_calculateTotal();
|
||||
});
|
||||
|
||||
// 품목 정보 저장
|
||||
@@ -636,9 +646,11 @@
|
||||
}
|
||||
}
|
||||
%>
|
||||
// 기존 품목 로드 완료 후 합계 계산
|
||||
fn_calculateTotal();
|
||||
}
|
||||
|
||||
// 품목별 금액 계산
|
||||
|
||||
// 품목별 금액 계산
|
||||
function fn_calculateItemAmount(itemId) {
|
||||
var quantity = parseFloat(removeComma($("#" + itemId + " .item-order-quantity").val())) || 0;
|
||||
var unitPrice = parseFloat(removeComma($("#" + itemId + " .item-order-unit-price").val())) || 0;
|
||||
@@ -654,8 +666,9 @@
|
||||
// 총액 계산
|
||||
var totalAmount = supplyPrice + vat;
|
||||
$("#" + itemId + " .item-order-total-amount").val(addComma(totalAmount));
|
||||
fn_calculateTotal();
|
||||
}
|
||||
|
||||
|
||||
// 부가세 직접 입력 시 총액만 재계산
|
||||
function fn_calculateTotalFromVat(itemId) {
|
||||
var supplyPrice = parseFloat(removeComma($("#" + itemId + " .item-order-supply-price").val())) || 0;
|
||||
@@ -664,19 +677,36 @@
|
||||
// 총액 계산
|
||||
var totalAmount = supplyPrice + vat;
|
||||
$("#" + itemId + " .item-order-total-amount").val(addComma(totalAmount));
|
||||
fn_calculateTotal();
|
||||
}
|
||||
|
||||
|
||||
// 공급가액 직접 입력 시 부가세와 총액 재계산
|
||||
function fn_calculateFromSupplyPrice(itemId) {
|
||||
var supplyPrice = parseFloat(removeComma($("#" + itemId + " .item-order-supply-price").val())) || 0;
|
||||
|
||||
|
||||
// 부가세 자동 계산 (공급가액의 10%)
|
||||
var vat = Math.round(supplyPrice * 0.1);
|
||||
$("#" + itemId + " .item-order-vat").val(addComma(vat));
|
||||
|
||||
|
||||
// 총액 계산
|
||||
var totalAmount = supplyPrice + vat;
|
||||
$("#" + itemId + " .item-order-total-amount").val(addComma(totalAmount));
|
||||
fn_calculateTotal();
|
||||
}
|
||||
|
||||
// 품목 합계 계산
|
||||
function fn_calculateTotal() {
|
||||
var totalQty = 0, totalSupply = 0, totalVat = 0, totalAmount = 0;
|
||||
$(".item-row").each(function() {
|
||||
totalQty += parseFloat(removeComma($(this).find(".item-order-quantity").val())) || 0;
|
||||
totalSupply += parseFloat(removeComma($(this).find(".item-order-supply-price").val())) || 0;
|
||||
totalVat += parseFloat(removeComma($(this).find(".item-order-vat").val())) || 0;
|
||||
totalAmount += parseFloat(removeComma($(this).find(".item-order-total-amount").val())) || 0;
|
||||
});
|
||||
$("#totalOrderQuantity").text(addCommaInt(totalQty));
|
||||
$("#totalOrderSupplyPrice").text(addComma(totalSupply));
|
||||
$("#totalOrderVat").text(addComma(totalVat));
|
||||
$("#totalOrderTotalAmount").text(addComma(totalAmount));
|
||||
}
|
||||
|
||||
// 품번/품명 셀렉트박스 옵션 채우기 (Select2 AJAX)
|
||||
@@ -1037,7 +1067,7 @@
|
||||
|
||||
if(confirm("해당 품목을 삭제하시겠습니까?")) {
|
||||
$("#" + itemId).remove();
|
||||
|
||||
|
||||
// itemList에서 제거
|
||||
for(var i = 0; i < itemList.length; i++) {
|
||||
if(itemList[i].id == itemId) {
|
||||
@@ -1045,10 +1075,13 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 행 번호 재정렬
|
||||
fn_reorderItemRows();
|
||||
|
||||
|
||||
// 합계 재계산
|
||||
fn_calculateTotal();
|
||||
|
||||
// 모든 행이 삭제되면 안내 메시지 표시
|
||||
if($(".item-row").length == 0) {
|
||||
$("#noItemRow").show();
|
||||
@@ -1487,6 +1520,17 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="totalRow" style="background:#f5f5f5; font-weight:bold;">
|
||||
<td colspan="7" style="text-align:center; padding:8px; border:1px solid #ddd;">Total</td>
|
||||
<td style="text-align:right; padding:8px; border:1px solid #ddd;" id="totalOrderQuantity">0</td>
|
||||
<td style="padding:8px; border:1px solid #ddd;"></td>
|
||||
<td style="text-align:right; padding:8px; border:1px solid #ddd;" id="totalOrderSupplyPrice">0.00</td>
|
||||
<td style="text-align:right; padding:8px; border:1px solid #ddd;" id="totalOrderVat">0.00</td>
|
||||
<td style="text-align:right; padding:8px; border:1px solid #ddd;" id="totalOrderTotalAmount">0.00</td>
|
||||
<td style="padding:8px; border:1px solid #ddd;"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -414,7 +414,22 @@ var columns = [
|
||||
var objid = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_showEstimateList(objid);
|
||||
}
|
||||
},
|
||||
},
|
||||
// 11-1. 추가견적 PDF 첨부
|
||||
{headerHozAlign : 'center', hozAlign : 'center', minWidth: 55, widthGrow: 0.7, title : '추가견적', field : 'ADD_EST_CNT',
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
var cnt = fnc_checkNull(cell.getValue());
|
||||
var icon = '<span style="font-size:14px; cursor:pointer;">📎</span>';
|
||||
if(cnt !== '' && parseInt(cnt) > 0){
|
||||
return icon + ' <span style="color:#1a73e8; font-weight:bold;">' + cnt + '</span>';
|
||||
}
|
||||
return icon;
|
||||
},
|
||||
cellClick:function(e, cell){
|
||||
var objid = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_openAddEstimatePdf(objid);
|
||||
}
|
||||
},
|
||||
// 12. 아마란스 결재상태 (hidden)
|
||||
{title:'AMARANTH_STATUS', field:'AMARANTH_STATUS', visible: false},
|
||||
// 13. 결재상태 (아마란스 전자결재)
|
||||
@@ -556,7 +571,7 @@ function fn_search(){
|
||||
console.log("품목 검색 조건 설정됨:", partObjId);
|
||||
}
|
||||
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/contractMgmt/contractGridList.do", columns, true);
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/contractMgmt/estimateGridList.do", columns, true);
|
||||
}
|
||||
|
||||
function _fnc_datepick(){
|
||||
@@ -635,6 +650,14 @@ function fn_delete(){
|
||||
}
|
||||
|
||||
|
||||
// 추가견적 PDF 첨부 팝업
|
||||
function fn_openAddEstimatePdf(objId){
|
||||
var popup_width = 700;
|
||||
var popup_height = 400;
|
||||
var url = '/contractMgmt/addEstimatePdfPopup.do?targetObjId=' + objId;
|
||||
fn_centerPopup(popup_width, popup_height, url);
|
||||
}
|
||||
|
||||
function fn_FileRegist(objId, docType, docTypeName){
|
||||
var popup_width = 800;
|
||||
var popup_height = 300;
|
||||
|
||||
@@ -1662,14 +1662,14 @@ function fn_generatePdf() {
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
|
||||
// 페이지가 넘어가면 추가 페이지 생성
|
||||
while (heightLeft >= 0) {
|
||||
// 페이지가 넘어가면 추가 페이지 생성 (1mm 이상 넘칠 때만)
|
||||
while (heightLeft > 1) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
}
|
||||
|
||||
|
||||
// 파일명 생성
|
||||
var estimateNo = $("#estimate_no").val() || "견적서";
|
||||
var fileName = estimateNo + '.pdf';
|
||||
@@ -1782,13 +1782,13 @@ function fn_generateAndUploadPdf(callback) {
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
|
||||
while (heightLeft >= 0) {
|
||||
while (heightLeft > 1) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
}
|
||||
|
||||
|
||||
console.log('PDF 생성 완료');
|
||||
|
||||
// PDF를 Base64로 변환
|
||||
|
||||
@@ -1158,7 +1158,7 @@ function fn_generateAndUploadPdf(callback) {
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
|
||||
while (heightLeft >= 0) {
|
||||
while (heightLeft > 1) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
|
||||
@@ -125,7 +125,7 @@ String connector = person.getUserId();
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
// initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
//첨부팝업
|
||||
$(".File").click(function(){
|
||||
@@ -760,16 +760,16 @@ function fn_deleteErp(){
|
||||
<!-- </td> -->
|
||||
<td><label for="">품번</label></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<!-- 입력값 포함 검색 (structurePopupRight.jsp 방식: LIKE '%...%') -->
|
||||
<input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" style="width:150px;" autocomplete="off" value="${param.SEARCH_PART_NO}">
|
||||
<!-- (기존) Select2 OBJID 정확매칭 방식 → 주석처리
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
-->
|
||||
</td>
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
<!-- 입력값 포함 검색 (structurePopupRight.jsp 방식: LIKE '%...%') -->
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" style="width:150px;" autocomplete="off" value="${param.SEARCH_PART_NAME}">
|
||||
</td>
|
||||
|
||||
<td><label for="">Revision</label></td>
|
||||
|
||||
@@ -2001,9 +2001,11 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
AND UPPER(T.PART_NO) LIKE UPPER('%${SEARCH_PART_NO}%')
|
||||
</if>
|
||||
|
||||
<!-- (기존) Select2 OBJID 정확매칭 → 주석처리 (structurePopupRight.jsp 방식으로 변경: LIKE 포함검색 사용)
|
||||
<if test="SEARCH_PART_OBJID != null and SEARCH_PART_OBJID != ''">
|
||||
AND T.OBJID = #{SEARCH_PART_OBJID}
|
||||
</if>
|
||||
-->
|
||||
<if test="SEARCH_PART_NAME != null and SEARCH_PART_NAME != ''">
|
||||
AND UPPER(T.PART_NAME) LIKE UPPER('%${SEARCH_PART_NAME}%')
|
||||
</if>
|
||||
|
||||
@@ -2899,6 +2899,14 @@ public class ContractMgmtController {
|
||||
request.setAttribute("docTypeName", CommonUtils.checkNull(paramMap.get("docTypeName")));
|
||||
return "/contractMgmt/FileRegistPopup";
|
||||
}
|
||||
|
||||
/**
|
||||
* 추가견적 PDF 첨부 팝업
|
||||
*/
|
||||
@RequestMapping("/contractMgmt/addEstimatePdfPopup.do")
|
||||
public String addEstimatePdfPopup(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
return "/contractMgmt/addEstimatePdfPopup";
|
||||
}
|
||||
|
||||
/**
|
||||
* 영업정보의 품목 목록 조회 (견적서 작성 시 사용)
|
||||
|
||||
@@ -739,6 +739,8 @@
|
||||
AND CANCEL_QTY != ''
|
||||
AND CANCEL_QTY != '0'
|
||||
) AS CANCEL_QTY_SUM
|
||||
-- 추가견적 PDF 첨부 건수
|
||||
,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE = 'estimate02' AND UPPER(STATUS) = 'ACTIVE') AS ADD_EST_CNT
|
||||
FROM
|
||||
CONTRACT_MGMT AS T
|
||||
LEFT OUTER JOIN
|
||||
@@ -1014,9 +1016,134 @@
|
||||
AND COALESCE(IS_DIRECT_ORDER, 'N') != 'Y'
|
||||
</if>
|
||||
|
||||
ORDER BY REGDATE DESC
|
||||
ORDER BY REGDATE DESC
|
||||
</select>
|
||||
|
||||
<!-- 견적관리 리스트 (estimateList_new 전용 - list_type=estimate 필터 적용) -->
|
||||
<select id="estimateGridList" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
T.*
|
||||
FROM
|
||||
<include refid="contractBase"/> T
|
||||
WHERE 1=1
|
||||
<if test="Year !=null and Year != '' ">
|
||||
AND SUBSTR(CONTRACT_DATE,0,5) = #{Year}
|
||||
</if>
|
||||
|
||||
<if test="category_cd !=null and category_cd != '' ">
|
||||
AND category_cd = #{category_cd}
|
||||
</if>
|
||||
|
||||
<if test="customer_objid !=null and customer_objid != '' ">
|
||||
AND customer_objid = #{customer_objid}
|
||||
</if>
|
||||
|
||||
<if test="product != null and product !='' ">
|
||||
AND product = #{product}
|
||||
</if>
|
||||
|
||||
<if test="status_cd !=null and status_cd !=''">
|
||||
AND status_cd = #{status_cd}
|
||||
</if>
|
||||
|
||||
<if test="result_cd !=null and result_cd !=''">
|
||||
AND result_cd = #{result_cd}
|
||||
</if>
|
||||
<if test="contract_result !=null and contract_result !=''">
|
||||
AND contract_result = #{contract_result}
|
||||
</if>
|
||||
|
||||
<if test="contract_start_date != null and !''.equals(contract_start_date)">
|
||||
AND TO_DATE(CONTRACT_DATE,'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{contract_start_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="contract_end_date != null and !''.equals(contract_end_date)">
|
||||
AND TO_DATE(CONTRACT_DATE,'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{contract_end_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
|
||||
<if test="pm_user_id !=null and pm_user_id !=''">
|
||||
AND pm_user_id = #{pm_user_id}
|
||||
</if>
|
||||
|
||||
<if test="appr_status !=null and appr_status != '' ">
|
||||
AND APPR_STATUS = #{appr_status}
|
||||
</if>
|
||||
|
||||
<if test="area_cd != null and area_cd !='' ">
|
||||
AND AREA_CD = #{area_cd}
|
||||
</if>
|
||||
|
||||
<if test="paid_type != null and paid_type !='' ">
|
||||
AND PAID_TYPE = #{paid_type}
|
||||
</if>
|
||||
|
||||
<if test="search_partObjId != null and search_partObjId != ''">
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM CONTRACT_ITEM CI
|
||||
WHERE CI.CONTRACT_OBJID = T.OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CI.PART_OBJID = #{search_partObjId}
|
||||
)
|
||||
</if>
|
||||
|
||||
<if test="search_serialNo != null and search_serialNo != ''">
|
||||
AND UPPER(SERIAL_NO) LIKE UPPER('%${search_serialNo}%')
|
||||
</if>
|
||||
|
||||
<if test="contract_currency != null and contract_currency != ''">
|
||||
AND CONTRACT_CURRENCY = #{contract_currency}
|
||||
</if>
|
||||
|
||||
<if test="receipt_start_date != null and !''.equals(receipt_start_date)">
|
||||
AND RECEIPT_DATE IS NOT NULL
|
||||
AND RECEIPT_DATE != ''
|
||||
AND (
|
||||
CASE
|
||||
WHEN RECEIPT_DATE ~ '^\d{8}$' THEN TO_DATE(RECEIPT_DATE, 'YYYYMMDD')
|
||||
WHEN RECEIPT_DATE ~ '^\d{4}-\d{2}-\d{2}$' THEN TO_DATE(RECEIPT_DATE, 'YYYY-MM-DD')
|
||||
ELSE NULL
|
||||
END
|
||||
) <![CDATA[ >= ]]> TO_DATE(#{receipt_start_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="receipt_end_date != null and !''.equals(receipt_end_date)">
|
||||
AND RECEIPT_DATE IS NOT NULL
|
||||
AND RECEIPT_DATE != ''
|
||||
AND (
|
||||
CASE
|
||||
WHEN RECEIPT_DATE ~ '^\d{8}$' THEN TO_DATE(RECEIPT_DATE, 'YYYYMMDD')
|
||||
WHEN RECEIPT_DATE ~ '^\d{4}-\d{2}-\d{2}$' THEN TO_DATE(RECEIPT_DATE, 'YYYY-MM-DD')
|
||||
ELSE NULL
|
||||
END
|
||||
) <![CDATA[ <= ]]> TO_DATE(#{receipt_end_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
|
||||
<if test="due_start_date != null and !''.equals(due_start_date)">
|
||||
AND (
|
||||
SELECT MIN(CI.DUE_DATE)
|
||||
FROM CONTRACT_ITEM CI
|
||||
WHERE CI.CONTRACT_OBJID = T.OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CI.DUE_DATE IS NOT NULL
|
||||
AND CI.DUE_DATE != ''
|
||||
) <![CDATA[ >= ]]> #{due_start_date}
|
||||
</if>
|
||||
<if test="due_end_date != null and !''.equals(due_end_date)">
|
||||
AND (
|
||||
SELECT MIN(CI.DUE_DATE)
|
||||
FROM CONTRACT_ITEM CI
|
||||
WHERE CI.CONTRACT_OBJID = T.OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CI.DUE_DATE IS NOT NULL
|
||||
AND CI.DUE_DATE != ''
|
||||
) <![CDATA[ <= ]]> #{due_end_date}
|
||||
</if>
|
||||
|
||||
<!-- 통합 등록 건 제외 (견적관리에서는 통합직발 숨김) -->
|
||||
AND COALESCE(IS_DIRECT_ORDER, 'N') != 'Y'
|
||||
|
||||
ORDER BY REGDATE DESC
|
||||
</select>
|
||||
|
||||
<!-- 주문서관리 Total 합계 조회 (조회된 데이터 전체 합계) -->
|
||||
<select id="getContractGridTotalAmount" parameterType="map" resultType="map">
|
||||
/* contractMgmt.getContractGridTotalAmount */
|
||||
@@ -3031,38 +3158,7 @@ SELECT
|
||||
,TOTAL_CNT::integer
|
||||
FROM (
|
||||
SELECT COUNT(1)::float TOTAL_CNT
|
||||
FROM
|
||||
( SELECT
|
||||
OBJID::VARCHAR
|
||||
,CUSTOMER_OBJID
|
||||
,CATEGORY_CD
|
||||
,PRODUCT_GROUP
|
||||
,PRODUCT
|
||||
,PRODUCT_STD
|
||||
,QTY
|
||||
,WARRANTY
|
||||
,PRODUCT_PRICE
|
||||
,OTHER_PRICE
|
||||
,TOTAL_PRICE
|
||||
,CONTRACT_USER_ID
|
||||
,CONTRACT_DATE
|
||||
,CONTRACT_PHONE
|
||||
,CONTRACT_EMAIL
|
||||
,CONTRACT_OFFICE_NO
|
||||
,CONTRACT_FAX_NO
|
||||
,EST_RELEASE_DATE
|
||||
,REGDATE
|
||||
,WRITER
|
||||
,ESTIMATE_NO
|
||||
,CONTRACT_PRODUCT_PRICE
|
||||
,SALE
|
||||
,FINAL_TOTAL_PRICE
|
||||
,CONTRACT_TYPE
|
||||
,NOTE
|
||||
,CUS_REQUEST_DATE
|
||||
,DELIVERY_PLACE
|
||||
,PRODUCT_CODE
|
||||
FROM ESTIMATE_MGMT ) AS T
|
||||
FROM ESTIMATE_MGMT AS T
|
||||
WHERE 1=1
|
||||
<if test="PRODUCT_CATEGORY !=null and PRODUCT_CATEGORY != '' ">
|
||||
AND PRODUCT_GROUP = #{PRODUCT_CATEGORY}
|
||||
@@ -3092,11 +3188,11 @@ SELECT
|
||||
</if>
|
||||
|
||||
<if test="contract_start_date != null and !''.equals(contract_start_date)">
|
||||
AND TO_DATE(TO_CHAR(TO_DATE(CONTRACT_DATE,'YYYYMMDD'),'YYYY-MM-DD'),'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{contract_start_date}, 'YYYY-MM-DD')
|
||||
AND TO_DATE(CONTRACT_DATE,'YYYYMMDD') <![CDATA[ >= ]]> TO_DATE(#{contract_start_date}, 'YYYY-MM-DD')
|
||||
|
||||
</if>
|
||||
<if test="contract_end_date != null and !''.equals(contract_end_date)">
|
||||
AND TO_DATE(TO_CHAR(TO_DATE(CONTRACT_DATE,'YYYYMMDD'),'YYYY-MM-DD'),'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{contract_end_date}, 'YYYY-MM-DD')
|
||||
AND TO_DATE(CONTRACT_DATE,'YYYYMMDD') <![CDATA[ <= ]]> TO_DATE(#{contract_end_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="status_cd != null and !''.equals(status_cd)">
|
||||
AND CONTRACT_STATUS_CODE = #{status_cd}
|
||||
@@ -3115,19 +3211,19 @@ SELECT
|
||||
FROM(
|
||||
SELECT
|
||||
CONTRACT_MGMT.*
|
||||
,TO_DATE(TO_CHAR(TO_DATE(CONTRACT_MGMT.EST_RELEASE_DATE ,'YYYYMMDD'),'YYYY-MM-DD'),'YYYY-MM-DD') AS TO_DATE_EST_RELEASE_DATE
|
||||
,TO_DATE(TO_CHAR(TO_DATE(CONTRACT_MGMT.CONTRACT_DATE ,'YYYYMMDD'),'YYYY-MM-DD'),'YYYY-MM-DD') AS TO_DATE_CONTRACT_DATE
|
||||
,TO_DATE(CONTRACT_MGMT.EST_RELEASE_DATE,'YYYYMMDD') AS TO_DATE_EST_RELEASE_DATE
|
||||
,TO_DATE(CONTRACT_MGMT.CONTRACT_DATE,'YYYYMMDD') AS TO_DATE_CONTRACT_DATE
|
||||
,ROW_NUMBER() OVER (ORDER BY ESTIMATE_NO DESC) AS RNUM
|
||||
FROM
|
||||
( SELECT T.OBJID::VARCHAR
|
||||
,T.CUSTOMER_OBJID
|
||||
,ESTIMATE_NO
|
||||
,CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN (SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = T.CUSTOMER_OBJID) ELSE (SELECT SUPPLY_NAME FROM SUPPLY_MNG AS O WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR) END AS SUPPLY_NAME
|
||||
,CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN NULL ELSE (SELECT CODE_NAME(AREA_CD) FROM SUPPLY_MNG AS O WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR) END AS AREA_CD_NAME
|
||||
,CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN (SELECT CEO_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = T.CUSTOMER_OBJID) ELSE (SELECT CHARGE_USER_NAME FROM SUPPLY_MNG AS O WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR) END AS CHARGE_USER_NAME
|
||||
,CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN NULL ELSE (SELECT REG_ID FROM SUPPLY_MNG AS O WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR) END AS REG_ID
|
||||
,CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN (SELECT BUS_REG_NO FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = T.CUSTOMER_OBJID) ELSE (SELECT BUS_REG_NO FROM SUPPLY_MNG AS O WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR) END AS BUS_REG_NO
|
||||
,CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN NULL ELSE (SELECT REG_NO FROM SUPPLY_MNG AS O WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR) END AS REG_NO
|
||||
,COALESCE(CL.CLIENT_NM, SP.SUPPLY_NAME) AS SUPPLY_NAME
|
||||
,SP.AREA_CD_NAME
|
||||
,COALESCE(CL.CEO_NM, SP.CHARGE_USER_NAME) AS CHARGE_USER_NAME
|
||||
,SP.REG_ID
|
||||
,COALESCE(CL.BUS_REG_NO, SP.BUS_REG_NO) AS BUS_REG_NO
|
||||
,SP.REG_NO
|
||||
,T.CATEGORY_CD
|
||||
,T.PRODUCT_GROUP AS PRODUCT_GROUP
|
||||
,T.PRODUCT AS PRODUCT
|
||||
@@ -3141,12 +3237,35 @@ SELECT
|
||||
,FINAL_TOTAL_PRICE
|
||||
,CONTRACT_DATE
|
||||
,(SELECT USER_NAME FROM USER_INFO AS O WHERE O.USER_ID = T.CONTRACT_USER_ID ) AS CONTRACT_USER_NAME
|
||||
,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE='estimate01' AND UPPER(STATUS) = 'ACTIVE') AS CU01_CNT
|
||||
,COALESCE(FC.CU01_CNT, 0) AS CU01_CNT
|
||||
,COALESCE(FC.ADD_ESTIMATE_FILE_CNT, 0) AS ADD_EST_CNT
|
||||
,T.REGDATE
|
||||
,PRODUCT_CODE
|
||||
,(SELECT CODE_NAME FROM COMM_CODE AS O WHERE O.CODE_ID = T.STATUS) AS STATUS_NAME
|
||||
,STATUS
|
||||
FROM ESTIMATE_MGMT AS T) AS CONTRACT_MGMT
|
||||
FROM ESTIMATE_MGMT AS T
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT CLIENT_NM, CEO_NM, BUS_REG_NO
|
||||
FROM CLIENT_MNG AS C
|
||||
WHERE 'C_' || C.OBJID::VARCHAR = T.CUSTOMER_OBJID
|
||||
AND T.CUSTOMER_OBJID LIKE 'C_%'
|
||||
) AS CL ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT SUPPLY_NAME, CODE_NAME(AREA_CD) AS AREA_CD_NAME, CHARGE_USER_NAME, REG_ID, BUS_REG_NO, REG_NO
|
||||
FROM SUPPLY_MNG AS O
|
||||
WHERE O.OBJID::VARCHAR = T.CUSTOMER_OBJID::VARCHAR
|
||||
AND T.CUSTOMER_OBJID NOT LIKE 'C_%'
|
||||
) AS SP ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
COUNT(1) FILTER (WHERE DOC_TYPE = 'estimate01') AS CU01_CNT,
|
||||
COUNT(1) FILTER (WHERE DOC_TYPE = 'estimate02') AS ADD_ESTIMATE_FILE_CNT
|
||||
FROM ATTACH_FILE_INFO
|
||||
WHERE TARGET_OBJID = T.OBJID
|
||||
AND DOC_TYPE IN ('estimate01', 'estimate02')
|
||||
AND UPPER(STATUS) = 'ACTIVE'
|
||||
) AS FC ON TRUE
|
||||
) AS CONTRACT_MGMT
|
||||
WHERE 1=1
|
||||
<if test="PRODUCT_CATEGORY !=null and PRODUCT_CATEGORY != '' ">
|
||||
AND PRODUCT_GROUP = #{PRODUCT_CATEGORY}
|
||||
@@ -3176,11 +3295,11 @@ SELECT
|
||||
</if>
|
||||
|
||||
<if test="contract_start_date != null and !''.equals(contract_start_date)">
|
||||
AND TO_DATE(TO_CHAR(TO_DATE(CONTRACT_DATE,'YYYYMMDD'),'YYYY-MM-DD'),'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{contract_start_date}, 'YYYY-MM-DD')
|
||||
AND TO_DATE(CONTRACT_DATE,'YYYYMMDD') <![CDATA[ >= ]]> TO_DATE(#{contract_start_date}, 'YYYY-MM-DD')
|
||||
|
||||
</if>
|
||||
<if test="contract_end_date != null and !''.equals(contract_end_date)">
|
||||
AND TO_DATE(TO_CHAR(TO_DATE(CONTRACT_DATE,'YYYYMMDD'),'YYYY-MM-DD'),'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{contract_end_date}, 'YYYY-MM-DD')
|
||||
AND TO_DATE(CONTRACT_DATE,'YYYYMMDD') <![CDATA[ <= ]]> TO_DATE(#{contract_end_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="status_cd != null and !''.equals(status_cd)">
|
||||
AND STATUS = #{status_cd}
|
||||
@@ -3240,6 +3359,7 @@ SELECT
|
||||
END AS CUS_REQUEST_DATE
|
||||
,DELIVERY_PLACE
|
||||
,PRODUCT_CODE
|
||||
,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = A.OBJID AND DOC_TYPE='estimate02' AND UPPER(STATUS) = 'ACTIVE') AS ADD_EST_CNT
|
||||
FROM ESTIMATE_MGMT A
|
||||
WHERE A.OBJID = #{objId}::NUMERIC
|
||||
</select>
|
||||
@@ -3302,13 +3422,13 @@ SELECT
|
||||
, #{qty }
|
||||
, #{warranty }
|
||||
<if test="product_price != null and !''.equals(product_price)">
|
||||
, #{product_price }::NUMERIC
|
||||
, #{product_price }::NUMERIC
|
||||
</if>
|
||||
<if test="other_price != null and !''.equals(other_price)">
|
||||
, #{other_price }::NUMERIC
|
||||
, #{other_price }::NUMERIC
|
||||
</if>
|
||||
<if test="total_price != null and !''.equals(total_price)">
|
||||
, #{total_price }::NUMERIC
|
||||
, #{total_price }::NUMERIC
|
||||
</if>
|
||||
, #{contract_user_id }
|
||||
, #{contract_date }
|
||||
@@ -3317,20 +3437,20 @@ SELECT
|
||||
, #{contract_office_no}
|
||||
, #{contract_fax_no }
|
||||
<if test="est_release_date != null and !''.equals(est_release_date)">
|
||||
,#{est_release_date}
|
||||
,#{est_release_date}
|
||||
</if>
|
||||
, NOW()
|
||||
, #{userId}
|
||||
,(SELECT TO_CHAR(NOW(),'yy')::VARCHAR ||'E-'||LPAD((SELECT NEXTVAL('estimate_mgmt_seq'))::VARCHAR ,4,'0'))
|
||||
<if test="contract_product_price != null and !''.equals(contract_product_price)">
|
||||
,#{contract_product_price}::NUMERIC
|
||||
,#{contract_product_price}::NUMERIC
|
||||
</if>
|
||||
,#{sale}
|
||||
,#{final_total_price}::NUMERIC
|
||||
,#{contract_type}
|
||||
,#{note}
|
||||
<if test="cus_request_date != null and !''.equals(cus_request_date)">
|
||||
,#{cus_request_date}
|
||||
,#{cus_request_date}
|
||||
</if>
|
||||
,#{delivery_place}
|
||||
,#{product_code}
|
||||
|
||||
@@ -25,6 +25,8 @@ import org.apache.ibatis.session.SqlSession;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.apache.pdfbox.multipdf.PDFMergerUtility;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -3406,6 +3408,42 @@ private String encodeImageToBase64(String imagePath) {
|
||||
* @param estimateTemplate
|
||||
* @return
|
||||
*/
|
||||
/**
|
||||
* 견적서 PDF + 추가견적(estimate02) PDF 파일들을 하나로 병합
|
||||
*/
|
||||
private File mergePdfWithAddEstimate(File estimatePdf, List<Map> addEstFiles) throws Exception {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String mergedFileName = estimatePdf.getName().replace(".pdf", "_merged.pdf");
|
||||
File mergedFile = new File(tempDir + File.separator + mergedFileName);
|
||||
|
||||
PDFMergerUtility merger = new PDFMergerUtility();
|
||||
merger.setDestinationFileName(mergedFile.getAbsolutePath());
|
||||
|
||||
// 1. 견적서 PDF 추가
|
||||
merger.addSource(estimatePdf);
|
||||
|
||||
// 2. 추가견적 PDF 파일들 추가
|
||||
for(Map fileInfo : addEstFiles) {
|
||||
String filePath = CommonUtils.checkNull(fileInfo.get("FILE_PATH"));
|
||||
if("".equals(filePath)) filePath = CommonUtils.checkNull(fileInfo.get("file_path"));
|
||||
String savedName = CommonUtils.checkNull(fileInfo.get("SAVED_FILE_NAME"));
|
||||
if("".equals(savedName)) savedName = CommonUtils.checkNull(fileInfo.get("saved_file_name"));
|
||||
if("".equals(savedName)) savedName = CommonUtils.checkNull(fileInfo.get("FILE_SAVED_NAME"));
|
||||
if("".equals(filePath)) filePath = Constants.FILE_STORAGE;
|
||||
|
||||
File addFile = new File(filePath + File.separator + savedName);
|
||||
if(addFile.exists() && addFile.getName().toLowerCase().endsWith(".pdf")) {
|
||||
merger.addSource(addFile);
|
||||
System.out.println("추가견적 PDF 병합 추가: " + addFile.getName());
|
||||
}
|
||||
}
|
||||
|
||||
merger.mergeDocuments(null);
|
||||
mergedFile.deleteOnExit();
|
||||
|
||||
return mergedFile;
|
||||
}
|
||||
|
||||
private File getPdfFromSession(String sessionId, Map estimateTemplate) {
|
||||
try {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
@@ -3539,18 +3577,37 @@ private String encodeImageToBase64(String imagePath) {
|
||||
}
|
||||
}
|
||||
|
||||
// 5. PDF 파일 처리
|
||||
// 5. PDF 파일 처리 (견적서 + 추가견적 PDF 병합)
|
||||
ArrayList<HashMap> attachFileList = new ArrayList<HashMap>();
|
||||
if(!"".equals(pdfSessionId)) {
|
||||
File pdfFile = getPdfFromSession(pdfSessionId, estimateTemplate);
|
||||
if(pdfFile != null && pdfFile.exists()) {
|
||||
// 추가견적(estimate02) PDF 파일 조회
|
||||
Map<String, Object> fileParam = new HashMap<String, Object>();
|
||||
fileParam.put("targetObjId", objId);
|
||||
fileParam.put("docType", "estimate02");
|
||||
List<Map> addEstFiles = sqlSession.selectList("common.getFileList", fileParam);
|
||||
|
||||
File finalPdf = pdfFile;
|
||||
|
||||
// 추가견적 PDF가 있으면 병합
|
||||
if(addEstFiles != null && !addEstFiles.isEmpty()) {
|
||||
try {
|
||||
finalPdf = mergePdfWithAddEstimate(pdfFile, addEstFiles);
|
||||
System.out.println("PDF 병합 완료: 견적서 + 추가견적 " + addEstFiles.size() + "건");
|
||||
} catch(Exception mergeEx) {
|
||||
System.out.println("PDF 병합 실패, 견적서만 첨부: " + mergeEx.getMessage());
|
||||
finalPdf = pdfFile;
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<String, String> fileMap = new HashMap<String, String>();
|
||||
fileMap.put(Constants.Db.COL_FILE_REAL_NAME, pdfFile.getName());
|
||||
fileMap.put(Constants.Db.COL_FILE_SAVED_NAME, pdfFile.getName());
|
||||
fileMap.put(Constants.Db.COL_FILE_PATH, pdfFile.getParent());
|
||||
fileMap.put(Constants.Db.COL_FILE_REAL_NAME, finalPdf.getName());
|
||||
fileMap.put(Constants.Db.COL_FILE_SAVED_NAME, finalPdf.getName());
|
||||
fileMap.put(Constants.Db.COL_FILE_PATH, finalPdf.getParent());
|
||||
attachFileList.add(fileMap);
|
||||
|
||||
System.out.println("PDF 파일 첨부 완료: " + pdfFile.getAbsolutePath());
|
||||
|
||||
System.out.println("PDF 파일 첨부 완료: " + finalPdf.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("PDF 파일을 찾을 수 없습니다: " + pdfSessionId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user