"""12-15 집수정 조립 — 2026-09-14 브레인 ㉯ 남은 몫 판정 ⑴~⑸. 원문 L6460 12-15 표는 조립형(구체·버림 인력 비고 칸 · 다짐기 · 거푸집 합판4회 · 철근가공조립(보통) · 뚜껑 · 설치비 5%). B08 은 집수정을 12-15 에 곧장(개소) 이어 단가가 안 섰음. ⑴ 다짐기(카탈로그 없음) 빠진 구체 갈래는 안 세움 — 인력만이면 조립 줄이 조용히 싸짐 ⑵ □형 원단위에 버림 성분 없음 → 「성분 미확보」 로 막음(0 은 지어냄) ⑶ 철근 갈래는 12-15 표 「보통」(B08 추정 「간단」 걷음 · 4회와 같은 원칙) ⑷ 뚜껑·설치비는 조각 모양이 달라 조립 밖 · 사유만 ⑸ 돌집수정은 콘크리트 집수정 표가 아니라 종전대로 목적: 금액을 못 세워도 **조용히 사라지던 것이 사유로 드러남**. """ from __future__ import annotations 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 B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff # noqa: E402 from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table # noqa: E402 CONCRETE = {"structure_id": "b1", "type_id": "pipe_inlet_basin", "start_m": 50.0, "end_m": 50.0, "options": {"inlet_basin_form": "□형(기본형)", "inlet_basin_material": "콘크리트", "pipe_diameter_mm": "800"}} # fmt: skip STONE = {"structure_id": "b2", "type_id": "pipe_inlet_basin", "start_m": 60.0, "end_m": 60.0, "options": {"inlet_basin_form": "돌집수정 ㄷ형"}} # fmt: skip def _basin(structure: dict) -> dict: unit = build_table([structure], {"pipe_inlet_basin": "집수정"}) handoff = build_handoff(unit_quantity_table=unit) return next(r for r in handoff["work_items"] if r["origin"] == "structure") def test_버림_갈래는_서고_구체_갈래는_다짐기가_풀려야_섬() -> None: """⑴ 다짐기 빠진 구체 갈래는 안 세움 — 2026-09-14 661 뒤 ① 진동기(엔진식 4611-0350)가 풀려 이제 섬.""" from B09_Estimation.B09_Estimation_UnitPrice import cached_build, detail_of build = cached_build() assert "B-FP-12-15#구체콘크리트" in build.book.titles rows = detail_of(build, "B-FP-12-15#버림콘크리트")["rows"] assert {r["ref_code"]: float(r["quantity"]) for r in rows} == {"1013": 0.15, "1002": 0.27} body = {r["ref_code"] for r in detail_of(build, "B-FP-12-15#구체콘크리트")["rows"]} assert "X-4611-0350" in body, body # 인력만으로 서지 않음(⑴ 까닭 그대로) left = " ".join(build.unattached.get("FP-12-15", [])) assert "구체콘크리트" not in left and "봉상후렉시블" not in left, left def test_콘크리트_집수정은_조립_조각으로_가고_막힌_까닭이_드러남() -> None: row = _basin(CONCRETE) assert row["work_item_code"] is None, row codes = {p["code"]: p for p in row["composite_parts"]} assert codes["FP-12-15#구체콘크리트"]["quantity"] > 0 assert codes["FP-12-04#4회"]["quantity"] > 0 assert "FP-12-03#보통" in codes, list(codes) # ⑶ 표가 적은 갈래 reasons = " ".join(str(m.get("reason")) for m in row["composite_not_ready"] or []) assert "FP-12-15#버림콘크리트" in {str(m.get("code")) for m in row["composite_not_ready"]} assert reasons, row assert "뚜껑" in row["spec_class_basis"] and "설치비" in row["spec_class_basis"] # ⑷ def test_돌집수정은_종전대로_12_15_곧장() -> None: row = _basin(STONE) assert row["work_item_code"] == "FP-12-15" and not row["composite_parts"], row def test_콘크리트_집수정_콘크리트는_타설_줄이_또_세지_않음() -> None: unit = build_table([CONCRETE], {"pipe_inlet_basin": "집수정"}) handoff = build_handoff(unit_quantity_table=unit) placing = [ r for r in handoff["work_items"] if str(r["work_item_code"] or "").startswith("FP-12-01") ] assert not placing, placing # 구체 조각이 셈 — 두 번 안 셈 def test_내역_조립_줄은_금액_없이_사유() -> None: from B09_Estimation.B09_Estimation_BillOfQuantities import build_bill unit = build_table([CONCRETE], {"pipe_inlet_basin": "집수정"}) bill = build_bill(build_handoff(unit_quantity_table=unit)) line = next(r for r in bill.rows if r.code is None and "집수정" in r.name) assert line.amount_krw is None and "묶음 조각" in line.note, line.note