"""277 「운반 단가」 창 오른쪽 계산 칸 — 미리보기 `blocks`(머리 · 호표 줄 · 계 · 출처 · 하위 산근) · 옛 `lines` · 단가 그대로 · 칸 고르기(운반거리만 = 거리 칸만 · Cm 받음 = 사이클 칸까지) · 운반거리 칸 높이(`ui-input--sm`) · 「자동계산」 단추.""" import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from B08_Quantity.B08_Quantity_Haul_Cycle import FILL # noqa: E402 from B09_Estimation.B09_Estimation_Router import PreviewBody, logic_preview # noqa: E402 from B09_Estimation.B09_Estimation_Sangeun import _input_names # noqa: E402 GIVEN = {"재료": "토사", "운반거리": 23.877, "지역": "전국평균", "보정작업": "해당 없음"} CYCLE_ONLY = {"Cm", "사이클시간", "t2"} def _src(name: str) -> str: return (ROOT / name).read_text(encoding="utf-8") def test_미리보기_칸_GF000284(tmp_path): got = logic_preview(tmp_path, PreviewBody(code="GF000284", given=GIVEN)) (block,) = got["blocks"] # 하위 산근 없음 assert block["logic"] == "GF000284" and block["source"] == "산림품셈 10-12-1" assert block["unit"] == got["unit"] == "㎥" assert block["price"] == got["price"] and got["price"] > 0 assert block["parts"] == got["parts"] assert block["head"][0].startswith(block["name"]) and block["foot"].startswith("계 :") assert any(h.startswith("Cmt = ") for h in block["head"]) # 중간값 names = [ln["name"] for ln in block["lines"]] assert names == ["굴착기(무한궤도) 0.7㎥(적재)", "덤프트럭 15ton(운반)"] truck = block["lines"][1] assert truck["qty"] == 1.25 and truck["unit"] == "시간" and len(truck["text"]) == 3 assert set(truck) == {"name", "spec", "qty", "unit", "kind", "labor", "material", "expense", "why", "text"} # fmt: skip # 옛 글 줄 그대로 = 머리 + 줄 글 + 계 texts = [t for ln in block["lines"] for t in ln["text"]] assert got["lines"] == [*block["head"], *texts, block["foot"]] def test_칸_고르기_규칙(): def boxes(code: str) -> tuple[bool, bool]: names = _input_names(code) return any(n in FILL for n in names), any(n in CYCLE_ONLY for n in names) assert boxes("GF000284") == (True, False) # 운반거리만 = 거리 칸만 assert boxes("GF000134") == (True, True) # Cm = 사이클 칸까지 modal = _src("B09_Estimation/B09_Estimation_UI_Haul_Modal.ts") assert 'CYCLE_ONLY = new Set(["Cm", "사이클시간", "t2"])' in modal assert "want.some((n) => CYCLE_ONLY.has(n)) ? [cycleBox(input)]" in modal assert 'el("pre"' not in modal and "cycleLines" not in modal # 조합 = 담은 로직 줄마다 미리보기 · 최신 응답만 · 하위 산근 이어 붙임 · 셈 중 옛 칸 흐리게 for want in ("st.lines.map((l) => ({ code: l.로직, given: libFilled(l)", "my !== seq", '"하위 산근"', 'classList.add("is-stale")', "조합 단가 = [적용] · [저장] 뒤 서버 셈"): # fmt: skip assert want in modal, want def test_칸_그리기_테마(): steps = _src("B09_Estimation/B09_Estimation_UI_Haul_Steps.ts") for want in ("export function distBox", "export function cycleBox", "export function logicBox", "export function splitHead", 'toLocaleString("ko-KR"', '"입력값"', '"중간값"', '"호표"', "빈칸 — "): # fmt: skip assert want in steps, want css = _src("B09_Estimation/B09_Estimation_UI_Haul_Steps.css") assert "#" not in css.replace("/*", "").split("*/", 1)[1] # 색 = 테마 변수만 assert "var(--color-danger)" in css and "text-align: right" in css def test_운반거리_칸_높이_자동계산_단추(): values = _src("M02_MasterTemplete/M02_Labor_Values.ts") assert '"ui-input ui-input--sm m02-inputval__control"' in values modal = _src("B09_Estimation/B09_Estimation_UI_Haul_Modal.ts") assert '"거리에서"' not in modal and 'AUTO = "자동계산"' in modal for want in ("unown && o.dist", 'variant: "pill"', '"aria-pressed"', '"is-active"', "st.own.delete(name);", "st.libOwn.delete(id);"): # fmt: skip assert want in modal, want