feat(M01): 흐름 로직 입력 약속 하나 — 저장 때 「입력」 은 흐름의 설계 때 정할 것으로 다시 씀 · 지우는 것은 계산 칸만 · 시험판 길 지움
- 흐름으로 저장 = 계산 칸(중간 · 호표 · 결과 · 덧줄)만 지우고 「입력」(이름 · 설명 · 단위 · 고르기 · 범위)은 흐름에서 같은 꼴로 · 조합 · 구조물 · 미리 보기 · 다시 적용은 「입력」 을 그대로 읽음(따로 갈래 없음) - 엔진 갈래: 안 준 입력 = 멈춤 · 빈 값으로 준 입력 · 단가 없는 품목 · 표에 없는 조건 = 그 값만 비움(알림) · 결과 꼴 = 돈 출력 줄 · 값들 · 알림 - 프로젝트에서 고른 자재 = 흐름 재료 자리 이름으로(고름 · 다시 적용 때 살림) - 시험판 길 지움: /list · /get · /save · /delete · /user-elements(서버) · cfList · cfGet · cfSave · cfDelete · cfUserElement*(Api) · 빈 _data 폴더 - 시험: 조합에 담은 로직을 흐름으로 바꿔도 입력 목록 · 로직별 결과 · 비목 합 · 단가 묶음 셈이 같음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
This commit is contained in:
@@ -185,7 +185,11 @@ def run(flow: dict, key: str, inputs: dict, strict: bool = False) -> dict:
|
||||
given = {k: _value(v, words) for k, v in (inputs or {}).items()}
|
||||
flow = {**flow, "key": key}
|
||||
values = dc._design_values(flow, given)
|
||||
blank = [d for d in dc.design_inputs(flow) if strict and given.get(d["port"]) is None]
|
||||
designs = dc.design_inputs(flow) if strict else []
|
||||
lack = [d["port"] for d in designs if d["port"] not in given]
|
||||
if lack: # 안 준 입력 — 엔진 `_inputs` 와 같이 멈춤(빈 값으로 준 입력은 아래 「빈 입력」)
|
||||
raise store.cm.mf.FormulaError(f"「{key}」 입력 「{lack[0]}」 없음")
|
||||
blank = [d for d in designs if given.get(d["port"]) is None]
|
||||
for d in blank:
|
||||
values.setdefault(d["box"], {})[d["port"]] = None
|
||||
got = dc.run(flow, values, load, flow.get("userElements") or [], [key])
|
||||
@@ -200,14 +204,22 @@ def _engine(master, ref: str, row: dict, given: dict) -> dict:
|
||||
|
||||
단가 · 값 · 표 = 부른 쪽이 넘긴 master(프로젝트 사본이면 그 단가 · `M02_DF_Values.SOURCE`).
|
||||
"""
|
||||
picks = (
|
||||
store.cm.mf.mp.CHOSEN.get() or {}
|
||||
) # 고른 자재 — 흐름은 재료 자리 이름으로(호표 차례 아님)
|
||||
slots = {d["port"] for d in dc.design_inputs(row[FLOW]) if d.get("kind") == "재료 자리"}
|
||||
given = {**given, **{k: v for k, v in picks.items() if k in slots}}
|
||||
token = dv.SOURCE.set(master)
|
||||
try:
|
||||
got = run(row[FLOW], ref, given, strict=True)
|
||||
finally:
|
||||
dv.SOURCE.reset(token)
|
||||
if got["errors"]:
|
||||
raise store.cm.mf.FormulaError(f"「{ref}」 흐름 셈 — {' · '.join(got['errors'])}")
|
||||
cost, notes = got["cost"], got.get("notes") or []
|
||||
# 빈 값(빈 입력 · 단가 없는 품목 · 표에 없는 조건 → #N/A)을 쓴 칸은 엔진처럼 그 값만 비움 — 알림
|
||||
empty = [e for e in got["errors"] if "#N/A" in e or "단가 없는 품목" in e]
|
||||
stop = [e for e in got["errors"] if e not in empty]
|
||||
if stop:
|
||||
raise store.cm.mf.FormulaError(f"「{ref}」 흐름 셈 — {' · '.join(stop)}")
|
||||
cost, notes = got["cost"], [*(got.get("notes") or []), *empty]
|
||||
outs = [b for b in row[FLOW].get("boxes") or [] if b.get("kind") == "output"]
|
||||
extra = {"중간": {}, "값들": cost["값들"], **({"알림": notes} if notes else {})}
|
||||
if outs and all((b.get("output") or {}).get("cost") in (None, "값") for b in outs):
|
||||
@@ -216,6 +228,7 @@ def _engine(master, ref: str, row: dict, given: dict) -> dict:
|
||||
lines = [] # 옛 「줄」 꼴 — 돈 출력 상자마다 한 줄(수량 1 · 단가 = 금액)
|
||||
for b in outs:
|
||||
kind, value = (b.get("output") or {}).get("cost"), got["outputs"].get(b["id"])
|
||||
value = None if value == dc.NA_VALUE else value
|
||||
if kind in dc.COSTS:
|
||||
unit = (b.get("output") or {}).get("unit") or ""
|
||||
lines.append({"이름": b.get("name") or "", "단위": unit,
|
||||
@@ -346,10 +359,20 @@ def _redo(row: dict, key: str) -> list[str]:
|
||||
|
||||
|
||||
def _bare(row: dict) -> dict:
|
||||
"""흐름 로직 줄 — 옛 식 칸(입력 · 중간 · 호표 · 결과 · 덧줄)은 지움(흐름이 정본)
|
||||
"""흐름 로직 줄 — 계산 칸(중간 · 호표 · 결과 · 덧줄)은 지움(흐름이 정본) · 「입력」 은 흐름의
|
||||
「설계 때 정할 것」 으로 같은 꼴로 다시 씀(로직 입력 약속 하나 · 설명은 이름이 같으면 살림)
|
||||
· 끝수 · 시험입력 · 메타 칸은 둠 · 출처 없으면 「자체」."""
|
||||
kept = {k: v for k, v in row.items() if k not in store.cm.mf.OLD_FIELDS}
|
||||
return {"끝수": None, **kept, "출처": row.get("출처") or "자체"}
|
||||
kept = {k: v for k, v in row.items() if k not in store.cm.mf.CALC_FIELDS}
|
||||
said = {s.get("이름"): s.get("설명") for s in row.get("입력") or [] if s.get("설명")}
|
||||
inputs = []
|
||||
for spec in store.cm.mf.inputs_of(row):
|
||||
one = {
|
||||
"이름": spec["이름"],
|
||||
**({"설명": said[spec["이름"]]} if spec["이름"] in said else {}),
|
||||
}
|
||||
one |= {k: spec[k] for k in ("단위", "고르기", "범위") if spec.get(k) is not None}
|
||||
inputs.append(one)
|
||||
return {"끝수": None, **kept, "입력": inputs, "출처": row.get("출처") or "자체"}
|
||||
|
||||
|
||||
def save(batch: list[dict]) -> dict:
|
||||
@@ -360,6 +383,7 @@ def save(batch: list[dict]) -> dict:
|
||||
row = ch.get("row")
|
||||
if not isinstance(row, dict) or FLOW not in row:
|
||||
continue
|
||||
check(row[FLOW]) # 꼴부터 — 입력 약속을 흐름에서 다시 쓰기 전에
|
||||
new = ch.get("op") == "add" or (ch.get("op") == "edit" and not ch.get("key"))
|
||||
if new:
|
||||
if part.get("file") != make.OWN:
|
||||
|
||||
Reference in New Issue
Block a user