Files
Aislo/resources/tester/test_809_1_import_labor.py
T
eomsangdonandClaude Opus 5.5 c5067aa2b6 feat(809-1a): 일위대가 불러오기 = 경쟁사 로직 인정 · 요소만 연결 · [수정] 모달 = 일위대가 컨테이너 부품 · 기초 판정 걷음
- [수정] 모달 = Labor_Table(읽기 · 덧칸 표지 · 엑셀 금액) · 줄 = 로직(단가산출 · 일위대가) / 요소(연결됨 · 후보 · 못 이음) · 단가산출 줄 = 가져온 식 SK 수식 탭 모달(Labor_SkEdit) · 서버 hopyo-view(M02_Hopyo_View)
- 엑셀 보기 목록 · 칠 = 줄 표지(View.listing) · 단가산출 탭 = 블록 목록 + [가져온 식으로 열기] · [내 단가산출로]
- 걷음(요구 703): 판정 체계 785(Judge · Solve · Bind · San_Basis 다섯 · Make.Move · Row 1차 판정 · 화면 Check · CheckRows · Rows · Block · JudgeApi · Picks · Judge.css) · [우리 기초로 바꾸기](to-base) · 근거 기초 제안 · Clause 기초 판정
- 시험 지움: 642_2(Bind · Solve) · 642_3(Row 1차 판정) · 642_5(옮기기 Move) · 642_6(판정 화면) · 786_2(옛 [수정] 모달) · 793_3a(근거 → 기초 제안) — 모두 걷은 기초 판정 길 몫
- 시험 고침: 642_1 · 794_2a2 · 794_2b(근거 제안 부분만 뺌) · 793_2 · 793_3b(기초 바꾸기 기대 → 없음) · 627 · 779_2 · 785_4 · 807_1 · m02_hopyo_excel · grid · stmate(judge 길 → view 길)
- 새 시험 test_809_1_import_labor(기초 길 0 · 표지 1,350 줄 · 가져온 식 SK · 모달 = Labor_Table · 금액 = 엑셀)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 19:17:58 +09:00

139 lines
7.8 KiB
Python

# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀
"""809-1 엑셀 불러오기 일위대가 = 경쟁사 로직 인정 · 요소만 연결(요구 702 · 703) — 임시 storage · M01 그대로.
① 기초 길 0 — 판정 · 근거 기초 제안 · [우리 기초로 바꾸기] · [옮기기] 서버 · 화면 모두 없음
② 줄 표지 = 로직(단가산출 · 일위대가) / 요소(연결됨 · 후보 · 못 이음) — 실무 여덟 1,350 줄 · 갈래 수 그대로
③ 로직 줄 = 가져온 식 SK(경쟁사 로직 그대로 · 엑셀 단가 = 엑셀)
④ [수정] 모달 = 일위대가 컨테이너 부품(`Labor_Table` · 읽기 · 덧칸 표지 · 엑셀 금액)
⑤ 금액 같음 — 보기 문서(엑셀 숫자 그대로 고정 줄) 1 단위 값 = 엑셀 호표 단가(실무 북부청 호표 모두)
실무 엑셀 없으면 그 시험만 skip.
"""
from __future__ import annotations
import importlib.util
from collections import Counter
from pathlib import Path
import helper_m02_hopyo_golden as golden
import pytest
from M02_MasterTemplete import M02_Hopyo_Build as hb
from M02_MasterTemplete import M02_Hopyo_Excel as hx
from M02_MasterTemplete import M02_Hopyo_Fixed as hfix
from M02_MasterTemplete import M02_Hopyo_Store as hs
from M02_MasterTemplete import M02_Hopyo_View as hv
from M02_MasterTemplete import M02_Labor_Ref as refs
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete import M02_Sangeun_FromHopyo as fh
from M02_MasterTemplete import M02_Sangeun_Imported as imp
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 같은 임시 층
ROOT = Path(__file__).resolve().parents[2]
M02 = ROOT / "M02_MasterTemplete"
MARKS = {"단가산출", "일위대가", "연결됨", "후보", "못 이음"}
def _ts(name: str) -> str:
return (M02 / f"M02_MasterTemplete_{name}.ts").read_text(encoding="utf-8")
# ── ① 기초 길 0 ──────────────────────────────────────────────────────────
def test_basis_paths_gone() -> None:
for mod in ("Hopyo_Judge", "Hopyo_Solve", "Hopyo_Bind", "San_Basis", "San_Basis_Store"):
assert importlib.util.find_spec(f"M02_MasterTemplete.M02_{mod}") is None, mod
for name in ("Hopyo_Check", "Hopyo_CheckRows", "Hopyo_Rows", "Hopyo_Block", "Hopyo_JudgeApi"):
assert not (M02 / f"M02_MasterTemplete_{name}.ts").exists(), name
assert not (M02 / "logic/M02_MasterTemplete_Hopyo_Picks.ts").exists()
assert not hasattr(imp, "to_base")
router = (M02 / "M02_Hopyo_Router.py").read_text(encoding="utf-8")
for path in ('"/layers/{layer}/hopyo-judge', '/check"', '/move"', '/price"', "hopyo-basis/"):
assert f"@router.get({path}" not in router and f"@router.post({path}" not in router
assert "/hopyo/{key}/move" not in router and "/hopyo/{key}/check" not in router
assert '"to-base"' not in (M02 / "M02_Sangeun_Router.py").read_text(encoding="utf-8")
from M02_MasterTemplete import M02_Hopyo_Make as hmake
assert not hasattr(hmake, "Move") and not hasattr(hmake.Lines, "picks")
panel, model = _ts("Hopyo_ImportedPanel"), (M02 / "logic/M02_Hopyo_Imported_Model.ts").read_text("utf-8") # fmt: skip
for gone in ("ToBase", "PickBase", "우리 기초로 바꾸기", "BasisCand"):
assert gone not in panel + model + _ts("Hopyo_Imported"), gone
# ── ② 줄 표지 ───────────────────────────────────────────────────────────
def test_marks_on_eight_files() -> None:
linker, total, n = hfix.Linker(True), Counter(), 0
for tag in golden.FILES:
book = golden.read(tag) if golden.FILES[tag].exists() else None
if book is None:
pytest.skip(f"실무 엑셀 없음 {tag}")
for h in book["호표"]:
got = hv.of(book, int(h["번"]), linker)
assert len(got["줄"]) == len(h.get("줄") or []) == len(got["문서"]["담은로직"])
for m in got["줄"]:
assert m["표지"] in MARKS and m["갈래"] == ("로직" if m["표지"] in ("단가산출", "일위대가") else "요소") # fmt: skip
if m["표지"] == "연결됨":
assert m["이음"] # 노임 · 기계 · 자재 · 비율 중 하나
if m["표지"] == "후보":
assert m["후보"] and all(c["키"] for c in m["후보"])
total[m["표지"]] += 1
n += 1
assert n == 1350 # 호표 줄 수 전후 같음
assert (total["단가산출"], total["일위대가"]) == (
735,
90,
) # 로직 줄 = 옛 갈래 단가산출 · 일위대가 그대로
assert total["연결됨"] + total["후보"] + total["못 이음"] == 525
def _hp(world, tag: str = "북부청임도") -> tuple[Path, str]:
src = golden.FILES.get(tag)
if src is None or not src.exists():
pytest.skip(f"실무 엑셀 없음 {tag}")
folder, data = world["personal"], src.read_bytes()
with store.at(folder):
parsed = hx.read_book(src.name, data)
row = hs.save(folder, src.name, parsed, {"이름": "sub1임시"}, None, hs.fingerprint(data))
fh.keep(folder, row["키"], src.name, data)
return folder, row["키"]
# ── ③ 로직 줄 = 가져온 식 SK ─────────────────────────────────────────────
def test_logic_line_is_imported_sk(world) -> None:
folder, hp = _hp(world)
with store.at(folder):
got = hv.view(folder, hp, 3) # 제3호표 — 단산 셋
logic = [m for m in got["줄"] if m["표지"] == "단가산출"]
assert len(logic) == 3 and all(m["번"] for m in logic)
made = fh.make(folder, hp, logic[0]["번"])
doc = store.read("sangeun", made["이름"])["문서"]
assert imp.is_imported(doc) and doc[imp.KEY]["단가기준"] == "엑셀" # 경쟁사 로직 그대로
assert doc.get("바탕") is None and "근거후보" not in doc[imp.KEY]
assert not list((folder / "precombo").glob("*.json")) # 보기는 일위대가를 안 씀
# ── ④ 모달 = Labor_Table ────────────────────────────────────────────────
def test_modal_is_labor_table() -> None:
view, sheet, table = _ts("Hopyo_View"), _ts("Hopyo_Sheet"), _ts("Labor_Table")
assert "mountLaborTable(host, r.문서" in view and "readOnly: true" in view
assert 'mode: "precombo"' in view and "openSkEdit(" in view and "mineButton(" in view
assert "/hopyo-view/" in view and "x_mark" in view and "x_excel" in view
assert "openHopyoView({" in sheet and "openHopyoCheck" not in sheet
assert "opt.view?.onRow?.(n)" in table and "viewRows(g)" in table # 덧칸 · 읽기만
for name in ("Hopyo_View", "Hopyo_Sheet", "Hopyo_SheetSk", "Labor_Table"):
assert len(_ts(name).splitlines()) <= 700, name
# ── ⑤ 금액 같음 ─────────────────────────────────────────────────────────
def test_view_money_equals_excel(world) -> None:
folder, hp = _hp(world)
with store.at(folder):
book = hs.read(folder, hp)
linker, bad = hfix.Linker(True), []
for h in book["호표"]:
doc = hv.of(book, int(h["번"]), linker)["문서"]
key = refs.create("precombo", {**doc, "구분": "실무자료"})["이름"]
got = hb.compare({"층": refs.here()[0], "주인": refs.here()[1], "키": key}, h)
if not got["같음"]:
bad.append((h["번"], got["엑셀"], got["우리"]))
assert not bad, bad[:5]