Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
76 lines
3.5 KiB
Python
76 lines
3.5 KiB
Python
"""B09 원가계산 — **치즐 소모량**(대형브레이커 깨기 · PLAN 1장 Ⓐ-3 · 2026-09-14 브레인 판정).
|
||
|
||
품셈 표가 브레이커 줄 옆에 「치즐소모량(본/hr)」을 줌 — 제8장 [주]⑤ 「브레이커 … 손료 및 치즐
|
||
소모율을 **추가**」. 실무 원본(영월·봉화·울진) 단가산출근거 「(2) 치즐 손료 · M=0.006 × 223,000 / Q
|
||
= 382.2 W/㎥」 — 재료비(재료비 집계표 M00118 치즐(대형 브레이카) 본).
|
||
|
||
수량 치즐(본/hr) ÷ Q × 장비 배분율 — 브레이커 줄과 같은 D(단가산출)에 나란히(Q 를 함께 실음)
|
||
단가 자원 목록 `AR-M` 치즐 — **수동 단가가 들어와야** 제목이 섬(임의 단가 없음) ·
|
||
안 들어오면 종전대로 「못 붙은 줄」
|
||
⚠ 기계 층(`X-0230` 대형브레이커)은 부착 장비라 손료만 — 치즐은 그 안에 없어 이중계상 아님(시험).
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from decimal import Decimal
|
||
from typing import Any
|
||
|
||
#: 자원 목록 치즐(대형브레이커용 · 본) — `resource_catalog_ext` 에 올린 코드.
|
||
CHISEL_CODE = "AR-M-a2926452"
|
||
#: 치즐을 붙이는 기계 — 대형브레이커(분류 0230).
|
||
BREAKER_PREFIX = "0230-"
|
||
CHISEL_MISSING = "치즐소모량(본/hr) — 치즐 단가 없음(「자재 단가」 탭에서 넣으면 붙음)"
|
||
#: ⚠ 선례를 함께 적음(2026-09-14 브레인 판정) — 사용자가 「같은 방식으로 유추할지」를 스스로 고르게.
|
||
CHISEL_AVERAGE_NOT_GIVEN = (
|
||
"치즐(평균 갈래) — 원문 9-4-1 [주]① 은 Q 평균만 정하고 치즐 평균은 안 줌(지어내지 않음)"
|
||
" · 참고 선례: 9-12-3 발파암 표는 같은 자리에서 치즐 평균"
|
||
" 「(0.006+0.02+0.03)/3 = 0.018」 을 스스로 적음 — 같은 방식으로 볼지는 판정 대기"
|
||
)
|
||
|
||
|
||
def chisel_per_hour(node: dict[str, Any]) -> Decimal | None:
|
||
"""표의 「치즐소모(량)(본/hr)」 줄 값 — 그 이름 칸 뒤 첫 수. 없으면 `None`."""
|
||
from B09_Estimation.B09_Estimation_MachineProductivity import parse_measure
|
||
|
||
for table in node.get("tables", []):
|
||
for row in table.get("raw_row") or []:
|
||
cells = ["".join(str(cell).split()) for cell in row]
|
||
for index, cell in enumerate(cells):
|
||
if not cell.startswith("치즐소모"):
|
||
continue
|
||
value = next(
|
||
(parse_measure(t) for t in cells[index + 1 :] if parse_measure(t)), None
|
||
)
|
||
if value:
|
||
return value
|
||
return None
|
||
|
||
|
||
def attach_chisel(
|
||
book: Any,
|
||
title_code: str,
|
||
per_hour: Decimal | None,
|
||
capacity: Decimal,
|
||
share: Decimal = Decimal(1),
|
||
) -> bool:
|
||
"""치즐 줄을 그 제목의 D 에 붙임 — 치즐 제목(수동 단가)이 없거나 소모량이 없으면 `False`."""
|
||
if not per_hour or CHISEL_CODE not in book.titles:
|
||
return False
|
||
book.add_output_detail(
|
||
title_code,
|
||
CHISEL_CODE,
|
||
per_hour / capacity * share,
|
||
note=(
|
||
f"치즐 {per_hour} 본/hr ÷ Q {capacity}"
|
||
+ (f" × 배분 {share}" if share != 1 else "")
|
||
+ " — 품셈 제8장 [주]⑤ 치즐 소모율 추가"
|
||
),
|
||
output=capacity,
|
||
)
|
||
return True
|
||
|
||
|
||
def without_chisel_labels(labels: list[str]) -> list[str]:
|
||
"""치즐이 붙은 뒤 「못 붙은 줄」 에서 치즐 글을 걷음."""
|
||
return [label for label in labels if "치즐" not in label]
|