- 원본 처리 근거대로 두 기초금액·두 대상액 식 중 작은 쪽 선택, 비교 줄 표시 - 샘플에 원본이 적어 둔 안전관리비 식을 그대로 재현 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
90 lines
3.9 KiB
Python
90 lines
3.9 KiB
Python
"""EST 테스트 앱 원가 보조 계산(원본 TfrmWongaDiget 기타경비 계산·산업안전보건관리비 비교)."""
|
||
|
||
import json
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
FILES = [
|
||
"native-math.js",
|
||
"native-formula.js",
|
||
"native-machine.js",
|
||
"native-rows.js",
|
||
"native-text.js",
|
||
"native-quantity.cjs",
|
||
"native-wonga.js",
|
||
"native-engine.js",
|
||
"native-row-match.js",
|
||
"native-escalation.js",
|
||
"native-progress.js",
|
||
"native-business.js",
|
||
"native-review.js",
|
||
"native-resources.js",
|
||
"native-schedule.js",
|
||
"native-model.js",
|
||
"native-verify.js",
|
||
"native-wonga-tools.js",
|
||
]
|
||
|
||
|
||
def run_js(code: str):
|
||
runner = f"""
|
||
const fs = require('fs'), vm = require('vm');
|
||
const ctx = vm.createContext({{ structuredClone, console }});
|
||
for (const f of {json.dumps(FILES)})
|
||
vm.runInContext(fs.readFileSync('tools/est-test/' + f, 'utf8'), ctx, {{ filename: f }});
|
||
ctx.source = JSON.parse(fs.readFileSync('tools/est-test/sample.json', 'utf8'));
|
||
process.stdout.write(JSON.stringify(vm.runInContext({json.dumps(code)}, ctx)));
|
||
"""
|
||
return json.loads(subprocess.check_output(["node", "-e", runner], cwd=ROOT).decode("utf-8"))
|
||
|
||
|
||
def test_anjun_reproduces_original_formula_pair_in_sample():
|
||
result = run_js(
|
||
"""(() => {
|
||
const calc = (p) => EstNative.calculate(EstModel.validate(p));
|
||
const p = calc(structuredClone(source));
|
||
const plain = (t) => String(t).replace(/\s+/g, '');
|
||
const row = p.tables.Wonga.find((r) => plain(r.Name).includes('산업안전') && Number(r.CalcIndex) !== 2);
|
||
const original = [row.VSusic, p.tables.Wonga.find((r) => plain(r.Name).includes('산업안전') && Number(r.CalcIndex) === 2).VSusic];
|
||
const before = p.tables.Wonga.length;
|
||
const out = EstWongaTools.anjun(p, { youl: 3.15, base: 5349000, addBase: false, compare: true });
|
||
const after = calc(p);
|
||
return { base: EstWongaTools.anjunBase(p.tables.Wonga), original, chosen: out.chosen, other: out.other,
|
||
rows: p.tables.Wonga.length === before, errors: after.calculation.errors.length };
|
||
})()"""
|
||
)
|
||
assert result["base"] == "(A + 4)"
|
||
assert result["chosen"] == "(A + 4) × 0.0315 × 1.2"
|
||
assert result["other"] == "((A + 4) + J/1.1) × 0.0315"
|
||
assert [x.replace(" ", "") for x in result["original"]] == [
|
||
result["chosen"].replace(" ", ""),
|
||
result["other"].replace(" ", ""),
|
||
]
|
||
assert result["rows"] is True and result["errors"] == 0
|
||
|
||
|
||
def test_gita_picks_smaller_base_and_validates():
|
||
result = run_js(
|
||
"""(() => {
|
||
const p = { options: {}, tables: { Wonga: [
|
||
{ Gubun: 'A', Name: '직 접 공 사 비', Cost: 1000 }, { Gubun: 'B', Name: '직접노무비', Cost: 300 },
|
||
{ Gubun: 'C', Name: '간접노무비', Cost: 50 }, { Gubun: 'D', Name: '기 타 경 비', Youl: '5%' } ] } };
|
||
const out = EstWongaTools.gita(p, { gcRatio: 0.4, baseRatio: 0.6, youl: 5.2, compare: true });
|
||
const row = p.tables.Wonga[3], cmp = p.tables.Wonga[4];
|
||
const errors = [];
|
||
for (const bad of [{ gcRatio: 2, baseRatio: 0.5, youl: 1 }, { gcRatio: 0.5, baseRatio: 0.5, youl: 11 }])
|
||
try { EstWongaTools.gita(p, bad); } catch (e) { errors.push(e.message.slice(0, 4)); }
|
||
let none = ''; try { EstWongaTools.anjun({ options: {}, tables: { Wonga: [] } }, { youl: 1 }); } catch (e) { none = e.message; }
|
||
return { values: out.values, vs: row.VSusic, youl: row.Youl, cmp: [cmp.VSusic, cmp.CalcIndex], errors, none,
|
||
stored: [p.options.GitaGCRatio, p.options.GitaBaseRatio] };
|
||
})()"""
|
||
)
|
||
assert result["values"] == [750, 600]
|
||
assert result["vs"] == "(A × 0.6) × 0.052"
|
||
assert result["youl"] == "5.2%"
|
||
assert result["cmp"] == ["((A × 0.4) + B + C) × 0.052", 2]
|
||
assert result["errors"] == ["1 이하", "기타경비"]
|
||
assert result["none"] == "산업안전보건관리비 비목이 없습니다."
|
||
assert result["stored"] == [0.4, 0.6]
|