feat(822-2): 식 고름 한 곳(목록 › 꼴) · 까닭 글 · 새 기계 식 등록 · 쓰는 계산식 · 직접 값 · 전력 미리보기

- M02_Machine_Hourly.pick = 목록 › 그 기계 식 › 꼴(내 기계와 같은 규칙) · why = 값 모자란 까닭(가격 없음 · 범위 · 일 단위 손료 …)
- 데이터 흐름 · 사본 모으기 · M01 · 불러오기 · 줄 쌓기 모두 pick 을 씀(데이터 흐름 옛 짝 고름 지움)
- 내 기계 꼴: 전력 · 전력 + 조종원 · 직종 입력 · 손료계수 한 칸 · 직접(GC001199 — 줄 쌓기 회색 풀림) · 연료 + 전력 = 400
- M01 [새 기계] 저장 = 꼴 식 「기계」 목록에 등록 · M01 에서 만든 기계 지우면 목록에서 뺌 · 상세 「쓰는 계산식」(POST /machine/formula) · 목록 시간당 「—」 대신 까닭 글
- 미리보기 짝: 잡품 = (주연료 + 전력) × %(전력 기종 = 전력비의 %)
- 시험 test_822_2 새로 · test_804_2 갈래에 전력 줄 더함(손료만 식과 전력 식은 다른 갈래 — 모르타르 믹서)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-12 18:12:34 +09:00
co-authored by Claude Opus 5.5
parent 58bebaf0c3
commit 062fb07668
15 changed files with 458 additions and 68 deletions
+9 -36
View File
@@ -258,59 +258,32 @@ def _user(uid: str, local: list[dict]) -> dict:
MACHINE_SEP = "#" # 입력 판(sub3) 기계 요소 ref 「EQ키#칸」
HOURLY = "시간당 경비" # 기계 칸 이름 — 기계 시간당 경비 로직으로 셈(기종 → 로직 짝)
_MACHINE_PLAIN = {"기계", "지역", "보정작업", "조종원직종"} # 이 밖의 입력 = 부착 장비 전용
def _machine_family() -> list[dict]:
"""기계 시간당 경비 로직 — 「건설기계」 장 파일 안 · 입력 「기계」 고르기가 있는 돈 로직."""
files = store.loaded()[0]
return [
row
for name, data in files.items()
if data.get("그룹") == "로직" and "건설기계" in name
for row in data.get("줄") or []
if str(row.get("결과단위") or "").startswith("원")
and any(i.get("이름") == "기계" and i.get("고르기") for i in row.get("입력") or [])
]
def _machine_rank(row: dict) -> tuple:
"""짝 차례(옛 EasyCalc `pickMachine` 와 같음) — 부착 전용 · 손료만 · 보정 · 기종 수 · 키."""
names = [i.get("이름") for i in row.get("입력") or []]
codes = next(i.get("고르기") for i in row["입력"] if i.get("이름") == "기계")
attach = any(n not in _MACHINE_PLAIN for n in names)
loss = "지역" not in names
return (attach, loss, loss and "보정작업" in names, len(codes), str(row.get("키")))
def _machine_hourly(key: str, inputs: dict) -> dict:
"""기계 한 시간 값 — 기종을 받는 기계경비 로직 가운데 짝 차례 첫째 · 빈 입력은 첫 고르기."""
"""기계 한 시간 값 — 식 고름 = `M02_Machine_Hourly.pick`(목록 › 꼴 · 822-2) · 빈 입력은 첫 고르기."""
from M02_MasterTemplete import M02_Machine_Hourly as mh
row, why = _brief(key, "기계")
if row is None:
return {"ok": False, "reason": why}
code = str(row.get("원문번호") or "")
fit = [r for r in _machine_family() if code in [str(c) for c in _codes(r)]]
if not fit:
return {"ok": False, "reason": f"「{row.get('이름')}」 은 시간당 경비를 셀 자료가 없음"}
logic = min(fit, key=_machine_rank)
logic = mh.pick(row)
if lack := mh.why(row, logic):
return {"ok": False, "reason": f"「{row.get('이름')}」 — {lack}"}
given = {}
for spec in logic.get("입력") or []:
name = spec.get("이름")
if name != "기계":
given[name] = inputs.get(name, (spec.get("고르기") or [None])[0])
args = "".join(f", {n}='{v}'" for n, v in given.items())
ref = f"로직({logic['키']}, 기계='{code}'{args})"
args = "".join(f", {n if n.isidentifier() else repr(n)}='{v}'" for n, v in given.items())
mine = f", 기계='{code}'" if mh.takes_machine(logic) else ""
ref = f"로직({logic['키']}{mine}{args})"
line = {"종류": "로직", "요소": ref, "이름": "기계", "단위": "시간", "수량": "1"}
got = _money(_calc({}, _row(line, ())), "계")
return {**got, "name": row.get("이름"), "unit": "원/시간"} if got["ok"] else got
def _codes(row: dict) -> list:
return next(
(i.get("고르기") or [] for i in row.get("입력") or [] if i.get("이름") == "기계"), []
)
def one_value(item: dict, local: list[dict] | None = None) -> dict:
"""물음 한 줄 `CfQuery {id, group, ref? · table? · unit? · field? · inputs?}` → `CfAnswer`.