Files
Aislo/resources/tester/test_809_1_import_labor.py
T
eomsangdonandClaude Opus 5.5 ae8d098a10 fix(815-3): 합친 뒤 시험 셋 가름 · 시간당 경비 식 조종원 차례 · 호표 기계 글 머리 꼬리 · 합친 판 요약 다시 잼
- 809_1 이름 = 진짜 흠 + 낡은 기대 — 읽기기(812-1)가 지은 율 줄 이름 「율」이 엑셀 글 머리로 안 바뀜 → `Import_Shape._MADE` 에 율 더함 · 합계 = 차림 글줄 · 기계 = 한 줄(이름 · 규격 칸) 은 낡은 기대 고침 · 금액 15,935 · 336 · 723 · 16,994 그대로
- 812_9 별칭 = 낡은 기대 — 815-2 가 아스팔트페이버 별칭을 마스터 기계 줄 칸으로 옮겨 「넣기 전 못 찾음」 이 안 맞음 · 시험은 마스터 칸으로 봄 · 부르는 곳 없는 `M02_Machine_Find.learn`(옛 장부 쓰기) · `by_code` · `same_kind`(걷은 연결 찾기 몫) 지움
- 804_2 hourly = 낡은 기대 — 814-1 이 GC000268 목록을 117 → 209 로 늘려 겹친 116 대 고름이 GC000269 로 뒤집힘(116 대 모두 원 단위 같음) · 같은 로직 줄만 대던 시험 → 같은 갈래 식(부착 · 손료만 · 조종원) 줄 모두 댐
- 진짜 흠(브레인 갈래 가) — GC000272 「조종원 없는 기종」 목록에 기계표 조종원 1 인 9 대가 겹쳐 목록 길이 차례로 고름 → `logic_of` = 기계표 조종원 > 0 이면 조종원 호표 든 식 먼저 · 불러오기 `hourly_link` 도 같은 길 · 바뀐 4 대 = 진동롤러(핸드가이드식) 0.7ton 6,557 → 41,969 · 래머 80kg 1,959 → 23,708 · 플레이트 콤팩터 1.5ton 2,855 → 24,604 · 발전기 100kW 45,535 → 67,284(M01 문서 금액 그대로) · 시험에 9 대 굳힘
- 778_5 기계 표 = 진짜 흠 — 812-9 찾기가 호표 기계 글 「운 반 : 덤프트럭(4.5Ton)」 · 「…[hr] : 90%」 · 「(90%)」 머리 꼬리를 안 뗌 → `Hopyo_Fixed._eqs` 쌍점 조각 · 율 꼬리 뗌 · 이어짐 187 · 고를 것 1 · 못 이음 2(조합 한 줄 · 괄호 깨짐) · 모두 이음 블록 161
- 721 단추 자리 = 낡은 기대(808-1 [단가 갱신][재생성] tools 더함)
- 815-1 보고 요약에 「합친 뒤」 열 — 기계 이음 95.7 % · 우리 값 원파일 1,891 · 0 원 줄 블록 147

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 16:32:28 +09:00

163 lines
9.3 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]
# ── ⑥ 가져온 식 표시(요구 704) — 지은 이름 → 엑셀 글 머리 · EST 기계 세 줄 = 한 줄 · 금액 그대로 ─────
def test_imported_doc_names_and_machine_line(world) -> None:
from M02_MasterTemplete import M02_Doc_Import as dim
from M02_MasterTemplete import M02_Doc_Import_Shape as shp
folder, hp = _hp(world)
out = fh.emit(
folder, hp, 8
) # 배수관부설(파형강관)(D=800mm) — 크레인 세 줄 · 줄_2 · 노무비_2 · 계_2
unit = out["로직"]["결과단위"].split("/", 1)[1]
sk = {"키": "SK-000000", "이름": "x", "단위": unit, "바탕": None, "입력값": {}}
sk[imp.KEY] = {"로직": out["로직"], "단가기준": "엑셀", "원본": out["원본"]}
new = dim.derive(sk)
names = [x["이름"] for x in new["금액"]]
assert "공구손료 및 잡재료비(노무비의 2%)" in names # 읽기기 지은 「율」 → 엑셀 글 머리
assert not any(shp._MADE.match(n) for n in names) # 줄_2 · 율 · 노무비_2 · 계_2 없음
# 812-1 읽기기 — 합계 = 차림 글줄(금액 줄 아님) · 기계 = 한 줄(이름 · 규격 칸 따로)
assert "노무비 합계" not in names and "계" not in names
crane = [x for x in new["금액"] if x.get("비목") == "묶음"]
assert [(x["이름"], x.get("규격")) for x in crane] == [("트럭탑재형크레인", "5Ton")]
got = dim.run(new, sk)
assert (got["노무비"], got["재료비"], got["경비"], got["계"]) == (15935, 336, 723, 16994)