merge: origin/sub_laptop_1 받기 — 노임 준용 + 품셈재료 연결 양쪽 살림
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
@@ -321,7 +321,7 @@ def evaluate(node, env: dict, master: Master, depth: int = 0):
|
||||
raise FormulaError(f"모르는 이름 「{node[1]}」")
|
||||
return env[node[1]]
|
||||
if kind == "ref":
|
||||
value = master.value(fill(node[1], env))[0]
|
||||
value = element(master, fill(node[1], env), env)[0]
|
||||
if value is None:
|
||||
raise FormulaError(f"「{node[1]}」 값 없음 — 관리자가 채울 값")
|
||||
if isinstance(value, list):
|
||||
@@ -426,8 +426,8 @@ def run(master: Master, ref: str, given: dict, depth: int = 0) -> dict:
|
||||
sums = dict.fromkeys(COST_ITEMS, Decimal(0))
|
||||
lines = []
|
||||
for item in row.get("호표", []):
|
||||
alias = None
|
||||
qty = evaluate(parse(item["수량"]), env, master, depth)
|
||||
source = None
|
||||
if item["종류"] == "로직":
|
||||
bundle = evaluate(parse(item["요소"]), env, master, depth)
|
||||
price = bundle["계"]
|
||||
@@ -437,15 +437,17 @@ def run(master: Master, ref: str, given: dict, depth: int = 0) -> dict:
|
||||
else {item["비목"]: qty * price}
|
||||
)
|
||||
else:
|
||||
node = parse(item["요소"])
|
||||
if node[0] == "field": # 값 묶음 요소의 칸 — 「재료:시중물가:M….채택」
|
||||
price = master.get(fill(node[1][1], env))["값"][node[2]]
|
||||
else:
|
||||
price, alias = master.value(fill(item["요소"], env))
|
||||
ref = fill(item["요소"], env)
|
||||
try:
|
||||
price, source = element(master, ref, env)
|
||||
except FormulaError:
|
||||
if qty != 0:
|
||||
raise
|
||||
price = None
|
||||
if price is None and qty == 0:
|
||||
price = Decimal(0) # 안 쓰는 재료 줄 — 값이 비어도 금액 0
|
||||
if price is None:
|
||||
raise FormulaError(f"「{fill(item['요소'], env)}」 값 없음 — 관리자가 채울 값")
|
||||
raise FormulaError(f"「{ref}」 값 없음 — 관리자가 채울 값")
|
||||
split = {item["비목"]: qty * price}
|
||||
for k, v in split.items():
|
||||
sums[k] += v
|
||||
@@ -457,7 +459,7 @@ def run(master: Master, ref: str, given: dict, depth: int = 0) -> dict:
|
||||
"단가": price,
|
||||
"금액": qty * price,
|
||||
"비목": split,
|
||||
**({"출처": f"준용: {alias}"} if alias else {}),
|
||||
**({"출처": source} if source else {}),
|
||||
}
|
||||
)
|
||||
for extra in row.get("덧줄", []):
|
||||
@@ -523,9 +525,12 @@ def _check_node(row, node, known: set, master: Master, where: str, out: list, ca
|
||||
refs = _expand(row, part[1], master) or []
|
||||
for ref in refs:
|
||||
try:
|
||||
master.get(ref)
|
||||
link = master.get(ref).get("연결")
|
||||
except FormulaError as e:
|
||||
out.append(f"{where} · {e}")
|
||||
continue
|
||||
if isinstance(link, dict) and link.get("지역") == "입력" and REGION not in known:
|
||||
out.append(f"{where} · 「{ref}」 는 입력 「{REGION}」 필요")
|
||||
if kind == "field" and part[1][0] == "ref":
|
||||
for ref in _expand(row, part[1][1], master) or []:
|
||||
try:
|
||||
@@ -633,3 +638,7 @@ def find_loops(graph: dict[str, set]) -> list[list[str]]:
|
||||
if node not in state:
|
||||
visit(node, [node])
|
||||
return loops
|
||||
|
||||
|
||||
# 품셈재료 단가 — 서로 부르는 모듈이라 끝에서 읽음
|
||||
from master_material import LINKED, REGION, element # noqa: E402, F401
|
||||
|
||||
Reference in New Issue
Block a user