# -*- coding: utf-8 -*- """261-2 B09 공사원가계산서 줄 이동 대상 — 모든 줄의 대상 키가 총괄 줄 키에 있음(빈 대상 = 이동 없음 허용). 직접재료비 → 총괄 「가. 순공사비계」(direct) · 직접노무비 · 산출경비와 같은 자리. """ import json import re import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[2] B09 = ROOT / "B09_Estimation" IMPORTS = re.compile(r"^import[^;]*;\n", re.MULTILINE) SUMS = {"material": 194234417, "labor": 346800554, "expense": 169324165, "supply_net": 69474220} BODY = f""" const user = {{ estimate: {{}} }}; const ctx = {{ sheets: {{ total: computeTotal({json.dumps(SUMS)}, user.estimate) }}, payload: {{}}, user, setUser: () => {{}} }}; const T = buildTotal(ctx), C = buildCost(ctx); console.log(JSON.stringify({{ totalKeys: T.rows.map((r) => r.key), cost: C.rows.map((r, i) => [r.key, C.link(i)]), }})); """ def _run() -> dict: names = ("Calc_Base", "Calc_Total", "UI_Tabs", "UI_Tabs_Total") script = "".join( IMPORTS.sub("", (B09 / f"B09_Estimation_{n}.ts").read_text(encoding="utf-8")) for n in names ) result = subprocess.run( ["node", "--experimental-strip-types", "--no-warnings", "--input-type=module-typescript"], input=script + BODY, capture_output=True, text=True, encoding="utf-8", timeout=60, ) # fmt: skip assert result.returncode == 0, result.stderr return json.loads(result.stdout) def test_모든_원가_줄_이동_대상이_총괄_줄에_있음(): got = _run() keys = set(got["totalKeys"]) missing = [k for k, link in got["cost"] if link and link["key"] not in keys] assert not missing, missing assert len(got["cost"]) > 20 def test_직접재료비_이동_대상_direct(): links = {k: link for k, link in _run()["cost"]} assert links["direct_material"] == {"tab": "total", "key": "direct"} assert links["direct_labor"] == links["expense"] == links["direct_material"]