- main(sub7 a774b4e97 Model 덧) 받아 합침 · Compute 재료 조건 찾기는 sub7 의 틀 채우기 + 빈 단가 알림
- 남은 8: 표에 여럿 맞음 5(옛 find 의 값 칸 있는 줄만 거름 — lookup) · 빈 값이 든 식 3(옛 = 그 줄 비움 · 흐름 = 빈 칸 0)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
106 lines
4.8 KiB
Python
106 lines
4.8 KiB
Python
# ruff: noqa: E501
|
|
"""흐름 셈 값 찾기 = 옛 셈과 같은 뜻(PLAN 36-2 변환 대조 · sub4) — 마스터 읽기만.
|
|
|
|
못박는 것
|
|
- 표 블록 끝 칸 「·범위규칙」 = 줄마다 경계 말(범위규칙 첫 낱말 · 「이하 포함」 이면 맨 윗줄 이상·이하)
|
|
- 재료 값이 로직 입력(자재지역 · 계약종별)을 읽음 · 빈 단가 = 알림(blank) — 셈은 계속
|
|
- 재료 조건 찾기 field 검색어 = 옛 검색어 찾기(틀의 {자리} 를 채운 글)
|
|
- 고르기 글 값(「080」)은 글 그대로 — 수로 바꾸면 고르기 밖
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from decimal import Decimal
|
|
|
|
from M01_MasterData import M01_MasterData_Store as store
|
|
from M01_MasterData import M01_MasterData_Store_Flow as sflow
|
|
from M02_MasterTemplete.DataFlow import M02_DF_Compute as dc
|
|
from M02_MasterTemplete.DataFlow import M02_DF_Values as dv
|
|
|
|
|
|
def _old(key: str) -> dict:
|
|
row = store.logic(key)["logic"]
|
|
given = {k: str(v) for k, v in store.cm.시험입력(row).items()}
|
|
return {"given": given, "got": store.calc(key, given), "row": row}
|
|
|
|
|
|
def test_표_범위규칙_칸() -> None:
|
|
tables = [
|
|
t
|
|
for d in store.loaded()[0].values()
|
|
if d.get("그룹") in store.cm.mf.TABLE_GROUPS
|
|
for t in d.get("표") or []
|
|
]
|
|
ranged = [t for t in tables if "범위" in (t.get("조건") or {}).values()]
|
|
for t in ranged[:40]:
|
|
got = dv._table(str(t["키"]))
|
|
head, rows = got["rows"][0], got["rows"][1:]
|
|
assert head[-1] == dv.RANGE_RULE
|
|
first = str(t.get("범위규칙") or "초과·이하").split(" · ")[0].split(" (")[0]
|
|
assert {r[-1] for r in rows} <= {first, "이상·이하"}, t["키"]
|
|
closed = [
|
|
t
|
|
for t in ranged
|
|
if str(t.get("범위규칙") or "").startswith("이상·미만")
|
|
and "이하 포함" in str(t.get("범위규칙"))
|
|
]
|
|
for t in closed[:5]: # 맨 윗줄(위 끝이 가장 큰 줄)만 이상·이하
|
|
words = [r[-1] for r in dv._table(str(t["키"]))["rows"][1:]]
|
|
assert "이상·이하" in words and "이상·미만" in words, t["키"]
|
|
plain = next(t for t in tables if "범위" not in (t.get("조건") or {}).values())
|
|
assert dv.RANGE_RULE not in dv._table(str(plain["키"]))["rows"][0]
|
|
|
|
|
|
def test_재료는_로직_입력을_읽고_빈_단가는_알림() -> None:
|
|
old = _old("GC000685") # 모래 — 「지역: 입력」 · 입력 자재지역
|
|
line = next(x for x in old["got"]["lines"] if x["이름"] == "모래")
|
|
cond = next(x["요소"] for x in old["row"]["호표"] if x["이름"] == "모래")
|
|
assert dv._material(cond, "㎥", old["given"])["value"] == line["단가"]
|
|
alone = dv._material(cond, "㎥")
|
|
assert alone["ok"] is False and alone["blank"] is True # 입력이 없으면 그 값만 비움
|
|
el = {
|
|
"ref": "MT030715",
|
|
"name": "바퀴숫돌",
|
|
"spec": "",
|
|
"unit": "개",
|
|
"mode": "fixed",
|
|
} # 값 빈 품목
|
|
flow = {
|
|
"boxes": [
|
|
{
|
|
"id": "m",
|
|
"kind": "input",
|
|
"name": "재료",
|
|
"input": {"mode": "group", "group": "재료", "elements": [el], "variables": []},
|
|
}
|
|
],
|
|
"links": [],
|
|
}
|
|
if dv._price("재료", "MT030715").get("blank"):
|
|
got = dc.run(flow, {}, lambda k: {}, [], ["t"])
|
|
assert got["errors"] == [] and any("바퀴숫돌" in n for n in got["notes"])
|
|
|
|
|
|
def test_검색어_조건_찾기는_옛_검색어_찾기() -> None:
|
|
old = _old("GF000185") # 레미콘 {굵은골재최대치수}-{강도}-{슬럼프}
|
|
item = next(
|
|
x
|
|
for x in old["row"]["호표"]
|
|
if isinstance(x["요소"], dict) and "{" in str(x["요소"].get("검색어"))
|
|
)
|
|
want = next(x for x in old["got"]["lines"] if x["이름"] == item["이름"])["단가"]
|
|
text = store.cm.mf.fill(item["요소"]["검색어"], old["given"])
|
|
slot = {"mode": "rule", "field": "검색어", "op": "같음", "unit": item["단위"],
|
|
"scope": {k: item["요소"][k] for k in ("구분", "상세구분") if item["요소"].get(k)},
|
|
"ref": json.dumps(store._dec(item["요소"]), ensure_ascii=False, default=str), "inputs": old["given"]} # fmt: skip
|
|
assert dv.slot_price(slot, text)["value"] == want
|
|
assert dv.slot_price({**slot, "ref": None}, text)["value"] == want # 묶음 없이 범위 + 검색어
|
|
assert dv._filled("레미콘 {a}-{b}-{c}", "레미콘 25-18-080") == "레미콘 25-18-080"
|
|
assert dv._filled("싱글코아바렐 {규격}", "BX") == "싱글코아바렐 BX"
|
|
|
|
|
|
def test_고르기_글_값은_글_그대로() -> None:
|
|
assert sflow._value("080", {"080"}) == "080" and sflow._value("080") == Decimal(80)
|
|
assert sflow._value("3") == Decimal(3) and sflow._value("토사") == "토사"
|