// REA f18804 → f16638 / f15868 / f15f40 / f16320 → f16ec8. const EstMachine = (() => { const { num, components, fixed, floating, even, sum } = EstMath; const fuels = new Set([ "주연료", "선박용경유", "전력", "경유", "휘발유", "중유", "전", "가스", "가솔린", "디젤", "diesel", "gasoline", "heavyoil", "lpg", "l.p.g", ]); function calculate(rows, criteria, options = {}) { const settings = new Map(criteria.map((row) => [num(row.Index), num(row.TC)])); const get = (index) => settings.get(index) ?? 0; const output = structuredClone(rows), titles = [], errors = []; let head = null, body = []; function finish() { if (!head) return; components.forEach( (key) => (head[key] = floating( body.filter((r) => num(r.CalcIndex) < 2).reduce((n, r) => n + num(r[key]), 0), )), ); head.TC = sum(head); titles.push({ ...head, OTC: head.TC, ONC: head.NC, OGC: head.GC, OJC: head.JC, OSC: head.SC, }); } for (const row of output) { const index = num(row.Index), link = num(row.LinkIndex); if (index > 0 && link !== 57) { finish(); head = row; body = []; continue; } if (!head || row.Index == null) continue; if (link === 52) { finish(); const title = titles[titles.length - 1], rate = num(row.GN) / 100; components.forEach((key) => (head[key] = floating(num(title[key]) * rate))); head.TC = sum(head); Object.assign(title, head, { NachalRatio: num(row.GN) }); row.TU = title.OTC; head = null; body = []; continue; } if (![0, 2].includes(num(row.CalcIndex))) { body.push(row); continue; } components.forEach((key) => (row[key] = 0)); const q = num(row.GN) / (["%", "%"].includes(row.Unite) ? 100 : 1), rate = 1 + num(row.Ratio) / 100; const digits = EstMath.even(get(index)); let value = 0, field = "JC"; if (index === -3) { const currency = String(row.Unite || "")[0]; if (currency === "\\") value = num(row.TU) * q * 1e-7; else if ("$PEFLMY".includes(currency || "\u0000")) { let exchange = get(currency.charCodeAt(0)); if (currency === "L" && !settings.has(76)) exchange = get(70); if (currency === "Y") exchange /= 100; if (!exchange) errors.push(`${head.Name}: 환율 없음 (${currency})`); const cut = options.DollarCostCut ? 1000 : 1; // f1580c receives two Currency integers; binary float multiplication can // turn an exact thousand (226644000) into the previous thousand. const converted = Number( (BigInt(even(num(row.TU) * 10000)) * BigInt(even(exchange * 10000))) / BigInt(cut * 100000000), ) * cut; value = converted * q * 1e-7; } else value = num(row.TU) * q; value = fixed((even(value * 10000) / 10000) * rate, digits); } else if (index === -2) { let unitPrice = num(row.TU), quantity = q; if (String(row.Name || "").includes("잡")) { const fuel = [...body].reverse().find( (r) => num(r.Index) === -2 && fuels.has( String(r.Name || "") .replace(/\s/g, "") .toLowerCase(), ), ); unitPrice = fuel ? num(fuel.GC) || (num(fuel.SCheck) === 3 ? num(fuel.JC) : 0) : 0; row.TU = unitPrice; row.Unite = "%"; quantity = num(row.GN) / 100; } value = fixed(even(even(unitPrice * quantity * 10000) * rate) / 10000, digits); field = num(row.SCheck) === 3 ? "JC" : "GC"; } else if (index === -1) { const coefficient = Math.trunc(get(num(row.NCGasu)) * 1e10) / 1e10; let price = num(row.TU) * coefficient; if (options.JDLCalcMethod) price = floating(price, 1); value = fixed(even(even(price * q * 10000) * rate) / 10000, digits); field = "NC"; } row[field] = value; row.TC = sum(row); body.push(row); } finish(); return { rows: output, titles, errors }; } let page = 0; function usage(project) { const titles = project.tables?.MachTitleDat || []; const grps = EstNative.groups(project.tables?.MachMainDat || []); return titles.map((title, index) => { const code = title.Code || ""; const group = grps.get(code); const appliedPrice = EstMath.num(title.TC); const hasOriginal = title.TC_ != null; const originalPrice = hasOriginal ? EstMath.num(title.TC_) : null; const difference = hasOriginal ? appliedPrice - originalPrice : null; return { index, Code: code, Name: title.Name || "", Size: title.Size || "", Unite: title.Unite || "", appliedPrice, originalPrice, difference, NC: EstMath.num(title.NC), GC: EstMath.num(title.GC), JC: EstMath.num(title.JC), detailCount: group ? group.rows.length : 0, status: !hasOriginal ? "신규(당초없음)" : Math.abs(difference) > 1e-6 ? "당초차이" : "일치", canApply: false, // 당초 계약값은 비교용이며 현재 단가 덮어쓰기 적용을 지원하지 않음 }; }); } function changes(project) { const labels = { new: "신규", deleted: "삭제", changed: "변경", unchanged: "동일" }; const titles = project.tables?.MachTitleDat || []; return titles.map((title, index) => { const appliedPrice = EstMath.num(title.TC); const hasOriginal = title.TC_ != null; const originalPrice = hasOriginal ? EstMath.num(title.TC_) : null; const difference = hasOriginal ? appliedPrice - originalPrice : null; const statusKey = !hasOriginal ? "new" : Math.abs(difference) > 1e-6 ? "changed" : "unchanged"; return { index, Code: title.Code || "", Name: title.Name || "", Size: title.Size || "", Unite: title.Unite || "", originalTC: originalPrice, TC: appliedPrice, difference, status: labels[statusKey] || statusKey, }; }); } function applyRowPrice() { throw Error( "기계경비 호표는 MachMainDat 산출 결과이며 당초 계약값으로의 덮어쓰기 적용은 지원하지 않습니다.", ); } function applyAllPrices() { throw Error( "기계경비 호표는 MachMainDat 산출 결과이며 당초 계약값으로의 덮어쓰기 적용은 지원하지 않습니다.", ); } function render() { const { state, esc, number, byId } = EstApp, isChange = state.view === "machine-change", rows = isChange ? changes(state.project) : usage(state.project); page = Math.max(0, Math.min(page, Math.ceil(rows.length / 100) - 1)); const visible = rows.slice(page * 100, page * 100 + 100), value = (v) => (v == null ? "" : number(v)); if (isChange) { byId("work-content").innerHTML = `
| 구분 | 코드 | 품명 | 규격 | 단위 | 당초 금액 | 변경 금액 | 증감 | 작업 |
|---|---|---|---|---|---|---|---|---|
| ${esc(row.status)} | ${esc(row.Code)} | ${esc(row.Name)} | ${esc(row.Size)} | ${esc(row.Unite)} | ${value(row.originalTC)} | ${value(row.TC)} | ${value(row.difference)} |
기계경비 호표의 산출 단가와 당초 계약 단가를 비교합니다. (기계 호표 단가는 MachMainDat 산출 공식에 의해 결정되며 당초값 덮어쓰기는 지원하지 않습니다.)
| 코드 | 품명 | 규격 | 단위 | 적용 단가 | 당초 단가 | 차이 | 상태 | 노무비 | 재료비 | 경비 | 작업 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| ${esc(row.Code)} | ${esc(row.Name)} | ${esc(row.Size)} | ${esc(row.Unite)} | ${value(row.appliedPrice)} | ${value(row.originalPrice)} | ${value(row.difference)} | ${esc(row.status)} | ${value(row.NC)} | ${value(row.GC)} | ${value(row.JC)} |