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

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