"""702-3 B09 단가연결 즉시 금액 · [저장] 단추 · 서고 사본 산근. - 서고 사본(단가연결로 들여온 사전조합)의 단가산출 줄 = 산근 목록에 듦 · 대가 블록 단가 채움 (옛 흠 — 산근이 구조물 사본만 훑어 서고 사본 산근 0 · 대가 빈칸) - 셈 미리보기 길(`POST …/estimation/calc`) = 화면 캐시로 서버 셈 · 저장 안 함 · 로직 연결 줄 금액 - 화면 — 연결 즉시 뒤에서 셈(차례 번호 · 옛 요청 끊기) · [저장] 단추 · 옮길 때 물음 임시 층(견본 마스터 · 임시 storage) · 실제 마스터 · 프로젝트는 안 씀. """ import json import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from B09_Estimation import B09_Estimation_Prices as prices # noqa: E402 from B09_Estimation import B09_Estimation_Sangeun as sangeun # noqa: E402 from B09_Estimation.B09_Estimation_Calc_Base import compute_base # noqa: E402 from B09_Estimation.B09_Estimation_Calc_Labor import compute_labor # noqa: E402 from resources.tester.test_204_2_b09_bill_library import ( # noqa: E402, F401 daega_inputs, library, linked_resource_keys, world, ) B09 = ROOT / "B09_Estimation" def test_서고_사본_산근_목록에_듦_대가_단가_채움(world): root = world["root"] folder = library.import_copy(root, "precombo", "system", None, world["key"])["폴더"] daega = daega_inputs(root) block = next(b for b in daega["blocks"] if b["id"] == daega["libs"][folder]) wanted = [ln["key"] for ln in block["lines"] if ln["kind"] == "sangeun"] base = compute_base(prices.build_inputs(None, linked_resource_keys(root)), {}) sg = sangeun.build(root, base) assert [r["key"] for r in sg["sg_list"]] == wanted # 둘 다 산근 · 블록 줄 키 그대로 assert all(r["sum"] for r in sg["sg_list"]) assert sg["sg_list"][0]["uses"] == ["서고 서고 조합"] by_key = {r["key"]: r for r in sg["sg_list"]} labor = compute_labor(daega, {**base, "gaps": []}, by_key) row = next(r for r in labor["daega"] if r["key"] == block["id"]) saved = row["sum"] # 742-1 서고 SC 안 줄 저장 수량(2 · 1 · 3) = 굳힌 사본 그대로 assert saved and not row.get("blank") cover = {block["cover"]: {ln["cid"]: {"qty": q} for ln, q in zip(block["lines"], (2, 1, 3))}} labor = compute_labor(daega, {**base, "gaps": []}, by_key, cover) row = next(r for r in labor["daega"] if r["key"] == block["id"]) assert row["sum"] == saved and not row.get("blank") # 이 공사 입력(같은 수) = 같은 값 def test_화면_연결_뒤_셈_저장_단추_옮김_물음_TS(): shell = (B09 / "B09_Estimation_UI_Shell.ts").read_text("utf-8") live = (B09 / "B09_Estimation_UI_Live.ts").read_text("utf-8") router = (B09 / "B09_Estimation_Router.py").read_text("utf-8") assert '"/{project_id}/estimation/calc"' in router assert "AbortController" in live and "seq" in live # 차례 번호 · 옛 요청 끊기 assert "Common_Btn_Save" in shell and "b09Save" in shell assert "askProjectLeave" in shell # 단계 이동 = 물음(저장 · 폐기 · 취소) def test_뒤_셈_차례_번호_옛_요청_끊기_셈_중(): proc = subprocess.run( ["node", str(Path(__file__).parent / "helper_702_3_live.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr o = json.loads(proc.stdout) assert o["wait"] == ["hand:a"] and o["same"] == [] # 로직 연결이 서버 기준과 다른 줄만 assert o["strip"] == {} # 기다리는 줄 = 옛 산근 단가 안 씀 assert o["mark"] == ["셈 중", None] # 그 줄 금액 칸만 assert o["sentAfterSame"] == 1 # 가는 중 같은 지문 = 다시 안 보냄 assert o["firstAborted"] is True # 바뀐 지문 = 옛 요청 끊음 assert o["url"] == "/api/projects/P1/estimation/calc" assert o["settled"] == [[2, 2]] and o["busyAfter"] is False # 마지막 것만 받음 assert o["cancelled"] == [True, False] # 기다릴 줄 없어짐 = 가던 것 끊음 assert o["failed"] == [ ["warning"], [None, 4], 4, ] # 못 받음 = 알림 한 번 · 같은 지문 다시 안 보냄