"""M02 일위대가 맞춤 몫(PLAN 338-1 · 설계 2-2 · 2-7 · 776-3) — 단가산출 블록 단위 줄을 절(맨 윗 절 · 작은 절)마다 묶어 노임(직종 → 인) · 장비(「굴착기|0.6」 → 시간) 벡터. 형식 모름(단위 줄만 · `M02_Hopyo_UnitLine`) · 셈 밖 줄 뺌 · 금액 안 씀 · 장비 갈래 = `M02_Hopyo_Words.mtypes`. """ from __future__ import annotations import re from typing import Any from M02_MasterTemplete.M02_Hopyo_ReadEst import trade # 노임 이름 → 우리 인력(B09 도 씀) from M02_MasterTemplete.M02_Hopyo_Words import mtypes, nfkc __all__ = ["eq_key", "sections", "trade"] _SIZE = re.compile(r"(\d+(?:\.\d+)?)\s*(㎥|m3|톤|ton|t\b|kw|hp)", re.I) def eq_key(text: Any) -> str | None: """장비 글 → 「굴착기|0.6」(갈래 + 로 묶음 · 크기 없으면 「굴착기|」) · 장비 아니면 None.""" kinds = mtypes(text) if not kinds: return None m = _SIZE.search(nfkc(text).replace(",", "")) size = ( m.group(1).rstrip("0").rstrip(".") if m and "." in m.group(1) else m.group(1) if m else "" ) return f"{'+'.join(sorted(kinds))}|{size}" def _part(title: str, parent: str) -> dict[str, Any]: return {"제목": title, "절": parent, "노임": {}, "장비": {}} def sections(units: list[dict[str, Any]]) -> list[dict[str, Any]]: """블록 단위 줄(`M02_Hopyo_UnitLine`) → 몫마다 {제목 = 줄 절, 절 = 윗절, 노임, 장비} — 셈 밖 · 매개값 없는 줄 뺌 · 장비 = 시간 50 아래 · 노임 · 장비가 하나도 없는 몫은 뺌.""" out: dict[str, dict[str, Any]] = {} for one in units: q, kind = one.get("품"), one.get("묶음") if one.get("밖") or not q or kind not in ("L", "X"): continue title = str(one.get("절") or "") part = out.setdefault(title, _part(title, str(one.get("윗절") or title))) if kind == "L" and (who := one.get("직종") or trade(one.get("이름"))): part["노임"][who] = part["노임"].get(who, 0) + float(q) elif kind == "X" and q < 50: k = eq_key(f"{one.get('이름') or ''} {one.get('규격') or ''}") or f"?{one.get('코드')}" part["장비"][k] = part["장비"].get(k, 0) + float(q) return [p for p in out.values() if p["노임"] or p["장비"]]