diff --git a/B09_Estimation/B09_Estimation_UI_Tabs_Total.ts b/B09_Estimation/B09_Estimation_UI_Tabs_Total.ts index 1ea78b13f..e41a21e1b 100644 --- a/B09_Estimation/B09_Estimation_UI_Tabs_Total.ts +++ b/B09_Estimation/B09_Estimation_UI_Tabs_Total.ts @@ -271,7 +271,7 @@ export const buildTotal: TabBuild = (ctx): TabTable => { /** 원가계산서 줄 [키(cost · 총괄 줄), 구분, 비목, 세목] */ const COST_ROWS: Array<[string, string, string, string, string?]> = [ - ["direct_material", "순공사원가", "재료비", "직접재료비", "material"], + ["direct_material", "순공사원가", "재료비", "직접재료비", "direct"], ["indirect_material", "순공사원가", "재료비", "간접재료비"], ["scrap", "순공사원가", "재료비", "작업설 · 부산물 등(△)"], ["material", "순공사원가", "재료비", "소계", "direct"], diff --git a/resources/tester/test_261_2_b09_cost_link_targets.py b/resources/tester/test_261_2_b09_cost_link_targets.py new file mode 100644 index 000000000..7b6db0414 --- /dev/null +++ b/resources/tester/test_261_2_b09_cost_link_targets.py @@ -0,0 +1,54 @@ +# -*- 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"]