- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경 - DB 연결 하드코딩 → .env 기반으로 변경 - MySQL strict mode DATE 오류 수정
182 lines
5.3 KiB
JavaScript
182 lines
5.3 KiB
JavaScript
// jQuery 의존성 확인
|
|
if (typeof jQuery === 'undefined') {
|
|
console.error('jQuery is required for calculation.js');
|
|
}
|
|
|
|
// 계산 로직을 위한 기본 클래스
|
|
class BaseCalculator {
|
|
constructor() {
|
|
this.cleanNumber = this.cleanNumber.bind(this);
|
|
this.formatNumber = this.formatNumber.bind(this);
|
|
}
|
|
|
|
// 숫자만 남기는 헬퍼
|
|
cleanNumber(str) {
|
|
return Number(String(str).replace(/[^0-9.-]/g, '')) || 0;
|
|
}
|
|
|
|
// 3자리마다 콤마 찍되, 먼저 소수점 이하는 반올림 처리
|
|
formatNumber(num) {
|
|
const value = typeof num === 'string'
|
|
? parseFloat(num.replace(/,/g, ''))
|
|
: num;
|
|
const rounded = Math.round(value || 0);
|
|
return rounded.toLocaleString();
|
|
}
|
|
|
|
// 행별 합계 계산 (기본 구현)
|
|
calculateRowTotal(row) {
|
|
throw new Error('calculateRowTotal must be implemented by subclass');
|
|
}
|
|
}
|
|
|
|
// 견적서 계산 클래스
|
|
class EstimateCalculator extends BaseCalculator {
|
|
calculateRowTotal(row) {
|
|
row = $(row);
|
|
|
|
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 ? this.cleanNumber(suInput.val()) : 1;
|
|
const areaLength = areaLengthInput.length ? this.cleanNumber(areaLengthInput.val()) : 1;
|
|
const areaPrice = areaPriceInput.length ? this.cleanNumber(areaPriceInput.val()) : 1;
|
|
let unitPrice = unitPriceInput.length ? this.cleanNumber(unitPriceInput.val()) : 1;
|
|
|
|
const roundedAreaPrice = parseFloat(areaPrice.toFixed(2));
|
|
|
|
if (roundedAreaPrice > 0) {
|
|
unitPrice = Math.ceil(areaLength * roundedAreaPrice);
|
|
unitPriceInput.val(this.formatNumber(unitPrice));
|
|
}
|
|
|
|
let totalPrice;
|
|
if (!areaLength && !areaPrice) {
|
|
totalPrice = su * unitPrice;
|
|
} else if (areaLength && !areaPrice) {
|
|
totalPrice = areaLength * unitPrice;
|
|
} else {
|
|
totalPrice = su * unitPrice;
|
|
}
|
|
|
|
const totalCell = row.find('.total-price');
|
|
if (totalCell.length) {
|
|
totalCell.text(this.formatNumber(totalPrice));
|
|
}
|
|
|
|
return totalPrice;
|
|
}
|
|
}
|
|
|
|
// 거래명세표 계산 클래스
|
|
class TransactionCalculator extends BaseCalculator {
|
|
calculateRowTotal(row) {
|
|
row = $(row);
|
|
|
|
const suInput = row.find('.su-input');
|
|
const unitPriceInput = row.find('.unit-price-input');
|
|
const supplyPriceCell = row.find('.supply-price');
|
|
const taxCell = row.find('.tax-price');
|
|
const totalCell = row.find('.total-price');
|
|
|
|
const su = suInput.length ? this.cleanNumber(suInput.val()) : 1;
|
|
const unitPrice = unitPriceInput.length ? this.cleanNumber(unitPriceInput.val()) : 0;
|
|
|
|
// 공급가액 계산
|
|
const supplyPrice = su * unitPrice;
|
|
|
|
// 부가세 계산 (10%)
|
|
const tax = Math.round(supplyPrice * 0.1);
|
|
|
|
// 합계 계산
|
|
const totalPrice = supplyPrice + tax;
|
|
|
|
// 각 셀에 값 표시
|
|
if (supplyPriceCell.length) {
|
|
supplyPriceCell.text(this.formatNumber(supplyPrice));
|
|
}
|
|
if (taxCell.length) {
|
|
taxCell.text(this.formatNumber(tax));
|
|
}
|
|
if (totalCell.length) {
|
|
totalCell.text(this.formatNumber(totalPrice));
|
|
}
|
|
|
|
return totalPrice;
|
|
}
|
|
}
|
|
|
|
// 계산기 팩토리
|
|
class CalculatorFactory {
|
|
static createCalculator(type) {
|
|
switch(type) {
|
|
case 'estimate':
|
|
return new EstimateCalculator();
|
|
case 'transaction':
|
|
return new TransactionCalculator();
|
|
default:
|
|
throw new Error('Unknown calculator type');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 전역 계산기 인스턴스
|
|
let calculator = null;
|
|
|
|
// 계산기 초기화 함수
|
|
function initializeCalculator(type) {
|
|
calculator = CalculatorFactory.createCalculator(type);
|
|
}
|
|
|
|
// 기존 함수들을 새로운 클래스 기반으로 래핑
|
|
function calculateRowTotal(row) {
|
|
if (!calculator) {
|
|
console.error('Calculator not initialized');
|
|
return 0;
|
|
}
|
|
return calculator.calculateRowTotal(row);
|
|
}
|
|
|
|
function calculateSubtotalBySerial(serialNumber) {
|
|
if (!calculator) {
|
|
console.error('Calculator not initialized');
|
|
return 0;
|
|
}
|
|
|
|
let subtotal = 0;
|
|
const rows = $(`.calculation-row[data-serial="${serialNumber}"]`);
|
|
|
|
rows.each(function() {
|
|
subtotal += calculator.calculateRowTotal($(this));
|
|
});
|
|
|
|
const subtotalCells = $(`.subtotal-cell[data-serial="${serialNumber}"]`);
|
|
if (subtotalCells.length > 0) {
|
|
subtotalCells.each(function() {
|
|
$(this).text(calculator.formatNumber(subtotal));
|
|
});
|
|
}
|
|
|
|
return subtotal;
|
|
}
|
|
|
|
function calculateAllSubtotals() {
|
|
if (!calculator) {
|
|
console.error('Calculator not initialized');
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|