"""M01 로직 줄 식 시트(PLAN 794-1 · 요구 650~652 · 요구서_652 1 장 6) — 관리자 시트 식 칸 서버 몫. 이름 꼴 ↔ 엔진 식 · 상한 = M02 단가산출 식 칸과 한 벌(`M02_Sangeun_Formula` 불러 씀 · 고치지 않음) · 검사 = 저장 때와 같은 엔진 검사(`check_logic`) 중 그 자리 까닭만 · 셈 · 쓰기 없음(③ 서버 단독). 자리 = (갈래 중간 | 호표 | 덧줄, 차례 0 부터) — 저장은 화면 캐시 줄 → 기존 M01 [저장](`/save`). 짝 = `logic/M01_Logic_Sheet_Model.ts`(줄 고치기 — 서버 짝 함수 없음 · 자리 꼴만 같음) · 시험 `resources/tester/test_794_1_m01_sheet.py`. """ from __future__ import annotations import copy from typing import Any from M01_MasterData import M01_MasterData_Store as store FIELD = {"중간": "식", "호표": "수량", "덧줄": "식"} def _fx() -> Any: from M02_MasterTemplete import M02_Sangeun_Formula as fx # M02 가 M01 을 부름 — 늦게 return fx def _rows(row: dict, part: str) -> list: got = row.get(part) return got if isinstance(got, list) else [] def names(row: dict) -> dict[str, Any]: """줄마다 이름 꼴 식 글 {중간: [글], 호표: [글], 덧줄: [글], 이름표: [{글, 갈래}]}.""" fx, out = _fx(), {} for part, field in FIELD.items(): out[part] = [fx.to_name(str(x.get(field) or ""), row) for x in _rows(row, part)] try: out["이름표"] = fx.name_table(row, {}) except (KeyError, TypeError, ValueError): out["이름표"] = [] return out def _where(row: dict, part: str, at: int) -> str: """`check_logic` 까닭 머리(그 자리).""" key = f"{row.get('키')} {row.get('원문번호')}" name = _rows(row, part)[at].get("이름", "") return f"{key} {part} {name}" + (" 수량" if part == "호표" else "") def check(row: dict, part: str, at: int, text: str) -> dict[str, Any]: """식 글 하나 → {되나, 까닭, 식(엔진), 글(이름 꼴)} — 그 자리에 넣은 사본을 엔진 검사.""" fx = _fx() text = str(text or "").strip() out: dict[str, Any] = {"되나": False, "까닭": [], "식": None, "글": None} if part not in FIELD or not 0 <= at < len(_rows(row, part)): return out | {"까닭": [f"없는 자리 「{part} {at}」"]} if not text: return out | {"까닭": ["식이 빔"]} if bad := fx.limits(text): return out | {"까닭": bad} got, why = fx.to_engine(text, row) if why: return out | {"까닭": why} out |= {"식": got, "글": fx.to_name(got, row)} trial = copy.deepcopy(row) trial[part][at][FIELD[part]] = got head = _where(trial, part, at) found = store.cm.mf.check_logic(store.loaded()[1], trial)[0] mine = [w[len(head) :].lstrip(" ·") for w in found if w.startswith(head)] return out | {"되나": not mine, "까닭": mine}