· 장비 한 벌(Equipment)에 「어느 표 줄을 읽을지」 만 적고 값은 2장 표에서 읽음 — 나머지 소형 장비도 같은 길로 더함 · 체인톱 1대 1일 호표 = 휘발유 5.6ℓ(2-1-1) + 잡품 주연료비 40% + 손료 0.0084(2-2-1) × 구입가(「자재 단가」 칸 · 없으면 사유) · 쓰는 공종에 표가 이름으로 밝힌 인원 줄 수량만큼(4-2-2 「벌목부」 · 6-5 「특별인부 (체인톱 사용)」 · 넓히지 않음) · 체인오일 일반/친환경은 「자재 단가」 에 넣은 쪽 × 인원 × 2.1ℓ · 둘 다면 사유(브레인 판정 ①②③) 오른 제목: 4-2-2 +31·+41·+53원(+3.6%) · 6-5 +43,821원(+4.29%) · 나머지 그대로 · 프로젝트 내역 지장목제거 잡관목제거 +548,652(본체 109,122,948 → 109,671,600) · 잴 시험 넷 빨강→초록 · 끄기 넷 빨강 · 전체 시험 1712 + 381 통과 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
81 lines
4.0 KiB
Python
81 lines
4.0 KiB
Python
"""2장 소요재료·기계손료 표를 읽는 한 벌 — 체인톱부터(2026-09-15 브레인 ㉡ · 판정 ①②③).
|
||
|
||
산림품셈 2-1-1 체인톱 표(F0042): 보통휘발유(주연료) 5.6ℓ/대/일 · 잡품 주연료비 40% · 체인오일(일반·친환경) 2.1ℓ/대/일
|
||
「체인톱 대수는 산출된 벌목부 또는 특별인부의 100% 적용」 · 2-2-1 체인톱 손료(F0064): 45cc 0.0084(1일 1대) × 체인톱가격
|
||
체인톱을 쓰는 공종(4-2-2 단목베기 · 6-5 어린나무가꾸기)이 인력만으로 서서 연료·잡품·손료가 통째로 빠져 있었음.
|
||
③ 표가 이름으로 밝힌 인원 줄만 — 4-2-2 「벌목부」 · 6-5 「특별인부 (체인톱 사용)」
|
||
① 체인오일 일반/친환경은 「자재 단가」 에 넣은 쪽 · 둘 다면 안 붙고 사유
|
||
② 체인톱가격·체인오일 시중가격은 칸 + 사유 · 휘발유는 유가 판으로 바로 섬
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from decimal import ROUND_FLOOR, Decimal
|
||
|
||
from B09_Estimation.B09_Estimation_UnitPrice import cached_build
|
||
|
||
SAW = "X-AR-X-61d1681d"
|
||
SAW_PRICE = "AR-M-5649cf3f"
|
||
OIL = "AR-M-fa7fbf6d"
|
||
ECO_OIL = "AR-M-de2fe662"
|
||
|
||
|
||
def _rows(book, code: str) -> list:
|
||
own = book.details.get(code) or []
|
||
return [
|
||
*own,
|
||
*(r for d in own if d.ref_code.startswith("D-") for r in book.details[d.ref_code]),
|
||
]
|
||
|
||
|
||
def test_체인톱_1대_1일_호표는_표의_휘발유와_잡품_40퍼센트() -> None:
|
||
book = cached_build().book
|
||
rows = book.details[SAW]
|
||
fuel = next(r for r in rows if r.ref_code == "M-FUEL-휘발유")
|
||
assert fuel.quantity == Decimal("5.6"), fuel
|
||
misc = next(r for r in rows if r.percent_of_material is not None)
|
||
assert misc.percent_of_material == Decimal(40)
|
||
price = book.titles["M-FUEL-휘발유"].slots[-1]
|
||
expected = (Decimal("5.6") * price * Decimal("1.4")).quantize(Decimal(1), rounding=ROUND_FLOOR)
|
||
assert abs(book.resolve(SAW).material - expected) <= 1, (book.resolve(SAW), expected)
|
||
|
||
|
||
def test_단목베기는_벌목부_인원만큼_체인톱_어린나무가꾸기는_체인톱_사용_특별인부만큼() -> None:
|
||
book = cached_build().book
|
||
rows = _rows(book, "B-FP-04-02-02#5m미만")
|
||
faller = next(r for r in rows if book.titles[r.ref_code].name == "벌목부")
|
||
saw = next(r for r in rows if r.ref_code == SAW)
|
||
assert saw.quantity == faller.quantity, (saw, faller)
|
||
rows = _rows(book, "B-FP-06-05")
|
||
special = next(
|
||
r
|
||
for r in rows
|
||
if book.titles.get(r.ref_code) and book.titles[r.ref_code].name == "특별인부"
|
||
)
|
||
saw = next(r for r in rows if r.ref_code == SAW)
|
||
assert saw.quantity == special.quantity, (saw, special)
|
||
# 보통인부(작업 보조)는 체인톱을 안 씀 — 표가 이름으로 밝힌 줄만(③)
|
||
assert sum(1 for r in rows if r.ref_code == SAW) == 1
|
||
|
||
|
||
def test_체인오일은_넣은_쪽만_둘_다면_사유() -> None:
|
||
none = cached_build()
|
||
assert any("체인오일" in label for label in none.unattached.get("FP-04-02-02", []))
|
||
one = cached_build(material_prices=((OIL, "2250", "시중"),))
|
||
rows = _rows(one.book, "B-FP-04-02-02#5m미만")
|
||
faller = next(r for r in rows if one.book.titles[r.ref_code].name == "벌목부")
|
||
oil = next(r for r in rows if r.ref_code == OIL)
|
||
assert oil.quantity == faller.quantity * Decimal("2.1"), oil
|
||
both = cached_build(material_prices=((OIL, "2250", "시중"), (ECO_OIL, "6000", "시중")))
|
||
assert not any(r.ref_code in (OIL, ECO_OIL) for r in _rows(both.book, "B-FP-04-02-02#5m미만"))
|
||
assert any("둘 다" in label for label in both.unattached.get("FP-04-02-02", []))
|
||
|
||
|
||
def test_체인톱가격이_들면_손료_0_0084_가_경비로() -> None:
|
||
none = cached_build()
|
||
assert any("체인톱가격" in label for label in none.unattached.get("FP-06-05", []))
|
||
priced = cached_build(material_prices=((SAW_PRICE, "900000", "견적"),))
|
||
assert priced.book.resolve(SAW).expense == Decimal(7560) # 900,000 × 0.0084
|
||
for code in (SAW_PRICE, OIL, ECO_OIL):
|
||
assert "FP-04-02-02" in none.material_uses.get(code, []), code
|