"""M02 일위대가 입력 목록(39-3). 담은 단가산출 로직마다 입력 전부 · 로직마다 갈라 보이고 이름이 같아도 합치지 않음 · 입력 목록은 그 로직 줄의 `입력` 그대로(하위 로직으로 넘겨지는 입력은 맨 위 로직 입력으로만) · 자동값 = `master_auto.values`(보기용 · 저장 안 함). 일위대가 입력 모달(`GET /api/m02/logic-lib/inputs`)이 씀. M01 은 읽기만 · 권한은 부르는 쪽 몫. """ from __future__ import annotations from decimal import Decimal from typing import Any from M01_MasterData import M01_MasterData_Store as m01 from M01_MasterData import M01_MasterData_Store_Combo as combo_store _SPEC = ("이름", "설명", "단위", "고르기", "범위") _LAYERED = "골쌓기 기준" # 85-2 — 표 주문에 이 글이 있으면 켜쌓기율 대상 로직 def _num(value: Any) -> Any: """Decimal → JSON 수(M01 길과 같은 규칙) · 목록 · 묶음 안까지.""" if isinstance(value, Decimal): return int(value) if value == value.to_integral_value() else float(value) if isinstance(value, list): return [_num(v) for v in value] if isinstance(value, dict): return {k: _num(v) for k, v in value.items()} return value def _logics(codes: list[str]) -> tuple[list[dict], list[str]]: """([로직 줄 …], 빠진 로직 키) — 키 차례 그대로.""" whole = m01.loaded()[1] found, missing = [], [] for code in codes: try: found.append(whole.logic(code)) except combo_store.cm.mf.FormulaError: missing.append(code) return found, missing def layered() -> set[str]: """켜쌓기율(85-2) 대상 로직 키 — 표 `주` 에 「골쌓기 기준」 · 그 표 `용도.로직키`(자동 판정).""" out: set[str] = set() for data in m01.loaded()[0].values(): for row in data.get("표") or []: if any(_LAYERED in str(note) for note in row.get("주") or []): out.update((row.get("용도") or {}).get("로직키") or []) return out def _labels(whole: Any, spec: dict) -> dict[str, str]: """고르기 원문번호 → 보이는 글(85-1) — 기계 「이름 규격」 · 직종(입력 이름에 「직종」) 「이름」 · 모르는 번호는 뺌.""" table = "LB" if "직종" in str(spec.get("이름") or "") else "EQ" rows = whole.numbers.get(table, {}) out = {} for value in spec.get("고르기") or []: row = rows.get(str(value)) if isinstance(value, str) else None if row: out[value] = " ".join(str(row[k]) for k in ("이름", "규격") if row.get(k)) return out def _listed(logics: list[dict]) -> list[dict[str, Any]]: """로직 줄마다 `{로직, 이름, 결과단위, 출처, 켜쌓기, 입력: [{이름, 설명, 단위, 고르기?, 고르기이름?, 범위?, 자동값}]}`.""" whole = m01.loaded()[1] layers = layered() out = [] for logic in logics: auto = m01.mau.values(whole, logic) specs = [] for spec in logic.get("입력") or []: one = {k: spec[k] for k in _SPEC if k in spec} one.setdefault("설명", None) one.setdefault("단위", None) labels = _labels(whole, spec) if labels: one["고르기이름"] = labels specs.append({**one, "자동값": auto.get(spec["이름"])}) out.append( { "로직": logic.get("키"), "이름": logic.get("이름"), "결과단위": logic.get("결과단위"), "출처": logic.get("출처"), "켜쌓기": logic.get("키") in layers, "입력": specs, } ) return out def logic_inputs(codes: list[str]) -> dict[str, Any]: """일위대가 입력 모달 — 로직 키들의 입력 목록 `{로직: [...], 빠진로직}`(키 차례 · 겹침 한 번)""" found, missing = _logics(list(dict.fromkeys(c for c in codes if c))) return _num({"로직": _listed(found), "빠진로직": missing})