feat(M02): 구조물 조합 상단 표 「일위대가 합계」 읽기 전용 줄 — 반영합 · 없으면 기준합(기준) · 카드 저장 뒤 다시 읽기(86-3)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
This commit is contained in:
2026-10-08 12:11:47 +09:00
co-authored by Claude Sonnet 5.5
parent cd8a226323
commit 142194a1e5
12 changed files with 136 additions and 16 deletions
+29 -3
View File
@@ -226,13 +226,39 @@ def _codes() -> dict[str, str]:
return codes
def structure_numbers() -> dict[str, dict[str, str]]:
"""`{열 id: {도번, 면적번}}` — 집계표 줄 · 좌측 줄이 한 번에 받음(없는 쪽은 빈 글)."""
out: dict[str, dict[str, str]] = {}
def _total(sums: Any) -> float | None:
"""`계산값` 합 칸의 `계` — 수 아닌 값 · 없음 = None."""
total = sums.get("계") if isinstance(sums, dict) else None
if total is None or isinstance(total, bool):
return None
try:
return float(total)
except (TypeError, ValueError):
return None
def _labor_sum(doc: dict[str, Any]) -> dict[str, Any]:
"""일위대가 합계 칸(86-3) — 반영합 `계`(0 아님) · 없으면 기준합 `계` + `합계기준` 참 ·
담은 로직 0 · 계산값 없음 = 빈 칸 (목록 `labor` 합계와 같은 규칙)."""
if not doc.get("담은로직"):
return {}
calc = doc.get("계산값") or {}
if total := _total(calc.get("반영합")):
return {"일위대가합계": total, "합계기준": False}
base = _total(calc.get("기준합"))
return {} if base is None else {"일위대가합계": base, "합계기준": True}
def structure_numbers() -> dict[str, dict[str, Any]]:
"""`{열 id: {도번, 일위대가번, 면적번, (일위대가합계, 합계기준)}}` — 집계표 줄 · 좌측 줄이 한 번에
받음(번호 없는 쪽은 빈 글 · 합계는 일위대가 계산값이 있을 때만)."""
out: dict[str, dict[str, Any]] = {}
for kind, key, _, _ in PARTS:
for name, doc in _docs(kind):
row = out.setdefault(name, {k: "" for _, k, _, _ in PARTS})
row[key] = str(doc.get(key) or "")
if kind == "labor":
row.update(_labor_sum(doc))
return out