// REA TFRMCONVERTTOGANGUB (0xf616f0, 0xf61888) // 자재단가(StuffcDat) 부가세 계산: 포함(*1.1) / 제외(/1.1) 및 단단위 자릿수(사사오입/절하/절상) 처리 const EstVat = (() => { const { num, fixed, even } = EstMath; // REA radCalcMethod: 0 = 부가세포함(×1.1), 1 = 부가세제외(÷1.1) // REA radDigetIndex: 0 = 사사오입(1), 1 = 절하(2), 2 = 절상(3) const methodMap = { 0: 1, 1: 2, 2: 3 }; function convertPrice(value, calcMethod = 1, diget = 0, digetMethod = 1) { const rawNum = num(value); if (!rawNum) return 0; const factor = calcMethod === 0 ? 1.1 : 1 / 1.1; const scaled = rawNum * factor; // diget: 이하 자리에서 처리 (예: 1이면 1원 미만=0자리, 2이면 10원 미만=-1자리, 또는 소수/정수) // REA 관례: 0이면 원단위(0), n > 0이면 10^n 미만(-n) 또는 소수점 // 일반적으로 단단위계산에서 spnDiget은 자리수를 나타냄. 0이면 정수 원단위(0), n이면 -n 단위 절하/사사오입/절상. const digits = -Math.max(0, Math.trunc(num(diget))); if (digetMethod === 2) { const step = 10 ** -digits; return Math.ceil(even(scaled * 10000) / 10000 / step) * step; } const m = methodMap[digetMethod] ?? 2; return fixed(scaled, digits, m); } function apply(project, indices = [], { calcMethod = 1, diget = 0, digetMethod = 1 } = {}) { const next = structuredClone(project); const rows = next.tables.StuffcDat || []; const targets = indices.length ? indices.filter((i) => i >= 0 && i < rows.length) : rows.map((_, i) => i); if (!targets.length) throw Error("적용할 자재 항목이 없습니다."); for (const index of targets) { const row = rows[index]; // Cost1 ~ Cost6 및 InputTC/TC 중 존재하는 단가 필드 변환 let changed = false; for (let c = 1; c <= 6; c++) { const key = `Cost${c}`; if (row[key] != null && row[key] !== "") { row[key] = convertPrice(row[key], calcMethod, diget, digetMethod); changed = true; } } if (row.InputTC != null && row.InputTC !== "") { row.InputTC = convertPrice(row.InputTC, calcMethod, diget, digetMethod); changed = true; } if (row.TC != null && row.TC !== "") { row.TC = convertPrice(row.TC, calcMethod, diget, digetMethod); changed = true; } } return next.options?.AutoCalc === false ? next : EstNative.calculate(next); } return { convertPrice, apply, }; })();