"""치즐 소모량(Ⓐ-3 · 2026-09-14 브레인 판정) — **칸을 채우면 치즐 공종 상태가 움직이는가**로 잼. 「칸이 섰다」가 아니라 「칸을 채우면 못 붙은 줄이 풀린다」가 판정(81공종 다시 셈에서 칸을 다 채워도 상태가 안 움직였던 까닭이 치즐 15공종). 단가는 없음 — 시험의 223,000 원은 실무 원본(영월 M00118) 대조용 값이고 프로그램에 넣지 않음. 근거 — 실무 원본 단가산출근거 「(2) 치즐 손료 · M=0.006 × 223,000 / Q = 382.2 W/㎥」(재료비) · 품셈 제8장 [주]⑤ 「브레이커 … 손료 및 치즐 소모율을 **추가**」(기계 손료에 안 듦 → 이중계상 아님). """ from __future__ import annotations from decimal import Decimal from B09_Estimation.B09_Estimation_Chisel import CHISEL_CODE from B09_Estimation.B09_Estimation_UnitPrice import cached_build #: 기본 조립에서 「치즐소모량」 이 못 붙은 줄로 남던 15공종. CHISEL_ITEMS = ( "FP-09-04-01", "FP-09-05-02", "FP-09-12-02", "FP-09-12-03", *(f"FP-09-13-{n:02d}" for n in range(7, 19)), ) PRICE = (CHISEL_CODE, "223000", "시험") def _chisel_labels(build, code: str) -> list[str]: return [label for label in build.unattached.get(code, []) if "치즐" in label] def test_칸을_안_채우면_종전대로_못_붙은_줄() -> None: base = cached_build() assert CHISEL_CODE not in base.book.titles assert all(_chisel_labels(base, code) for code in CHISEL_ITEMS) # 「자재 단가」 탭에 칸이 서는 자리 — 치즐을 쓰는 16공종이 다 실림(암질 표 둘 포함) assert set(CHISEL_ITEMS) <= set(base.material_uses[CHISEL_CODE]) def test_칸을_채우면_치즐_못_붙은_줄이_풀린다() -> None: filled = cached_build(material_prices=(PRICE,)) left = {code: _chisel_labels(filled, code) for code in CHISEL_ITEMS} # 9-4-1 평균 갈래만 남음 — 원문 [주]① 은 Q 평균만 정하고 치즐 평균은 안 줌(지어내지 않음) assert {code: labels for code, labels in left.items() if labels} == { "FP-09-04-01": [left["FP-09-04-01"][0]] } assert "평균" in left["FP-09-04-01"][0] whole = [code for code in CHISEL_ITEMS if not filled.unattached.get(code)] assert len(whole) >= 12, ( whole ) # 못 붙은 줄이 아예 없어진 공종(9-13-14·15 는 들어내기 줄이 남음) def test_치즐은_시간당_소모량_나누기_Q_로_재료비에_붙음() -> None: base = cached_build() filled = cached_build(material_prices=(PRICE,)) # 9-4-1 연암 — 0.006 본/hr ÷ Q 5.0 × 223,000 = 267.6 원/㎥ (배분율 없음) gap = ( filled.book.resolve("B-FP-09-04-01#연암").material - base.book.resolve("B-FP-09-04-01#연암").material ) # 줄 0.1원·소계 원 미만 절사가 기존 재료비 끝전과 겹쳐 267 또는 268 assert Decimal("267") <= gap <= Decimal("268") rock = next(d for d in filled.book.details["D-FP-09-04-01#연암"] if d.ref_code == CHISEL_CODE) assert rock.quantity == Decimal("0.006") / Decimal("5.0") and rock.output == Decimal("5.0") # 9-12-2 암절취 — 장비(90%) 몫 · 0.006 ÷ 3.5 × 0.9 × 223,000 = 344.05 detail = next(d for d in filled.book.details["D-FP-09-12-02"] if d.ref_code == CHISEL_CODE) assert detail.quantity == Decimal("0.006") / Decimal("3.5") * Decimal("0.9") assert detail.output == Decimal("3.5") def test_치즐은_기계_손료와_겹치지_않음() -> None: """㉠ 브레이커 시간당 사용료는 손료만(부착 장비) — 치즐이 X 층 안에 없음.""" filled = cached_build(material_prices=(PRICE,)) breaker = next(code for code in filled.book.titles if code.startswith("X-0230-")) stack, seen = [breaker], set() while stack: code = stack.pop() assert code != CHISEL_CODE if code in seen: continue seen.add(code) stack.extend(d.ref_code for d in filled.book.details.get(code, []) if d.ref_code != code)