"""기계 보기 서버 몫(PLAN 840-2 · 요구 853 · 862) — M01 기계 상세 · 내 기계가 같이 씀 · 쓰기 없음. `sheet(줄, 본, 덮음, 개인)` → {키, 이름, 까닭, 문서, 값, 연결, 직종} - 식 고름 = `M02_Machine_Hourly.pick`(지금 줄 · 내 기계 = 셈 꼴 `M02_MyMachine.engine`) · 못 고름 = 키 없음 + 까닭 - 문서 = 그 식 수식 문서(그대로) · 값 = `본`(처음 줄 · 없으면 줄)의 셈 꼴 값 칸 — 셈 차례 = 덮음(`기계덮음` 꼴 · 836-1) 얹음 → 값 박음(`bind` — 남은 요소 `EQ:{S_기계}` 칸 → 숫자 · 저장 전 새 기계 · 내 기계도 같은 계산기로 셈) - 파이썬 · TS 짝 — `bind` ↔ `common_util/common_util_machine_sheet.ts` `bindDoc` · 거울 시험 test_840_2_machine_sheet.py - 연결 = 덮음 얹은 문서 셈이 쓴 요소 · 표 · 문서(`master_doc_record`) — 화면이 같은 계산기로 즉시 다시 셈 - 직종 = 노임 요소 코드 → 인력 원문번호(조종원 줄 → 기계 줄 `조종원직종`) """ from __future__ import annotations import copy import json from decimal import Decimal from typing import Any from M01_MasterData import M01_MasterData_Store as m01 from M02_MasterTemplete import M02_MyMachine as mym def _plain(v: Any) -> Any: if isinstance(v, Decimal): return int(v) if v == v.to_integral_value() else float(v) return v def bind(doc: dict, vals: dict) -> dict: """식 문서 → 기계 값 칸을 숫자로 박은 새 문서(그 칸이 없는 줄은 요소 그대로).""" out = copy.deepcopy(doc) for v in out.get("변수") or []: link = v.get("연결") or {} key = str(link.get("키") or "") col = link.get("칸") if ( link.get("갈래") == "요소" and key.startswith("EQ:") and "{S_기계}" in key and col in vals ): v["연결"] = {"갈래": "숫자", "값": vals[col]} return out def _shape(row: dict, mine: bool) -> dict: if mine: return mym.engine(row) return {**row, "값": m01._dec(row.get("값") or {})} def _jobs() -> dict[str, str]: rows = (m01.loaded()[0].get("인력.json") or {}).get("줄") or [] return {str(r["키"]): str(r.get("원문번호")) for r in rows if r.get("키")} def sheet(row: Any, base: Any = None, cover: Any = None, mine: bool = False) -> dict: import master_doc_calc as mc import master_doc_cover as mcv import master_doc_link as ml import master_doc_record as mr from M01_MasterData import M01_MasterData_Doc as m01doc from M02_MasterTemplete import M02_Machine_Hourly as mh if not isinstance(row, dict): raise m01.StoreError(400, "기계 줄이 묶음 아님") cur = _shape(row, mine) logic = mh.pick(cur) out: dict[str, Any] = {"직종": _jobs()} doc = m01doc.docs().get(str(logic["키"])) if logic else None if doc is None: why = mh.why(cur, logic) or ("식 문서 없음" if logic else "식 없음") return out | {"키": None, "까닭": why, "문서": None, "값": {}, "연결": {}} vals = _shape(base if isinstance(base, dict) else row, mine).get("값") or {} no = str(row.get("원문번호") or row.get("키") or "새 기계") given = {"기계": no} entry = cover if isinstance(cover, dict) and cover else None try: covered = mcv.cover_doc(doc, given, mcv.clean({no: m01._dec(entry)})) if entry else doc except ValueError as e: raise m01.StoreError(400, str(e)) from None shaped = bind(covered, vals) links = ml.Links(mym.whole(), m01doc.docs()) rec = mr.Rec(links) rec.prefetch(shaped) mc.calc(shaped, rec, given) got = {"키": logic["키"], "이름": logic.get("이름"), "까닭": mh.why(cur, logic), "문서": doc, "값": vals, "연결": rec.out()} # fmt: skip return json.loads(json.dumps(out | got, ensure_ascii=False, default=_plain))