/* ============================================================================= * common_util_machine_coef.ts * 기계 손료계수 · 시간당 경비 미리보기(PLAN 821-2 · 요구서 796 1 장) — 기계 양식 즉시 셈. * * ⚠ 짝: `resources/master_data/scripts/master_machine_coef.py` — 같은 셈 · 같은 차례 * (거울 시험 `resources/tester/test_821_2_machine_coef.py`). 한쪽만 고치면 화면과 저장이 갈림. * 계수 = 건설품셈 공통 8-1-5(계수마다 정수 반올림 · 손료계수 = 합) · 미리보기 끝수 = 서버 * 기계경비식(줄 0.1 원 아래 버림 · 잡품 = 버린 주연료 × % · 비목 합 원 미만 버림) · 정본은 서버 식. * ========================================================================== */ export const MACHINE_INPUTS = [ "내용시간", "연간표준가동시간", "상각비율", "정비비율", "연간관리비율", ] as const; export const MACHINE_COEFS = ["상각비계수", "정비비계수", "관리비계수", "손료계수"] as const; export type MachineCoefs = Record<(typeof MACHINE_COEFS)[number], number>; const E = 1e-6; // 끊는 경계 부동소수 흔들림 막음 const num = (v: unknown): number => (typeof v === "number" && Number.isFinite(v) ? v : 0); const halfUp = (x: number): number => Math.floor(x + 0.5 + E); /** 줄 금액 = 0.1 원 아래 버림(B09 끝수 줄 자리). */ const tenth = (x: number): number => Math.floor(x * 10 + E) / 10; /** (내용시간 · 연간표준가동시간 · 상각비율 · 정비비율 · 연간관리비율) → 계수 넷 · 못 셈 = null. */ export function machineCoef( life: unknown, yearly: unknown, dep: unknown, rep: unknown, mgmt: unknown, ): MachineCoefs | null { const [t, h, a, m, k] = [life, yearly, dep, rep, mgmt].map(num); if (t <= 0 || h <= 0) return null; const n = t / h; const s = halfUp((a / t) * 1e7); const j = halfUp((m / t) * 1e7); const g = halfUp(((k * (1.1 * n + 0.9)) / (2 * n) / h) * 1e7); return { 상각비계수: s, 정비비계수: j, 관리비계수: g, 손료계수: s + j + g }; } /** 값 묶음에서 품셈 입력 다섯이 다 수일 때만 계수 넷. */ export function machineCoefOf(values: Record): MachineCoefs | null { if (!MACHINE_INPUTS.every((k) => typeof values[k] === "number")) return null; return machineCoef( ...(MACHINE_INPUTS.map((k) => values[k]) as [number, number, number, number, number]), ); } export interface MachineHourly { 손료: number; 주연료: number; 잡품: number; 전력: number; 조종원: number; 노무비: number; 재료비: number; 경비: number; 계: number; } /** 값 묶음 + 유가(원/ℓ) · 노임(원/일) · 전력(원/kWh) · 시간환산 → 시간당 줄 · 비목 · 계. */ export function machineHourly( values: Record, fuel: number, wage: number, power = 0, hour = 1 / 8, ): MachineHourly { const loss = Math.floor((num(values["가격"]) * 1000 * num(values["손료계수"])) / 1e7 + E); const oil = tenth(num(values["주연료"]) * num(fuel)); const misc = tenth((oil * num(values["잡재료율"])) / 100); const elec = tenth(num(values["전력"]) * num(power)); const crew = tenth(num(values["조종원"]) * hour * num(wage)); const labor = Math.floor(crew + E); const material = Math.floor(oil + misc + elec + E); return { 손료: loss, 주연료: oil, 잡품: misc, 전력: elec, 조종원: crew, 노무비: labor, 재료비: material, 경비: loss, 계: labor + material + loss, }; }