Files
Aislo/resources/tester/test_185_1_b09_total_level.py
T
eomsangdonandClaude Sonnet 5.5 f468a3a3fa feat(b09): 이동해 온 줄 빨강 모든 탭 · 비고 빈 줄 지움 · 총공사비 아래 고정 줄 (257-2)
- 설계내역서 밖 탭도 이동해 온 줄 = 같은 빨강 상자(줄 누름 · Esc · 방향키로 풂)
- 설계내역서 비고 「빈 줄 N」 지움(Py · TS 짝 · 「(제외금액)」 둠)
- 총괄설계내역서 · 공사원가계산서 총공사비 = 템플릿 아래 고정 줄(줄 이동 누름 빠짐)
- 시험 test_257_2 · 기대값 고침(145_3 · 145_4 · 182 · 185_1 · 242_1)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
2026-10-11 14:05:02 +09:00

87 lines
3.9 KiB
Python

# -*- 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"] # 원가계산서 = 총괄 거울