# -*- coding: utf-8 -*- """185-1 B09 총괄설계내역서 · 공사원가계산서 줄 레벨 — 줄 `level` · 1단 굵게 · 공용 표 level 옵션(201-1). 레벨 = 화면이 정함(줄 짜임이 `B09_Estimation_UI_Tabs_Total.ts` 에 있음 · 셈 짝은 값만 냄 → 거울 없음). 총괄 = 가.~바. 소계 1(굵게) · 그 밖 2 · 원가계산서 = 구분만 1 · 비목 소계 2 · 세목 3. 들여쓰기 = 공용 표 level { key: 명칭 칸 · of = 줄 level }(201-1 · 옛 is-lvN · is-indent · is-flat 갈음). """ 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 pack = (t) => t.rows.map((r, i) => [r.key, r.level, t.rowClass(i), t.level.key, t.level.of(i), t.cellClass ?? null]); const T = buildTotal(ctx), C = buildCost(ctx); console.log(JSON.stringify({{ total: pack(T), cost: pack(C), fixed: {{ total: T.total, cost: C.total }} }})); """ 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_총괄_레벨(): rows = {k: (lv, cls) for k, lv, cls, *_ in _run()["total"]} top = ["direct", "net_cost", "da", "supply_price", "contract"] assert all(rows[k] == (1, "is-title") for k in top) assert "grand" not in rows # 257-2 총공사비 = 표 아래 고정 줄(total) for k in ["in_price", "in_env", "indirect_labor", "machine", "retirement", "overhead", "vat", "supply"]: # fmt: skip assert rows[k] == (2, None), k assert {lv for lv, _ in rows.values()} == {1, 2} def test_원가계산서_레벨(): rows = {k: (lv, cls) for k, lv, cls, *_ in _run()["cost"]} for k in ["overhead", "profit", "supply_price", "vat", "contract", "supply"]: assert rows[k] == (1, "is-title"), k assert "grand" not in rows # 257-2 총공사비 = 표 아래 고정 줄(total) for k in ["material", "labor", "expense_sum"]: assert rows[k] == (2, None), k for k in ["direct_material", "scrap", "direct_labor", "indirect_labor", "expense", "safety"]: assert rows[k] == (3, None), k def test_명칭_칸만_들여씀_공용_level(): out = _run() for tab in ("total", "cost"): for _k, lv, _cls, key, of, cell in out[tab]: assert (key, of, cell) == ("name", lv, None) # 칸 class(is-indent · is-flat) 없음 def test_CSS_옛_레벨_규칙_없음_공용_표로(): css = (B09 / "B09_Estimation_UI_Page.css").read_text(encoding="utf-8") assert "is-indent" not in css and "is-flat" not in css and "is-lv" not in css common = (ROOT / "ui_template" / "ui_template_data_table.css").read_text(encoding="utf-8") assert re.search( r"td\.ui-data-table__lv \{\s*padding-left: calc\(var\(--spacing-8\) \+ var\(--dt-lv, 0\) \* var\(--dt-indent\)\);", common, ) def test_총공사비_아래_고정_줄_총괄_원가계산서(): fixed = _run()["fixed"] assert fixed["total"]["key"] == "grand" and fixed["total"]["name"] == "총공사비" assert fixed["cost"]["key"] == "grand" and fixed["cost"]["group"] == "총공사비" assert fixed["cost"]["amount"] == fixed["total"]["amount"] # 원가계산서 = 총괄 거울