"""EST 테스트 앱 기성 원가계산서 편집(원본 TfrmWongaAccomH/V 팝업) — 회차별 원가 서식 사본.""" 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", "native-progress-wonga.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_progress_wonga_edits_apply_to_round_copy_only(): result = run_js( r"""(() => { const p = EstNative.calculate(EstModel.validate(structuredClone(source))); const inputs = {}; p.tables.EstMainDat.forEach((row, i) => { if (row.Code && !Number(row.Level)) inputs[EstBusiness.rowKey(row, i)] = { Gum: 50, GumMode: 'ratio' }; }); p.progress = [{ id: 'one', name: '1회', inputs }]; const round = p.progress[0], ops = EstProgressWonga.ops; const calc = () => EstProgress.calculate(p, 'one'); const plain = (t) => String(t).replace(/\s+/g, ''); const base = calc(); const anjun = base.costs.findIndex((r) => plain(r.Name).includes('산업안전') && Number(r.CalcIndex) !== 2); const total = base.costs.findIndex((r) => Number(r.LinkIndex) === 55); const out = { errors: base.errors, baseTotal: base.total, length: base.costs.length }; ops.insert(p, round, 1); const ins = calc(); out.inserted = [ins.costs.length, ins.costs[1].Name, ins.costs[1].ContractCost, ins.costs[2].ContractCost === base.costs[1].ContractCost, p.tables.Wonga.length]; ops.undo(p, round); out.undone = ['wonga' in round, 'wongaUndo' in round]; ops.position(p, round, anjun, 2, 3); const cut = calc(); out.anjun = [base.costs[anjun].GumCost, cut.costs[anjun].GumCost, cut.costs[anjun].ContractCost]; ops.total(p, round, 4); const fixed = calc(); out.total = [cut.total, fixed.total, fixed.errors]; ops.clear(p, round, 0); const r0 = round.wonga[0]; out.cleared = [r0.VSusic, r0.Cost, r0.Youl, r0.Diget, r0.Name !== '']; ops.init(p, round); out.init = ['wonga' in round, 'wongaTotalDigits' in round, calc().total === base.total]; ops.undo(p, round); out.reinit = Array.isArray(round.wonga); ops.init(p, round); round.locked = true; try { ops.append(p, round); } catch (e) { out.locked = e.message; } return out; })()""" ) assert result["errors"] == [] assert result["baseTotal"] > 0 n = result["length"] assert result["inserted"] == [n + 1, "", 0, True, n] assert result["undone"] == [False, False] before, after, contract = result["anjun"] assert after == before // 1000 * 1000 and after != before and contract > 0 cut_total, fixed_total, errors = result["total"] assert fixed_total == cut_total // 10000 * 10000 and errors == [] assert result["cleared"] == ["", 0, "", 0, True] assert result["init"] == [False, False, True] assert result["reinit"] is True assert result["locked"] == "확정한 회차는 고칠 수 없습니다."