feat(b09): 설계내역서 손 줄 레벨 · 묶음 줄 금액 상위 합계 · 레벨 메뉴 (182-1)

- 손 줄 kind(group = 묶음 줄) · parent(묶음 손 줄 키) 저장 · 다듬기
- 셈 짝(Calc_Bill ts ↔ py) — 줄마다 level · 묶음 금액 = 자손 항목 합 + 빈 줄 n · 공종 합 · sums = 항목만
- 화면 — is-lvN 글자 크기(16 · 14 · 13px) · 첫 칸 들여쓰기 · 제목 · 묶음 줄 굵게
- 우클릭 — 아래에 하위 줄 추가 · 묶음 줄로 · 항목으로 · 들여쓰기 · 내어쓰기(손 묶음 깊이 2)
- 시험 test_182_b09_bill_level(레벨 · 합계 · 거울 · 저장 왕복 · 메뉴) · test_166_2 메뉴 판정 손봄

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KYZ2HWWdUwZWYnn3tQz7X
This commit is contained in:
2026-10-10 11:53:24 +09:00
co-authored by Claude Opus 5.5
parent 68e8c896e4
commit 8b64d794da
8 changed files with 560 additions and 37 deletions
+8 -3
View File
@@ -109,7 +109,8 @@ def _clean_ref(ref: Any) -> dict[str, Any] | None:
def clean_bill(raw: Any) -> dict[str, Any]:
"""설계내역서 손질(166-2) — 수량 덮어쓰기(수만) · 손 줄(`hand:` 키 · 아는 공종만)."""
"""설계내역서 손질(166-2) — 수량 덮어쓰기(수만) · 손 줄(`hand:` 키 · 아는 공종만) ·
182 레벨 = `kind`(group) · `parent`(`hand:` 키)."""
raw = raw if isinstance(raw, dict) else {}
qty = raw.get("qty") if isinstance(raw.get("qty"), dict) else {}
codes = {code for code, _name, _parent in SECTIONS}
@@ -119,14 +120,18 @@ def clean_bill(raw: Any) -> dict[str, Any]:
continue
if row.get("section") not in codes:
continue
group = row.get("kind") == "group" # 182 묶음 줄 = 이름만
parent = str(row.get("parent") or "")
rows.append(
{
"key": str(row["key"]),
"section": row["section"],
"after": _text(row.get("after")),
**({"kind": "group"} if group else {}),
**({"parent": parent} if parent.startswith("hand:") else {}),
**{k: _text(row.get(k)) for k in ("name", "spec", "unit")},
"qty": _num(row.get("qty")),
"ref": _clean_ref(row.get("ref")),
"qty": None if group else _num(row.get("qty")),
"ref": None if group else _clean_ref(row.get("ref")),
}
)
out: dict[str, Any] = {}