feat(M01): 흐름 셈 단가 = mf.run 을 부른 쪽 자리(프로젝트 사본이면 그 단가 · PLAN 36-4 브레인 답)
- M02_DF_Values.SOURCE — 단가 · 값 · 표를 넘겨진 Master 에서(없으면 마스터) · 견본 로직은 그 Master 에 잠깐 얹어 셈 - Store_Flow 옛 엔진 갈래가 master 를 넘김 · 다른 로직(흐름 · 옛)도 같은 자리 - 찾기 목록(재료 조건 찾기 · 그룹 찾기 · 기계 짝)은 마스터 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
This commit is contained in:
@@ -11,6 +11,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from contextvars import ContextVar
|
||||
from typing import Any
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as store
|
||||
@@ -21,6 +22,36 @@ RANGE_LOW, RANGE_HIGH = "·아래", "·위"
|
||||
FIELDS = (*cm.mf.COST_ITEMS, "계")
|
||||
|
||||
|
||||
# 단가 자리 — `mf.run` 을 부른 쪽이 넘긴 Master(프로젝트 사본이면 그 단가) · 없으면 마스터
|
||||
# ponytail: 단가 · 값 · 표만 이 자리 · 찾기 목록(재료 조건 찾기 · 그룹 찾기 · 기계 짝)은 마스터에서
|
||||
SOURCE: ContextVar = ContextVar("df_price_source", default=None)
|
||||
_DRAFT = "GX999998" # 단가 자리에 잠깐 얹는 견본 로직 키
|
||||
|
||||
|
||||
def _whole():
|
||||
return SOURCE.get() or store.loaded()[1]
|
||||
|
||||
|
||||
def _calc(inputs: dict, row: dict) -> dict:
|
||||
"""`Store.calc("", inputs, row)` 와 같은 꼴 — 단가 자리가 넘겨졌으면 그 Master 로 셈."""
|
||||
whole = SOURCE.get()
|
||||
if whole is None:
|
||||
return store.calc("", inputs, row, None)
|
||||
slot = whole.index.setdefault(_DRAFT[:2], {})
|
||||
slot[_DRAFT] = {**store._dec(row), "키": _DRAFT}
|
||||
try:
|
||||
given = cm.mf.fill_empty(slot[_DRAFT], {k: store._dec(v) for k, v in inputs.items()})
|
||||
got = cm.mf.run(whole, _DRAFT, given)
|
||||
except (cm.mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueError) as e:
|
||||
return {"ok": False, "reason": str(e) or type(e).__name__}
|
||||
finally:
|
||||
slot.pop(_DRAFT, None)
|
||||
if "결과" in got:
|
||||
return {"ok": True, "result": got["결과"], "middle": got["중간"]}
|
||||
sums = {k: got[k] for k in cm.mf.BUNDLE}
|
||||
return {"ok": True, "lines": got["줄"], "sums": sums, "middle": got["중간"]}
|
||||
|
||||
|
||||
# ── 입력 값 ────────────────────────────────────────────────────────────
|
||||
def _row(line: dict, names) -> dict:
|
||||
"""단가를 `/calc` 와 같은 셈으로 — 호표 한 줄(수량 1)짜리 저장 안 하는 견본 로직."""
|
||||
@@ -65,7 +96,7 @@ def _pick(key: Any) -> dict | None:
|
||||
def _material(cond: dict, unit: str) -> dict:
|
||||
"""검색어 묶음 재료 단가 — 기존 로직 재료 줄과 같은 길(검색어 · 자동값 차례 · 단위 환산)."""
|
||||
line = {"종류": "재료", "요소": cond, "이름": cond.get("검색어") or "재료", "수량": "1"}
|
||||
got = store.calc("", {}, _row({**line, "단위": unit, "비목": "재료비"}, ()), None)
|
||||
got = _calc({}, _row({**line, "단위": unit, "비목": "재료비"}, ()))
|
||||
if not got["ok"]:
|
||||
return got
|
||||
one = got["lines"][0]
|
||||
@@ -85,7 +116,7 @@ def _material(cond: dict, unit: str) -> dict:
|
||||
def _brief(key: str, want: str) -> tuple[dict | None, str | None]:
|
||||
"""마스터 줄 하나 + 그룹 확인 — (줄, 까닭) · 유가전력은 재료 그룹 안 MO 키."""
|
||||
try:
|
||||
row = store.loaded()[1].get(key)
|
||||
row = _whole().get(key)
|
||||
except cm.mf.FormulaError as e:
|
||||
return None, str(e)
|
||||
group = store.mk.GROUP_OF.get(store.mk.id_of(key))
|
||||
@@ -102,7 +133,7 @@ def _price(group: str, key: str, unit: str = "") -> dict:
|
||||
kind, cost = {"인력": ("인력", "노무비"), "재료": ("재료", "재료비")}[group]
|
||||
line = {"종류": kind, "요소": key, "이름": row.get("이름") or key, "수량": "1"}
|
||||
line = {**line, "단위": unit or row.get("단위") or "", "비목": cost}
|
||||
got = store.calc("", {}, _row(line, ()), None)
|
||||
got = _calc({}, _row(line, ()))
|
||||
if not got["ok"]:
|
||||
return got
|
||||
one = got["lines"][0]
|
||||
@@ -135,6 +166,12 @@ def _plain_value(group: str, key: str, field: str | None) -> dict:
|
||||
def _table(key: str, at: Any = None) -> dict:
|
||||
"""소요량 · 계수 표 → 머리 줄 + 줄(조건 칸 → 값 칸 · 범위가 있는 칸은 「·아래」 「·위」 두 칸 ·
|
||||
그 칸에 수 하나면 아래 · 위 같은 수) · at = 줄 차례(0부터)면 머리 줄 + 그 줄 하나."""
|
||||
if SOURCE.get() is not None: # 단가 자리(프로젝트 사본)의 표
|
||||
try:
|
||||
table = SOURCE.get().get(key)
|
||||
except cm.mf.FormulaError:
|
||||
table = None
|
||||
return _table_of(table, key, at)
|
||||
files = store.loaded()[0]
|
||||
table = next(
|
||||
(
|
||||
@@ -146,6 +183,10 @@ def _table(key: str, at: Any = None) -> dict:
|
||||
),
|
||||
None,
|
||||
)
|
||||
return _table_of(table, key, at)
|
||||
|
||||
|
||||
def _table_of(table: dict | None, key: str, at: Any) -> dict:
|
||||
if table is None:
|
||||
return {"ok": False, "reason": f"없는 표 「{key}」"}
|
||||
conds, lines = table.get("조건") or {}, table.get("줄") or []
|
||||
@@ -236,7 +277,7 @@ def _machine_hourly(key: str, inputs: dict) -> dict:
|
||||
args = "".join(f", {n}='{v}'" for n, v in given.items())
|
||||
ref = f"로직({logic['키']}, 기계='{code}'{args})"
|
||||
line = {"종류": "로직", "요소": ref, "이름": "기계", "단위": "시간", "수량": "1"}
|
||||
got = _money(store.calc("", {}, _row(line, ()), None), "계")
|
||||
got = _money(_calc({}, _row(line, ())), "계")
|
||||
return {**got, "name": row.get("이름"), "unit": "원/시간"} if got["ok"] else got
|
||||
|
||||
|
||||
@@ -269,7 +310,7 @@ def one_value(item: dict, local: list[dict] | None = None) -> dict:
|
||||
elif group == "기계" and str(ref or "").startswith("로직("):
|
||||
inputs = item.get("inputs") or {}
|
||||
line = {"종류": "로직", "요소": ref, "이름": "기계", "단위": "시간", "수량": "1"}
|
||||
got = _money(store.calc("", inputs, _row(line, inputs), None), field)
|
||||
got = _money(_calc(inputs, _row(line, inputs)), field)
|
||||
elif group == "기계" and field == HOURLY:
|
||||
got = _machine_hourly(str(ref or ""), item.get("inputs") or {})
|
||||
elif group in ("기계", "유가전력", "환율", "요율"):
|
||||
|
||||
Reference in New Issue
Block a user