Files
sam-kd/estimate/common/output_lastJS.php
hskwon aca1767eb9 초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
2025-12-10 20:14:31 +09:00

934 lines
33 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
// 견적서의 lastJS를 변형해서 수주내역에서 인정제품의 거래명세표를 저장하기 위함이다.
// 수주리스트의 인정제품 거래명세표로 활용되는 코드
var ajaxRequest_write = null;
$(document).ready(function() {
$('#loadingOverlay').hide(); // 로딩 오버레이 숨기기
var dataList = <?php echo json_encode($detailJson ?? []); ?>;
// JSON 데이터를 처리하기 전에 유효성 검사
if (dataList && typeof dataList === 'string') {
try {
dataList = JSON.parse(dataList); // JSON 문자열을 객체로 변환
} catch (e) {
console.error('JSON parsing error: ', e);
dataList = []; // 오류 발생 시 빈 배열로 초기화
}
}
// 배열인지 확인
// console.log('dataList after JSON.parse check: ', dataList);
if (!Array.isArray(dataList)) {
dataList = [];
}
else
{
$("#updateText").text('견적수정됨');
}
// 테이블에 데이터 로드
loadTableData('#detailTable', dataList);
// 셔터박스 오류메시지 화면에 표시
var shutterboxMsg = <?= json_encode($shutterboxMsg) ?>;
// JavaScript로 처리
if (shutterboxMsg) {
var shutterboxDiv = document.getElementById("shutterboxMsg");
shutterboxDiv.style.display = "block"; // 보이게 설정
shutterboxDiv.innerHTML = shutterboxMsg; // 내용 설정
}
});
function loadTableData(tableBodySelector, dataList) {
console.log('loadTableData data: ', dataList); // 여기서 데이터 확인
var tableBody = $(tableBodySelector); // 테이블 본문 선택
// 데이터를 반복하면서 테이블에 행을 업데이트
var count = 1;
dataList.forEach(function(rowData, index) {
var row = tableBody.find('tr').eq(index + count); // index에 맞는 tr을 가져옴
if (row.length) {
updateRowData(row, rowData, index);
}
// console.log('index data: ', index); // 여기서 데이터 확인
// console.log('rowData data: ', rowData); // 여기서 데이터 확인
// count++;
});
}
// 기존 행을 수정하는 함수
function updateRowData(row, rowData, rowIndex) {
// 수정해야 할 td 요소들을 선택하여 해당 값을 업데이트
row.find('.su-input').val(rowData[0]); // 수량
row.find('.area-length-input').val(rowData[2]); // 길이
row.find('.area-price-input').val(rowData[3]); // 면적단가
row.find('.unit-price-input').val(rowData[4]); // 단가
// 수정된 행에 동적 계산 함수 호출
calculateRowTotal(row); // 필요 시 계산 함수 호출
}
function inputNumber(input) {
const value = input.value.replace(/,/g, ''); // 콤마 제거
input.value = parseInt(value, 10).toLocaleString(); // 다시 콤마 추가
calculateRowTotal($(input).closest('tr')); // 행의 합계 다시 계산
}
// 이벤트 리스너 설정 및 계산 함수 호출
function setupEventListeners() {
document.querySelectorAll('input').forEach(input => {
input.addEventListener('input', function () {
const row = input.closest('tr');
calculateRowTotal(row);
calculateAllSubtotals();
calculateGrandTotal();
calculateRowTotalFirstTable();
});
});
}
// 페이지 로드 시 초기 계산 및 이벤트 리스너 설정
window.onload = function () {
calculateAllSubtotals();
calculateGrandTotal();
setupEventListeners();
updateDiscountFooterRow();
calculateEstimateAmounts();
calculateRowTotalFirstTable();
};
$(document).ready(function () {
var rowArray = <?= isset($row_array_json) ? $row_array_json : '[]' ?>;
if (Array.isArray(rowArray) && rowArray.length > 0) {
rowArray.forEach(function (rowspanValue, index) {
var cell = document.getElementById('dynamicRowspan-' + index);
console.log('index', index);
if (cell && rowspanValue > 0) {
cell.setAttribute('rowspan', rowspanValue);
}
});
}
});
// 숫자 포맷팅 함수 (콤마 추가 및 소수점 둘째자리에서 반올림)
function formatNumber(value) {
// 소수점 둘째 자리에서 반올림
const roundedValue = value;
// 콤마 추가 포맷팅
return new Intl.NumberFormat().format(roundedValue);
}
// 숫자에서 콤마를 제거하는 함수
function cleanNumber(value) {
// value가 null 또는 undefined인 경우 0을 반환하도록 처리
if (!value) return 0;
return parseFloat(value.replace(/,/g, '')) || 0;
}
// 입력 필드에서 숫자를 포맷팅하는 함수
function inputNumber(input) {
const cursorPosition = input.selectionStart; // 현재 커서 위치를 저장
const value = input.value.replace(/,/g, ''); // 입력값에서 숫자만 남기고 제거
const formattedValue = Number(value).toLocaleString(); // 천 단위 콤마 추가
input.value = formattedValue; // 포맷팅된 값으로 설정
input.setSelectionRange(cursorPosition, cursorPosition); // 커서 위치 유지
}
// 세부내역 행별 합계 계산
function calculateRowTotal(row) {
// row를 jQuery 객체로 변환
row = $(row);
// jQuery 객체에서 값을 가져옴
const itemNameInput = row.find('.item-name');
const suInput = row.find('.su-input');
const areaLengthInput = row.find('.area-length-input');
const areaPriceInput = row.find('.area-price-input');
const unitPriceInput = row.find('.unit-price-input');
const su = suInput.length ? cleanNumber(suInput.val()) : 1;
const areaLength = areaLengthInput.length ? cleanNumber(areaLengthInput.val()) : 1;
const areaPrice = areaPriceInput.length ? cleanNumber(areaPriceInput.val()) : 1;
let unitPrice = unitPriceInput.length ? cleanNumber(unitPriceInput.val()) : 1;
const roundedAreaPrice = parseFloat(areaPrice);
if (roundedAreaPrice > 0) {
unitPrice = Math.round(Math.round(areaLength * roundedAreaPrice )); // 소수점 첫째자리 반올림
unitPriceInput.val(formatNumber(unitPrice)); // 단가 업데이트
}
let totalPrice = 0;
if (!areaLength && !areaPrice) {
totalPrice = Math.round(Math.round((su * unitPrice) ) );
} else if (areaLength && !areaPrice) {
totalPrice = Math.round(Math.round((areaLength * unitPrice * su) ) );
} else {
totalPrice = Math.round(Math.round((su * unitPrice) ) );
}
const totalCell = row.find('.total-price');
if (totalCell.length) {
if(totalPrice>200)
totalCell.text(formatNumber(totalPrice));
}
console.log('totalPrice', totalPrice);
console.log('itemNameInput', itemNameInput.text());
console.log('suInput', suInput.val());
console.log('areaLengthInput', areaLengthInput.val());
console.log('areaPriceInput', areaPriceInput.val());
console.log('unitPriceInput', unitPriceInput.val());
// return Math.round( parseInt(totalCell.text().replace(/,/g, '')) );
return totalPrice;
}
// 계산식 첫테이블의 일련번호별 소계 계산 (jQuery 방식)
function calculateSubtotalBySerial(serialNumber) {
let subtotal = 0;
let vat = 0;
let total = 0;
const rows = $(`.calculation-row[data-serial="${serialNumber}"]`);
rows.each(function() {
// Math.round()는 소수점 이하를 반올림 (예: 1.4 -> 1, 1.5 -> 2)
// Math.ceil()은 소수점 이하를 무조건 올림 (예: 1.1 -> 2, 1.9 -> 2)
// Math.floor()는 소수점 이하를 무조건 버림 (예: 1.1 -> 1, 1.9 -> 1)
const rowTotal = calculateRowTotal($(this)); // 300 이하는 일련번호로 취급한다. 안전장치이다.
if (rowTotal > 300) {
subtotal += rowTotal;
}
console.log(' calculateSubtotalBySerial subtotal', subtotal);
});
vat = Math.round(subtotal * 0.1);
total = subtotal + vat;
const subtotalCells = $(`.subtotal-cell[data-serial="${serialNumber}"]`);
const vatCells = $(`.vat-cell[data-serial="${serialNumber}"]`);
const totalCells = $(`.subtotalamount-cell[data-serial="${serialNumber}"]`);
if (subtotalCells.length > 0) {
subtotalCells.each(function() {
$(this).text(formatNumber(subtotal));
});
} else {
console.error(`소계 셀을 찾을 수 없습니다. 일련번호: ${serialNumber}`);
}
if (vatCells.length > 0) {
vatCells.each(function() {
$(this).text(formatNumber(vat));
});
}
if (totalCells.length > 0) {
totalCells.each(function() {
$(this).text(formatNumber(total));
});
}
return subtotal;
}
// 모든 일련번호별 소계 및 총합계 계산 (jQuery 방식)
function calculateAllSubtotals() {
let grandTotal = 0;
const uniqueSerials = new Set();
$('.calculation-row').each(function() {
uniqueSerials.add($(this).data('serial'));
});
uniqueSerials.forEach(function(serialNumber) {
grandTotal += calculateSubtotalBySerial(serialNumber);
});
return grandTotal;
}
// 숫자만 남기는 헬퍼
function cleanNumber(str) {
return Number(String(str).replace(/[^0-9.-]/g, '')) || 0;
}
// 3자리마다 콤마 찍되, 먼저 소수점 이하는 반올림 처리
function formatNumber(num) {
// 1) 문자열이면 콤마 없애고 숫자로 변환
const value = typeof num === 'string'
? parseFloat(num.replace(/,/g, ''))
: num;
// 2) 소수점 이하 반올림
const rounded = Math.round(value || 0);
// 3) 천 단위 구분자 추가
return rounded.toLocaleString();
}
// 1) grand total 계산 후, 차액까지 계산
function calculateGrandTotal() {
// 소수점 이하를 반올림해서 정수 와 원 단위만 남김
const rawTotal = calculateAllSubtotals();
const rawVat = Math.round(rawTotal * 0.1);
const grandTotal = rawTotal;
const rawSumTotal = grandTotal + rawVat;
let finalTotal = 0;
if (rawVat > 0) {
finalTotal = rawSumTotal;
} else {
finalTotal = grandTotal;
}
const grandTotalCells = $('.grand-total');
if (grandTotalCells.length > 0) {
grandTotalCells.each(function() {
$(this).text(formatNumber(grandTotal));
});
$('#totalsum').text(formatNumber(finalTotal));
// 한글 금액 표기도 반올림된 정수로
$('#koreantotalsum').text(KoreanNumber(finalTotal));
const firstSum = cleanNumber($("#EstimateFirstSum").val());
if (grandTotal > 0 && rawVat> 0 && firstSum < 1) {
$("#EstimateFirstSum").val(formatNumber(finalTotal));
} else {
$("#EstimateUpdatetSum").val(formatNumber(finalTotal));
}
const updatedSum = cleanNumber($("#EstimateUpdatetSum").val());
if (updatedSum > 0) {
$("#EstimateDiffer").val(formatNumber(updatedSum - cleanNumber($("#EstimateFirstSum").val())));
} else {
$("#EstimateDiffer").val(0);
}
} else {
console.error("전체 합계 셀을 찾을 수 없습니다. '.grand-total' 클래스 확인하세요.");
}
let grandVatCells = $('.grand-vat');
if (grandVatCells.length > 0) {
grandVatCells.each(function() {
$(this).text(formatNumber(rawVat));
});
} else {
console.error("전체 합계 셀을 찾을 수 없습니다. '.grand-vat' 클래스 확인하세요.");
}
let grandSumCells = $('.grand-sum');
if (grandSumCells.length > 0) {
grandSumCells.each(function() {
$(this).text(formatNumber(rawSumTotal));
});
} else {
console.error("전체 합계 셀을 찾을 수 없습니다. '.grand-sum' 클래스 확인하세요.");
}
}
// 2) '견적확정액', '할인금액', '최종결정금액' 계산 함수
function calculateEstimateAmounts() {
// 1) 자동견적(=EstimateFirstSum) / 수동견적(=EstimateUpdatetSum) 값 가져오기
const autoSum = cleanNumber($("#EstimateFirstSum").val());
let manualSum = cleanNumber($("#EstimateUpdatetSum").val());
// ★ 수동견적과 자동견적이 같으면 수동견적을 지워서 나오지 않게
if (manualSum > 0 && manualSum === autoSum) {
manualSum = 0;
$("#EstimateUpdatetSum").val('');
}
// 2) 견적확정액 결정: 수동견적 있으면 수동, 없으면 자동
const fixAmount = manualSum > 0 ? manualSum : autoSum;
$("#EstimateFixAmount").val(formatNumber(fixAmount));
// 3) 할인금액 = 견적확정액 × 할인율 ÷ 100
const discountRate = $("#EstimateDiscountRate").val();
let discountAmt = fixAmount * discountRate / 100 ;
const subtotal = cleanNumber($('#subtotalamount').text());
let finalTotal = 0;
let finalRounded = 0;
if (discountRate > 0 ) {
finalTotal = subtotal - discountAmt;
// 1000원 미만 절사
finalRounded = Math.floor(finalTotal / 1000) * 1000;
}
else
{
finalTotal = subtotal ;
finalRounded = finalTotal ;
}
discountAmt += (finalTotal - finalRounded);
$("#EstimateDiscount").val(formatNumber(discountAmt));
// 4) 최종결정금액 = 견적확정액 할인금액
const finalSum = fixAmount - discountAmt;
$("#EstimateFinalSum").val(formatNumber(finalSum));
// → 할인/최종 합계 row 갱신
updateDiscountFooterRow();
}
// 첫 번째 테이블: 행별 합계 계산 (jQuery 방식)
function calculateRowTotalFirstTable() {
const rows = $('.calculation-firstrow');
rows.each(function() {
const suInput = $(this).find('.total-su-input'); // 수량 입력 필드
const subtotalCell = $(this).find('.subtotal-cell'); // 소계 셀
const unitPriceCell = $(this).find('.total-unit-price-input'); // 단가 셀
const su = suInput ? cleanNumber(suInput.text()) : 1;
const subtotal = subtotalCell ? cleanNumber(subtotalCell.text()) : 0;
let unitPrice = 0;
if (su > 0) {
unitPrice = subtotal / su; // 소계를 수량으로 나눠서 단가 계산
}
if (unitPriceCell.length) {
unitPriceCell.text(formatNumber(unitPrice)); // 단가 셀에 표시
}
});
}
function KoreanNumber(number) {
const koreanNumbers = ['', '일', '이', '삼', '사', '오', '육', '칠', '팔', '구'];
const koreanUnits = ['', '십', '백', '천'];
const bigUnits = ['', '만', '억', '조'];
let result = '';
let unitIndex = 0;
let numberStr = String(number);
// 숫자가 0인 경우 '영원'을 반환
if (number == 0) return '영원';
// 뒤에서부터 4자리씩 끊어서 처리
while (numberStr.length > 0) {
let chunk = numberStr.slice(-4); // 마지막 4자리
numberStr = numberStr.slice(0, -4); // 나머지 숫자
let chunkResult = '';
for (let i = 0; i < chunk.length; i++) {
const digit = parseInt(chunk[i]);
if (digit > 0) {
chunkResult += koreanNumbers[digit] + koreanUnits[chunk.length - i - 1];
}
}
if (chunkResult) {
result = chunkResult + bigUnits[unitIndex] + result;
}
unitIndex++;
}
// 불필요한 '일십', '일백', '일천' 등의 단위를 제거하고 '원'을 붙여 반환
result = result.replace(/일(?=십|백|천)/g, '').trim();
return result + '';
}
function removeAllButLastOccurrence(string, target) {
// 마지막 '만'의 위치를 찾습니다
const lastPos = string.lastIndexOf(target);
// 마지막 '만'이 없으면 원래 문자열을 반환합니다
if (lastPos === -1) {
return string;
}
// 마지막 '만'을 제외한 모든 '만'을 제거합니다
const beforeLastPos = string.slice(0, lastPos);
const afterLastPos = string.slice(lastPos);
// '만'을 빈 문자열로 대체합니다
const result = beforeLastPos.replace(new RegExp(target, 'g'), '') + afterLastPos;
return result;
}
$(document).ready(function() {
// 저장 버튼 클릭 시 saveData 함수 호출
$(".saveBtn").click(function() {
saveData();
});
});
function saveData() {
const myform = document.getElementById('board_form');
let allValid = true;
if (!allValid) return;
var num = $("#num").val();
$("#overlay").show();
$("button").prop("disabled", true);
// 모드 설정 (insert 또는 modify)
if ($("#mode").val() !== 'copy') {
if (Number(num) < 1) {
$("#mode").val('insert');
} else {
$("#mode").val('modify');
}
} else {
$("#mode").val('insert');
}
// 데이터 수집 (input 요소만 저장)
let formData = [];
$('#detailTable tbody tr').each(function() {
let rowData = [];
// 각 tr의 input 요소 순서대로 처리
$(this).find('input, select').each(function() {
let value = $(this).val();
rowData.push(value); // input 값을 배열에 순서대로 추가
});
formData.push(rowData); // 각 행의 input 데이터를 배열에 추가
});
// formData는 이제 각 행의 input 값들만 포함하는 배열입니다.
// console.log('formData:', formData);
// JSON 문자열로 변환하여 form input에 설정
let jsonString = JSON.stringify(formData);
$('#detailJson').val(jsonString);
// console.log('detailJson', jsonString);
$("#estimateSurang").val('<?= $estimateSurang ?>'); // 수량 저장
$("#estimateTotal").val($("#EstimateFinalSum").val()); // 최종 결정금액 저장
// 총금액 계산 (콤마 제거 후 숫자로 변환)
const unapproved = parseFloat(($("#ET_unapproved").val() || "0").replace(/,/g, ''));
const approved = parseFloat(($("#estimateTotal").val() || "0").replace(/,/g, ''));
const total = unapproved + approved;
$("#ET_total").val(total.toLocaleString()); // 최종 결정금액 저장
if (window.opener && !window.opener.closed) {
const $parent = window.opener.$; // 부모창의 jQuery 사용
// 수량은 있는 그대로
if ($parent("#estimateSurang").length) {
$parent("#estimateSurang").val($("#estimateSurang").val());
}
// 금액들은 toLocaleString()으로 콤마 포함
if ($parent("#estimateTotal").length) {
$parent("#estimateTotal").val(approved.toLocaleString());
}
if ($parent("#ET_unapproved").length) {
$parent("#ET_unapproved").val(unapproved.toLocaleString());
}
if ($parent("#ET_total").length) {
$parent("#ET_total").val(total.toLocaleString());
}
}
var form = $('#board_form')[0];
var datasource = new FormData(form);
if (ajaxRequest_write !== null) {
ajaxRequest_write.abort();
}
showMsgModal(2); // 파일저장중
// Ajax 요청으로 서버에 데이터 전송
ajaxRequest_write = $.ajax({
enctype: 'multipart/form-data',
processData: false,
contentType: false,
cache: false,
timeout: 600000,
url: "/estimate/insert_detail_output.php", // 산출내역 저장
type: "post",
data: datasource,
dataType: "json",
success: function(data) {
console.log(data);
setTimeout(function() {
$(opener.location).attr("href", "javascript:restorePageNumber();");
setTimeout(function() {
hideMsgModal();
hideOverlay();
window.close();
}, 1000);
}, 1000);
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
}
function generatePDF() {
var title_message = '<?php echo $title_message; ?>';
var workplace = '<?php echo $outworkplace; ?>';
var deadline = '<?php echo $indate; ?>';
var deadlineDate = new Date(deadline);
var formattedDate = "(" + String(deadlineDate.getFullYear()).slice(-2) + "." + ("0" + (deadlineDate.getMonth() + 1)).slice(-2) + "." + ("0" + deadlineDate.getDate()).slice(-2) + ")";
var result = 'KD' + title_message + '(' + workplace +')' + formattedDate + '.pdf';
var element = document.getElementById('content-to-print');
var opt = {
margin: [10, 3, 12, 3], // Top, right, bottom, left margins
filename: result,
image: { type: 'jpeg', quality: 1 },
html2canvas: {
scale: 3, // ★★★ 해상도(기본은 1) → 2~4 정도로 높이면 선명해짐 4는 용량이 매우 큽니다. 보통 3M 이상
useCORS: true,
scrollY: 0,
scrollX: 0,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight
},
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: {
mode: ['css', 'legacy'],
avoid: ['tr', '.avoid-break'] // 핵심
}
};
html2pdf().from(element).set(opt).save();
}
function generatePDF_server(callback) {
var workplace = '<?php echo $title_message; ?>';
var item = '<?php echo $emailTitle; ?>';
var today = new Date();
var formattedDate = "(" + String(today.getFullYear()).slice(-2) + "." + ("0" + (today.getMonth() + 1)).slice(-2) + "." + ("0" + today.getDate()).slice(-2) + ")";
var result = 'KD' + item +'(' + workplace + ')' + formattedDate + '.pdf';
var element = document.getElementById('content-to-print');
var opt = {
margin: [10, 3, 12, 3], // Top, right, bottom, left margins
filename: result,
image: { type: 'jpeg', quality: 0.70 },
html2canvas: { scale: 4 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: [''] }
};
html2pdf().from(element).set(opt).output('datauristring').then(function (pdfDataUri) {
var pdfBase64 = pdfDataUri.split(',')[1]; // Base64 인코딩된 PDF 데이터 추출
var formData = new FormData();
formData.append('pdf', pdfBase64);
formData.append('filename', result);
$.ajax({
type: 'POST',
url: '/email/save_pdf.php', // PDF 파일을 저장하는 PHP 파일
data: formData,
processData: false,
contentType: false,
success: function (response) {
var res = JSON.parse(response);
if (callback) {
callback(res.filename); // 서버에 저장된 파일 경로를 콜백으로 전달
}
},
error: function (xhr, status, error) {
Swal.fire('Error', 'PDF 저장에 실패했습니다.', 'error');
}
});
});
}
var ajaxRequest = null;
function sendmail() {
var secondordnum = '<?php echo $secondordnum; ?>'; // 서버에서 가져온 값
var item = '<?php echo $emailTitle; ?>';
if (!secondordnum) {
Swal.fire({
icon: 'warning',
title: '오류 알림',
text: '발주처 코드가 없습니다.'
});
return; // 함수 종료
}
if (typeof ajaxRequest !== 'undefined' && ajaxRequest !== null) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
type: 'POST',
url: '/email/get_companyCode.php',
data: { secondordnum: secondordnum },
dataType: 'json',
success: function(response) {
console.log('response : ', response);
if (response.error) {
Swal.fire('Error', response.error, 'error');
} else {
var email = response.email;
var vendorName = response.vendor_name;
Swal.fire({
title: 'E메일 보내기',
text: vendorName + ' Email 주소확인',
icon: 'warning',
input: 'text', // input 창을 텍스트 필드로 설정
inputLabel: 'Email 주소 수정 가능',
inputValue: email, // 기존 이메일 주소를 기본값으로 설정
showCancelButton: true,
confirmButtonText: '보내기',
cancelButtonText: '취소',
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return '이메일 주소를 입력해주세요!';
}
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailPattern.test(value)) {
return '올바른 이메일 형식을 입력해주세요!';
}
}
}).then((result) => {
if (result.isConfirmed) {
const updatedEmail = result.value; // 입력된 이메일 주소 가져오기
generatePDF_server(function(filename) {
sendEmail(updatedEmail, vendorName, item, filename);
});
}
});
}
},
error: function(xhr, status, error) {
Swal.fire('Error', '전송중 오류가 발생했습니다.', 'error');
}
});
}
function sendEmail(recipientEmail, vendorName, item, filename) {
if (typeof ajaxRequest !== 'undefined' && ajaxRequest !== null) {
ajaxRequest.abort();
}
var today = new Date();
var formattedDate = "(" + String(today.getFullYear()).slice(-2) + "." + ("0" + (today.getMonth() + 1)).slice(-2) + "." + ("0" + today.getDate()).slice(-2) + ")";
ajaxRequest = $.ajax({
type: 'POST',
url: '/email/send_email.php', // 이메일 전송을 처리하는 PHP 파일
data: { email: recipientEmail, vendorName: vendorName, filename: filename, item: item, formattedDate: formattedDate },
success: function(response) {
console.log(response);
Swal.fire('Success', '정상적으로 전송되었습니다.', 'success');
},
error: function(xhr, status, error) {
Swal.fire('Error', '전송에 실패했습니다. 확인바랍니다.', 'error');
}
});
}
$(document).ready(function() {
// 재계산 버튼 클릭 이벤트
$('.initialBtn').on('click', function() {
// 재계산 확인 알림
Swal.fire({
title: '견적데이터 재계산',
text: "견적 데이터를 재계산 하시겠습니까?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '예, 재계산합니다',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$("#estimateTotal").val(0); // 견적총액 저장
$("#EstimateFirstSum").val(0); // 견적초기금액
$("#EstimateUpdatetSum").val(0); // 수정금액
$("#EstimateDiffer").val(0); // 차액금액
$("#EstimateDiscountRate").val(0); // 할인율
$("#EstimateDiscount").val(0); // 할인금액
$("#EstimateFinalSum").val(0); // 최종결정금액
var form = $('#board_form')[0];
var datasource = new FormData(form);
const initialData = JSON.stringify([]); // 빈 배열로 재계산
$('#detailJson').val(initialData);
// 재계산된 데이터 저장 요청
$.ajax({
enctype: 'multipart/form-data',
processData: false,
contentType: false,
cache: false,
timeout: 600000,
url: "/estimate/insert_detail_output.php",
type: "post",
data: datasource,
dataType: "json",
success: function(response) {
Swal.fire({
title: '재계산 완료',
text: "모든 데이터가 재계산되었습니다.",
icon: 'success',
confirmButtonText: '확인'
}).then(() => {
hideMsgModal();
// 페이지 새로고침
location.reload();
});
},
error: function(jqxhr, status, error) {
Swal.fire({
title: '오류',
text: "재계산 중 오류가 발생했습니다.",
icon: 'error',
confirmButtonText: '확인'
});
console.log("AJAX Error: ", status, error);
}
});
}
});
});
});
// ───────────────────────────────────────────────────
// 할인/최종 합계 표시 함수 (이미 정의된 cleanNumber, formatNumber 사용)
function updateDiscountFooterRow() {
const rate = $('#EstimateDiscountRate').val();
const subtotal = cleanNumber($('#subtotalamount').text());
// 기존 tfoot 제거
$('#tableDetail tfoot').remove();
let discount = 0;
let finalTotal = 0;
let finalRounded = 0;
if (rate <= 0 ) {
discount = 0;
finalTotal = subtotal;
finalRounded = finalTotal;
} else {
discount = Math.round(subtotal * Number(rate) / 100);
finalTotal = subtotal - discount;
finalRounded = Math.floor(finalTotal / 1000) * 1000;
discount += (finalTotal - finalRounded);
}
if (rate > 0) {
const tfootHTML = `
<tfoot>
<tr class="bg-light">
<td colspan="8" class="text-end fw-bold">할인금액</td>
<td colspan="4" class="text-end text-danger"> - ${formatNumber(discount)}</td>
</tr>
<tr class="bg-secondary text-white">
<td colspan="8" class="text-end fw-bold">최종 합계</td>
<td colspan="4" class="text-end fw-bold">${formatNumber(finalRounded)}</td>
</tr>
</tfoot>
`;
$('#tableDetail').append(tfootHTML);
// 화면 하단 두 요소에도 최종합계 반영
$('#totalsum').text(formatNumber(finalRounded));
$('#koreantotalsum').text(KoreanNumber(finalRounded));
}
}
// ───────────────────────────────────────────────────
// 페이지 로드 시 & 할인율 변경 시 바인딩만 추가
$(document).ready(function() {
setTimeout(function() {
updateDiscountFooterRow();
}, 1000);
});
$(document).ready(function() {
// 산출내역서 보이기/숨기기
function toggleEstimateView() {
$('#showEstimateCheckbox').is(':checked')
? $('.Estimateview').show()
: $('.Estimateview').hide();
}
// 소요자재 보이기/숨기기 (vendor-send 토글 로직 제거)
function toggleListView() {
$('#showlistCheckbox').is(':checked')
? $('.listview, .vendor-send, .Novendor-send').show()
: $('.listview, .vendor-send, .Novendor-send').hide();
}
// 업체발송용 영역 토글
function toggleVendorDiv() {
// 업체발송용 클릭시 나머지 두개의 체크박스를 해제한다.
$('#showEstimateCheckbox').prop('checked', false);
$('#showlistCheckbox').prop('checked', false);
toggleEstimateView();
toggleListView();
if ($('#showVendorCheckbox').is(':checked')) {
$('.vendor-send').show();
$('.Novendor-send').hide();
} else {
$('.vendor-send').hide();
$('.Novendor-send').show();
}
}
var option = $('#option').val(); // option은 견적서 화면에서 업체발송용으로 강제 지정
if (option === 'option') {
// 초기 상태 반영
toggleEstimateView();
toggleListView();
toggleVendorDiv();
}
// 산출내역서 체크박스 이벤트
$('#showEstimateCheckbox').on('change', toggleEstimateView);
// 소요자재 체크박스 이벤트
$('#showlistCheckbox').on('change', function() {
toggleListView();
// 소요자재 클릭 시 "업체발송용" 체크 해제 + 영역 토글
$('#showVendorCheckbox').prop('checked', false);
});
// 업체발송용 체크박스 이벤트
$('#showVendorCheckbox').on('change', toggleVendorDiv);
// 할인율 변경시
$('#EstimateDiscountRate').on('input change', function() {
updateDiscountFooterRow();
calculateEstimateAmounts();
});
});
</script>