"""준비공 — 규준틀 재료 줄 (`B08_Quantity_Engine_Preparation` 에서 갈라냄 · 2026-09-14 700줄 제한). 내용·규칙은 그대로 옮겼다 — 개소 × 개소당 수량을 자재 축으로 보내고, 값은 제안값이며 산출 조건이 이긴다. """ from __future__ import annotations from typing import Any #: 규준틀 재료 — **세는 것은 확정이고 수량만 몰랐던 자리**(2026-09-09). #: 품셈 11-2·11-3 [주]④ 「재료량은 **설계수량에 따른다**」 ⇒ 품셈이 값을 안 주는 것이지 #: 「안 센다」가 아니다. 그래서 **제안값을 보이고 사용자가 고치는** 모양으로 둔다 #: (확정 ⑨·⑩ 과 같은 틀 — 「가는 기본값이고 나 선택처럼 동작할 수 있어야 함」). #: ⚠ **제안값은 실무 관측값이지 법정 기준이 아니다** — 울진 소광 원단위 라이브러리 §8 #: 「규준틀 수평 | 개소 | 각재 50×50 0.0044㎥ · 판재 T12 0.0029㎥ · 못 0.03㎏」. #: ⚠ **비탈 규준틀 값은 그 시트에 없다** — 수평 값을 준용하고 그 사실을 사유에 적는다. #: ⚠ **손율은 원문에 있다** — 품셈 11-2 [주]③ 비탈 **50%** · 11-3 [주]③ 수평 **80%**. FRAME_MATERIAL_SUGGESTED = { "각재 50×50": (0.0044, "㎥"), "판재 T12": (0.0029, "㎥"), "못": (0.03, "㎏"), } FRAME_MATERIAL_SOURCE = ( "⚠ 실무 관측값(울진 소광 원단위 라이브러리 §8 규준틀 수평) — **법정 기준 아님**." " 품셈 11-2·11-3 [주]④ 는 「재료량은 설계수량에 따른다」로만 둠. 산출 조건에서 고칠 수 있음" ) FRAME_LOSS_RATE = {"비탈 규준틀": 50, "수평 규준틀": 80} #: 자재 줄의 **이름 · 규격** — 이름 칸에 규격을 섞으면 할증률표(「각재」·「판재」)와 안 맞음 #: (2026-09-14 · 돌 줄 8210c2b7 과 같은 병). 산출 조건 키·관급구분 키(이름+규격)는 글자 그대로. FRAME_MATERIAL_NAME_SPEC = {"각재 50×50": ("각재", "50×50"), "판재 T12": ("판재", "T12")} def frame_material_rows( frame_rows: list[dict[str, Any]], overrides: dict[str, Any] | None = None ) -> list[dict[str, Any]]: """규준틀 재료 — 개소 × 개소당 수량. **자재 축으로 보낸다.** ⚠ 개소가 안 서면 재료도 안 선다(밑수가 그 줄이다). ⚠ 값은 **제안값**이고 산출 조건에서 덮어쓸 수 있다 — 그 사실이 사유에 적힌다. """ given = overrides or {} rows: list[dict[str, Any]] = [] for frame in frame_rows: count = frame.get("amount") if not count: continue loss = FRAME_LOSS_RATE.get(str(frame.get("item")), None) for name, (default, unit) in FRAME_MATERIAL_SUGGESTED.items(): raw = given.get(name) try: per_ea = ( float(raw) if raw is not None and str(raw).strip() != "" else float(default) ) except (TypeError, ValueError): per_ea = float(default) picked = "산출 조건에서 고른 값" if raw not in (None, "") else "제안값(기본)" material, spec = FRAME_MATERIAL_NAME_SPEC.get(name, (name, "")) rows.append( { "name": material, "spec": spec, "unit": unit, "amount": float(count) * per_ea, "destination": "material", "source": str(frame.get("item") or "규준틀"), "basis": ( f"{frame.get('item')} {float(count):g}개소 × {per_ea:g}{unit}/개소" f" ({picked}) · {FRAME_MATERIAL_SOURCE}" # ⚠ 준용이라는 사실이 상수 주석에만 있고 **화면 근거에는 없던** # 자리다 — 값이 서면 어디서 온 값인지 안 보인다(2026-09-09 감사). + ( " · ⚠ 비탈 규준틀 재료량은 그 시트에 없어 **수평 값을 준용**함" if str(frame.get("item")) == "비탈 규준틀" else "" ) + (f" · 손율 {loss}%(품셈 [주]③)" if loss else "") ), } ) return rows