"""M02 일위대가 불러오기 → 단가산출(PLAN 718-1 · 요구서 내역12 4장 22) — 산근(단산) 블록 = 바탕 없는 단가산출. 블록마다 SK 하나 — 그 블록을 부르는 첫 엑셀 줄(「단산N참조」)의 1 단위 단가 (노무비 · 재료비 · 경비)를 고정 더한줄 하나로(`M02_Hopyo_Fixed` 꼴 · 엑셀 숫자 그대로 · 서버가 파일에서 읽음) · 이름 = 블록 이름(없으면 줄 품명) · 단위 = 줄 단위(없으면 블록 · 「식」) · 구분 「실무자료」 · 상세구분 = 파일 · 본뜬 = {층 「실무자료」, 키 「HP-###### 단산N」, 파일, 원본, 확인} · 같은 본뜬이 이 층에 있으면 그대로(겹침 없음) · 만드는 층 = 부르는 층(마법사에서 고른 층). """ from __future__ import annotations import json from pathlib import Path from typing import Any from common_util.common_util_time import utc_now_text from M02_MasterTemplete import M02_Hopyo_Fixed as hfix from M02_MasterTemplete import M02_Hopyo_Store as hopyo_store from M02_MasterTemplete import M02_Labor_Fixed as fixed from M02_MasterTemplete import M02_Labor_Ref as refs ORIGIN = "실무자료" KIND = "sangeun" def mark(key: str, no: int) -> str: return f"{key} 단산{no}" def made(folder: str | Path, key: str | None = None) -> dict[str, str]: """이 층 실무자료 단가산출 `{본뜬 키: SK 키}`(`key` = 그 HP 것만).""" out = {} for path in sorted((Path(folder) / KIND).glob("SK-*.json")): try: got = json.loads(path.read_bytes()).get("본뜬") except (OSError, ValueError, AttributeError): continue if isinstance(got, dict) and got.get("층") == ORIGIN: if key is None or str(got.get("키") or "").startswith(f"{key} "): out[str(got.get("키"))] = path.stem return out def _doc(line: dict, block: dict, no: int, hp: dict, stamp: str, who: Any) -> dict[str, Any]: name = str(block.get("이름") or line.get("이름") or "").strip() or f"단산{no}" unit = str(line.get("단위") or block.get("단위") or "").strip() or "식" spec = str(line.get("규격") or "").strip() price = {k: hfix._plain(v) for k, v in hfix._parts(line.get("단가")).items()} fx = { "이름": name, "규격": spec, "단위": unit, "단가": price, "이음": dict.fromkeys(fixed.LINKS), "출처": {"파일": hp.get("파일"), "호표": line.get("_호표"), "줄": int(line.get("차례", 0))}, } return { "종류": "단가산출", "이름": name, "단위": unit, "구분": ORIGIN, "상세구분": str(hp.get("파일") or ""), "본뜬": { "층": ORIGIN, "키": mark(hp["키"], no), "파일": hp.get("파일"), "원본": list(refs.here()), "확인": {"누가": who, "때": stamp}, }, "바탕": None, "입력값": {}, "열린입력": [], "고름": {}, "자재표시": {}, "덮개": {}, "더한줄": [{"고정": fx, "이름": name, "단위": unit, "수량": 1}], "뺀줄": [], } def build(folder: Path, key: str, who: Any = None) -> dict[str, Any]: """[단가산출 만들기] — 산근 블록마다 바탕 없는 단가산출 → `{블록, 만듦 [{번, 이름, 키}], 그대로}`.""" hp = hopyo_store.read(folder, key) blocks = {int(b["번"]): b for b in hp.get("단산") or [] if b.get("번") is not None} calls: dict[int, dict] = {} for h in hp.get("호표") or []: for line in h.get("줄") or []: ref = line.get("참조") or {} no = int(ref.get("번") or 0) if ref.get("종류") == "단산" else 0 if no in blocks and no not in calls: calls[no] = {**line, "_호표": h.get("번")} have, stamp = made(folder, key), utc_now_text() out: dict[str, Any] = {"블록": len(calls), "만듦": [], "그대로": 0} for no in sorted(calls): if mark(key, no) in have: out["그대로"] += 1 continue doc = _doc(calls[no], blocks[no], no, hp, stamp, who) got = refs.create(KIND, doc) out["만듦"].append({"번": no, "이름": doc["이름"], "키": got["이름"]}) return out