feat(794-1): M01 관리자 줄 식 시트 — 로직 상세 첫 보기 「시트」 · 식 칸 칠 때마다 검사 · 기존 [저장] 길
- 로직 상세 보기 첫 칸 「시트」(기본) — 이름 | 식 | 값 | 비목 · 근거 · 옵션(시험 값) · 변수 · 계산 · 자원 · 율 · 덧줄 · 단계 · 끝수 · 소계 · 합계 · 상태줄 지금 · 고치기 전 - 식 글 = 이름 꼴(M02 단가산출 시트와 같은 번역 · 새 서버 M01_MasterData_Sheet.py · POST /api/m01/logic/sheet · /logic/sheet/check · 저장 때와 같은 엔진 검사 · 쓰기 없음) - 식 고침 = 시스템 관리자만 · 되는 식만 줄 사본에 · 캐시 → 기존 [저장](개정 확인 · 서버 검사 422) · [원래로] - 식 칸 몸 = 공용 A00_Common/sheet_formula_cell.ts — M02 단가산출 시트도 같은 것을 씀(동작 그대로) - 자체 로직(GX) 편집기 식 날 입력칸 → 읽기만(시트 식 칸으로 갈음) - 시험: test_794_1_m01_sheet 새로 · test_790_1 식 칸 문구 자리를 공용 파일로 옮김(식 칸 몸이 공용으로 감) · test_717_2b · test_722 LogicLab.ts 줄 상한 627 → 637(시트 이음 10 줄 · 셈 · 고침은 시트 파일로 뺌 · 700 아래) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"""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}
|
||||
Reference in New Issue
Block a user