fix(m02-df): 변환 흐름 화면 흠 넷 — 변수 예시값 · 표 찾기 실패 같은 뜻 · 다른 로직 서버 값 · 합계 끝수
- 변환: 설계 값 변수 예시값 = 줄 시험입력 · 없으면 check_master.시험입력 기본(글 수 → 수) · totalRound = null(옛 계는 끝수 없음) - Model CfLogic.totalRound(없음 = 기본 계금 1원 미만 버림 · null = 끝수 없음) · Round totalRoundFor · roundBy/roundText 가 null 받음 · Summary · M01 흐름 보기 합계가 그것을 씀 - Compute: 함수 결과 오류는 오류 값(「#N/A」 등)으로 넘김(화면 Eval 과 같음 · 받는 칸으로 번짐 · 옛 엔진은 그 줄을 비움) — 서버가 빈 칸 0 으로 계속 세던 차이 없앰 - 화면 값 물음(Entry_Detail queriesOf): 인력 · 기계 · 유가 조건 찾기도 자리 물음 · 재료 검색어 틀은 채운 글 · 다른 로직 입력은 서버 /logic-value 로 받은 설계 값째 셈(그 안 조건 찾기 · 단가까지) · Eval 은 서버 출력이 있으면 그것 - Values.one_value: 인력 · 기계 · 유가 자리 물음 = group_find - 전수 대조 시험입력 1,414/1,472(96.1%) · 기본 입력 1,429(97.1%) — 남은 49 는 sub4 범위규칙 칸 · 검색어 찾기 · 재료 값 차이 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VBToTCGk5dqDKeXCEP3vhk
This commit is contained in:
@@ -125,7 +125,8 @@ def _keys() -> list[str]:
|
||||
REASONS = [ # (알림에 든 말, 까닭) — 앞이 먼저
|
||||
("표에 여럿 맞음", "표 범위 규칙 다름 — 여럿 맞음(이상·이하 · 이상·미만 경계)"),
|
||||
("표에 없는 조건", "표 범위 규칙 다름 — 없는 조건(이상·이하 · 이상·미만 경계)"),
|
||||
("같음", "재료 검색어 자리 — 서버 조건 찾기(키 같음) ≠ 옛 검색어 찾기"),
|
||||
("검색어", "재료 검색어 틀 — 서버 검색어 찾기 대기(sub4)"),
|
||||
("같음", "조건 찾기 못 찾음(키 같음)"),
|
||||
("맞는 재료 없음", "재료 빈 검색어 — 서버 재료 값 찾기 다름"),
|
||||
("비어 있음", "단가 빈 품목 — 서버 처리 다름"),
|
||||
("값 없음", "단가 빈 품목 — 서버 처리 다름"),
|
||||
@@ -270,3 +271,16 @@ def test_전수_대조_옛_셈_같음() -> None:
|
||||
r for r in rows if r["시험입력"]["state"] == "흐름 셈 멈춤"
|
||||
][:3]
|
||||
assert report["시험입력"]["맞는 비율"] >= 0.5, report["시험입력"]
|
||||
|
||||
|
||||
def test_변수_예시값_합계_끝수() -> None:
|
||||
_copy()
|
||||
got = _shape("GF000007", "GF000226")
|
||||
for key, one in got.items():
|
||||
flow = one["flow"]
|
||||
design = next(b for b in flow["boxes"] if b["id"] == "in-design")
|
||||
assert all(v["example"] is not None for v in design["input"]["variables"]), key
|
||||
assert flow["totalRound"] is None # 옛 계는 끝수 없음
|
||||
box = next(b for b in got["GF000226"]["flow"]["boxes"] if b["id"] == "in-design")
|
||||
vars226 = {v["name"]: v["example"] for v in box["input"]["variables"]}
|
||||
assert vars226["직경"] == 60 # 줄의 시험입력(글 「60.0」 → 수)
|
||||
|
||||
@@ -854,9 +854,8 @@ def test_표_찾기_빈_조건칸_무엇이든_빈_값줄_건너뜀_실패는_
|
||||
monkeypatch.setattr(cp.dv, "one_value", lambda item, local=None: {"ok": True, "rows": BLOCK})
|
||||
for v, (screen_out, screen_breaks) in zip(vals, got):
|
||||
srv = cp.run(lg, {"v": v["v"]}, lambda key: {}, [])
|
||||
out = srv["outputs"]["o"]
|
||||
want = None if isinstance(screen_out, str) and screen_out.startswith("#") else screen_out
|
||||
assert (None if out is None else float(out)) == (None if want is None else float(want))
|
||||
out = srv["outputs"]["o"] # 오류 값은 화면과 같은 글(「#N/A」)
|
||||
assert out == screen_out if isinstance(screen_out, str) else float(out) == float(screen_out)
|
||||
assert [b["kind"] for b in srv["breaks"]] == screen_breaks
|
||||
|
||||
|
||||
@@ -915,3 +914,38 @@ def test_표_찾기_범위_경계_규칙_칸() -> None:
|
||||
)
|
||||
assert got == [[1, None], [2, None], [3, None], [3, None], [None, "표에 없는 조건"]]
|
||||
assert [list(cp._lookup(rule, block, {"x": x})) for x in xs] == got
|
||||
|
||||
|
||||
def test_화면_값_물음_조건_찾기_인력기계유가_검색어_틀_다른_로직() -> None:
|
||||
lg = {
|
||||
"key": None, "name": "t", "resultUnit": "", "userElements": [],
|
||||
"boxes": [
|
||||
{"id": "v", "kind": "input", "name": "설계", "input": {"mode": "variable", "elements": [], "variables": []}},
|
||||
{"id": "g", "kind": "input", "name": "기계", "input": {"mode": "group", "group": "기계", "variables": [], "elements": [
|
||||
{"ref": "EQ:{기계}#가격", "name": "가격 자리", "slot": "가격 자리", "spec": "", "unit": "-", "mode": "rule",
|
||||
"rule": {"field": "키", "op": "같음", "from": {"box": "v", "name": "기계"}}}]}},
|
||||
{"id": "m", "kind": "input", "name": "재료", "input": {"mode": "group", "group": "재료", "variables": [], "elements": [
|
||||
{"ref": "{}", "name": "레미콘 자리", "slot": "레미콘 자리", "spec": "", "unit": "㎥", "mode": "rule", "scope": {"구분": "레미콘"},
|
||||
"rule": {"field": "검색어", "op": "같음", "from": {"box": "v", "name": "a"}, "template": "레미콘 {a}-{b}",
|
||||
"slots": [{"name": "a", "from": {"box": "v", "name": "a"}}, {"name": "b", "from": {"box": "v", "name": "b"}}]}}]}},
|
||||
{"id": "o", "kind": "input", "name": "로직", "input": {"mode": "logic", "elements": [], "variables": [], "logic": {
|
||||
"key": "GC000270", "outputs": [{"name": "노무비", "unit": "원"}], "designs": [{"name": "기계", "unit": "-"}, {"name": "지역", "unit": "-"}],
|
||||
"examples": {"지역": "전국평균"}}}},
|
||||
],
|
||||
"links": [{"id": "l1", "from": {"box": "v", "name": "기계"}, "to": {"box": "o", "name": "기계"}}],
|
||||
} # fmt: skip
|
||||
pills = {"기계": "0201-0020", "a": 25, "b": "18"}
|
||||
got = _run(
|
||||
"cache.set(path.resolve(path.join(ROOT, 'M01_MasterData', 'M01_MasterData_UI_Logic_Api.ts')), { exports: { fetchLogics: async () => [] } });\n"
|
||||
"const D = loadTs(path.join(ROOT, 'M02_MasterTemplete', 'DataFlow', 'M02_DF_Entry_Detail.ts'));\n"
|
||||
f"const lg = {json.dumps(lg, ensure_ascii=False)};\nconst pills = {json.dumps(pills, ensure_ascii=False)};\n"
|
||||
"const qs = D.queriesOf(lg, (p) => pills[p.name] ?? null, M.elementPort)"
|
||||
".map(a => [a.port, a.q.group, a.q.value ?? null, a.q.logic ?? null, !!a.q.slot]);\n"
|
||||
"out([qs, E.evalLogic(lg, { o: { 노무비: 123 } }, { logics: {} }).ports.o]);"
|
||||
)
|
||||
qs, server = got
|
||||
assert ["가격 자리", "기계", "0201-0020", None, True] in qs
|
||||
assert ["레미콘 자리", "재료", "레미콘 25-18", None, True] in qs
|
||||
designs = {"기계": "0201-0020", "지역": "전국평균"}
|
||||
assert ["*", "기계", None, {"key": "GC000270", "designs": designs}, False] in qs
|
||||
assert server == {"노무비": 123} # 서버가 셈한 다른 로직 출력이 있으면 그것
|
||||
|
||||
@@ -573,7 +573,8 @@ def test_선_규칙_끝수_재료_조건_설계_때_정할_것(client: TestClien
|
||||
assert any("맞는 재료 없음" in e for e in bad["errors"]) and any(
|
||||
"표에 없는 조건" in e for e in bad["errors"]
|
||||
)
|
||||
assert bad["ports"]["f"]["합"] is None and _d(bad["cost"]["재료비"]) == 0
|
||||
# 함수 결과 오류 = 오류 값(화면 Eval 과 같음 · 받는 칸으로 번짐)
|
||||
assert bad["ports"]["f"]["합"] == "#N/A" and _d(bad["cost"]["재료비"]) == 0
|
||||
|
||||
|
||||
def test_표준_표_읽기_쓰기_처음값(client: TestClient, folder: Path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user