Files
Aislo/resources/tester/test_est_name_reg.py
T
eomsangdonandClaude Opus 5.5 f7b68be72a feat(est-test): 품명정리와 자재·견적단가 등록
- 원본 처리 근거대로 커서 자리 품명 나누기, 삭제할 칸, 빈 단위만 채움
- 내역·일위대가 행을 새 자재(M)·견적(W) 단가로 등록하고 연결, 중복·호표 거부

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 19:35:03 +09:00

103 lines
4.5 KiB
Python

"""EST 테스트 앱 품명정리와 자재·견적단가 등록(원본 TfrmNameDevide·popMainStuffcReg·popMainEstimateReg)."""
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-name-reg.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_divide_splits_at_position_and_syncs_title():
result = run_js(
"""(() => {
const p = { tables: {
HeadMainDat: [{ Index: 1, Code: 'U1', Name: '거푸집 설치 합판', Size: '3회', Unite: '' }, { Code: 'L1', LinkIndex: 6 },
{ Index: 2, Code: 'U2', Name: '거푸집 해체 강재', Size: '', Unite: '㎡' }],
HeadTitleDat: [{ Code: 'U1', Name: '거푸집 설치 합판' }, { Code: 'U2', Name: '거푸집 해체 강재' }] } };
const n = EstNameReg.divide(p, [0, 1, 2], 4, 0, '㎡');
const c = { tables: { HeadMainDat: [{ Index: 1, Code: 'X', Name: 'AB-CD', Size: '' }] } };
EstNameReg.divide(c, [0], 2, 1, '');
let bad = ''; try { EstNameReg.divide(p, [1], 4, 0, ''); } catch (e) { bad = e.message.slice(0, 6); }
const r = p.tables.HeadMainDat;
return { n, a: [r[0].Name, r[0].Size, r[0].Unite], b: [r[2].Name, r[2].Size, r[2].Unite],
title: p.tables.HeadTitleDat[0].Size, bad, cut: c.tables.HeadMainDat[0].Size };
})()"""
)
assert result["n"] == 2
assert result["a"] == ["거푸집 ", "설치 합판3회", "㎡"]
assert result["b"] == ["거푸집 ", "해체 강재", "㎡"]
assert result["title"] == "설치 합판3회"
assert result["bad"] == "품명을 정리"
assert result["cut"] == "CD"
def test_register_stuff_and_estimate_link_row_and_keep_price():
result = run_js(
r"""(() => {
const calc = (x) => EstNative.calculate(EstModel.validate(x));
const p = calc(structuredClone(source));
const i = p.tables.EstMainDat.findIndex((r) => Number(r.GU) > 0 && !Number(r.Level) && Number(r.LinkIndex) === 5);
p.tables.EstMainDat[i].Name = '시험 자재 등록품';
const before = p.tables.EstMainDat[i].TC;
const code = EstNameReg.register(p, 'EstMainDat', i, 'stuff');
const rec = p.tables.StuffcDat.find((r) => r.Code === code);
const j = p.tables.EstMainDat.findIndex((r, k) => k !== i && Number(r.JU) + Number(r.NU) > 0 && !Number(r.Level) && r.Name);
p.tables.EstMainDat[j].Name = '시험 견적 등록품';
const w = EstNameReg.register(p, 'EstMainDat', j, 'estimate');
const est = p.tables.EstiMateDat.find((r) => r.Code === w);
const after = calc(p);
const errors = [];
for (const fn of [() => EstNameReg.register(p, 'EstMainDat', i, 'stuff'),
() => EstNameReg.register(p, 'HeadMainDat', p.tables.HeadMainDat.findIndex((r) => Number(r.Index) > 0), 'stuff')])
try { fn(); } catch (e) { errors.push(e.message.slice(0, 6)); }
return { code: /^M\d{10}$/.test(code), price: rec.Cost1 === Number(p.tables.EstMainDat[i].GU) && rec.TC === rec.Cost1,
link: [p.tables.EstMainDat[i].LinkIndex, p.tables.EstMainDat[i].Code === code],
same: after.tables.EstMainDat[i].TC === before, w: /^W\d{10}$/.test(w),
est: est.TC === est.NC + est.GC + est.JC && est.ONC === est.NC, estLink: p.tables.EstMainDat[j].LinkIndex,
errors, calcErrors: after.calculation.errors.length };
})()"""
)
assert result == {
"code": True,
"price": True,
"link": [5, True],
"same": True,
"w": True,
"est": True,
"estLink": 101,
"errors": ["같은 명칭의", "호표는 자재"],
"calcErrors": 0,
}