"""M02 기계(M01 EQ) 한 시간 값 — [항목 추가] 창에서 기계를 고르면 고정 줄 단가(PLAN 736-3). 기계 줄 = 일위대가 · 단가산출 더한줄의 고정 줄(이음 기계 EQ · 수량 1) — 단가 = 이 값(노 · 재 · 경). 셈 = M01 「건설기계」 장 기계경비 로직 가운데 그 기종을 받는 짝 차례 첫째 (`로직(GC, 기계='원문번호')` · 옵션은 기본값). 짝 차례 · 셈은 `DataFlow/M02_DF_Values._machine_hourly` 와 같은 규칙(그 폴더는 시험 길이라 따로 둠). 마스터 파일은 읽기만 · 로그인 사용자 모두. """ from __future__ import annotations from typing import Any from M01_MasterData import M01_MasterData_Store as store cm = store.cm _PLAIN = {"기계", "지역", "보정작업", "조종원직종"} # 이 밖의 입력 = 부착 장비 전용 def _family() -> list[dict]: """기계 시간당 경비 로직 — 「건설기계」 장 파일 안 · 입력 「기계」 고르기가 있는 돈 로직.""" return [ row for name, data in store.loaded()[0].items() if data.get("그룹") == "로직" and "건설기계" in name for row in data.get("줄") or [] if str(row.get("결과단위") or "").startswith("원") and any(i.get("이름") == "기계" and i.get("고르기") for i in row.get("입력") or []) ] def _codes(row: dict) -> list: return next(i["고르기"] for i in row["입력"] if i.get("이름") == "기계") def _rank(row: dict) -> tuple: """부착 전용 · 손료만 · 보정 · 기종 수 · 키 — 작을수록 먼저.""" names = [i.get("이름") for i in row.get("입력") or []] attach = any(n not in _PLAIN for n in names) loss = "지역" not in names return (attach, loss, loss and "보정작업" in names, len(_codes(row)), str(row.get("키"))) def hourly(key: str) -> dict[str, Any]: """`{ok, 이름, 규격, 노무비, 재료비, 경비, 계}` · 못 셈 = `{ok: False, reason}`.""" if not key.startswith("EQ"): return {"ok": False, "reason": f"「{key}」 는 기계 아님"} try: row = store.loaded()[1].get(key) except cm.mf.FormulaError as e: return {"ok": False, "reason": str(e)} code = str(row.get("원문번호") or "") fit = [r for r in _family() if code in [str(c) for c in _codes(r)]] if not fit: return {"ok": False, "reason": f"「{row.get('이름')}」 은 시간당 경비를 셀 자료가 없음"} logic = min(fit, key=_rank) args = "".join( f", {i['이름']}='{(i.get('고르기') or [''])[0]}'" for i in logic.get("입력") or [] if i.get("이름") != "기계" ) call = f"로직({logic['키']}, 기계='{code}'{args})" line = {"종류": "로직", "요소": call, "이름": "기계", "단위": "시간", "수량": "1"} holder = { "키": "", "원문번호": "", "이름": "기계 시간", "결과단위": "원/식", "출처": "자체", "입력": [], "중간": [], "호표": [line], "덧줄": [], "끝수": None, } # fmt: skip got = store.calc("", {}, holder, None) if not got.get("ok") or "sums" not in got: return {"ok": False, "reason": got.get("reason") or "셈 못 함"} sums = {k: float(got["sums"][k]) for k in (*cm.mf.COST_ITEMS, "계")} return {"ok": True, "이름": row.get("이름"), "규격": row.get("규격"), **sums}