fix(M02): 흐름 셈 옛 셈과 같은 뜻 — 재료 값이 로직 입력(자재지역 · 계약종별) 읽음 · 빈 단가는 알림 · 표 범위 경계 칸 · 검색어 조건 찾기(PLAN 36-2 대조)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
This commit is contained in:
2026-10-02 00:35:21 +09:00
co-authored by Claude Opus 5.5
parent fa33abb5f0
commit 9872ad66f5
2 changed files with 73 additions and 21 deletions
+27 -8
View File
@@ -113,10 +113,12 @@ def _element_value(
) -> Any:
"""요소 알약 값 — 재료는 방식 셋 · 그 밖은 그룹 값 · 설계 값이 이김(선택 자리 = 키 · 수)."""
mode = el.get("mode") or "fixed"
env = ctx.get("env") or {} # 로직 입력(자재지역 · 계약종별 …) — 옛 셈 재료 찾기가 읽음
if group == "재료" and mode == "choice":
if isinstance(given, (int, float, Decimal)) and not isinstance(given, bool):
return given
got = dv.slot_price({"mode": "choice", "default": el.get("default")}, pick=given or None)
slot = {"mode": "choice", "default": el.get("default"), "inputs": env}
got = dv.slot_price(slot, pick=given or None)
elif group == "재료" and mode == "rule":
rule = el.get("rule") or {}
src = rule.get("from") or {}
@@ -125,13 +127,16 @@ def _element_value(
"scope": el.get("scope"),
"field": rule.get("field"),
"op": rule.get("op"),
"ref": el.get("ref"),
"unit": el.get("unit"),
"inputs": env,
}
got = dv.slot_price(slot, ports.get(src.get("box"), {}).get(src.get("name")))
if not got["ok"] and el.get("default"):
if not got["ok"] and not got.get("blank") and el.get("default"):
errors.append(
f"「{box.get('name')} · {el.get('name')}」 {got['reason']} — 기본 품목으로 셈"
)
got = dv.slot_price({"mode": "fixed", "ref": el["default"]})
got = dv.slot_price({"mode": "fixed", "ref": el["default"], "inputs": env})
elif group in dv.GROUP_RULE and mode == "rule": # 인력 · 기계 · 유가전력 조건 찾기
rule = el.get("rule") or {}
src = rule.get("from") or {}
@@ -144,9 +149,11 @@ def _element_value(
elif given is not None:
return given
else:
got = dv.one_value(
{"group": group, "ref": el.get("ref"), "unit": el.get("unit")}, ctx["local"]
)
item = {"group": group, "ref": el.get("ref"), "unit": el.get("unit"), "inputs": env}
got = dv.one_value(item, ctx["local"])
if not got["ok"] and got.get("blank"): # 옛 셈처럼 그 값만 비움(알림) — 셈은 계속
ctx["notes"].append(f"「{box.get('name')} · {el.get('name')}」 {got.get('reason')}")
return None
if not got["ok"]:
errors.append(f"「{box.get('name')} · {el.get('name')}」 {got.get('reason')}")
return None
@@ -487,7 +494,8 @@ NA_VALUE = "#N/A" # 함수 칸으로 가는 표 찾기 실패 — 칸에 NA()
def run(lg: dict, values: dict, load: Loader, local: list[dict], stack: list | None = None) -> dict:
"""셈 — {ports, outputs, cost, errors, breaks, filled}(filled = 받는 칸에 값만 되돌려 넣음)."""
ctx = {"load": load, "local": local, "stack": stack or [lg.get("key") or ""]}
ctx = {"load": load, "local": local, "stack": stack or [lg.get("key") or ""], "notes": [],
"env": _env(lg, values)} # fmt: skip
boxes = {b["id"]: b for b in lg.get("boxes") or []}
links = lg.get("links") or []
name = lambda i: boxes.get(i, {}).get("name") or i # noqa: E731
@@ -640,4 +648,15 @@ def run(lg: dict, values: dict, load: Loader, local: list[dict], stack: list | N
if b["id"] in sheets:
b["func"]["sheet"] = sheets[b["id"]]
return {"ports": ports, "arrived": arrived, "outputs": outputs, "cost": cost, "errors": errors,
"breaks": breaks, "filled": filled} # fmt: skip
"breaks": breaks, "notes": ctx["notes"], "filled": filled} # fmt: skip
def _env(lg: dict, values: dict) -> dict:
"""입력 상자 변수 값(설계 값 · 없으면 예시값) — 재료 찾기가 읽는 로직 입력."""
return {
v.get("name"): (values.get(b["id"]) or {}).get(v.get("name"), v.get("example"))
for b in lg.get("boxes") or []
if b.get("kind") == "input"
for v in (b.get("input") or {}).get("variables") or []
if v.get("name")
}