Files
Aislo/resources/tester/test_b08_tree_waste.py
T
eomsangdonandClaude Opus 5 7d856f37a3 feat(b08,b09): 폐기물처리비 — 경비 비목(일반관리비·이윤 밑수) · 임목폐기물 톤 · 분리발주 칸
- 원가계산서: 폐기물처리비를 경비 줄로(예정가격작성기준 제19조③18호) · 법정경비 뒤라 그 밑수엔 안 섞임
- 분리발주 칸(기본 아님) — 켜면 총원가 밖 · 총공사비에만 더함
- 준비공 「임목폐기물 처리」 톤: WA = 0.5·π·(B/2)²·h·1.3·W1·N · WR = WA × 15/85 (한국건설기술연구원 2012)
- 조사값 넷(1,000㎡당 본수·흉고직경·수고·단위체적중량) 칸 · 기본값 없음 · 5톤·100톤 경계 알림
- 수동 처리단가 빨간 테두리 + 「미확정 N건」 · 내역엔 안 서고 제외 사유 「경비」
- 시험: 승률 구조(경비·일반관리비·이윤 밑수 증가 · 법정경비 불변 · 분리발주) · 실정보고 부피 대조

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
2026-09-14 00:55:41 +09:00

67 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""임목폐기물 처리 — 톤으로 서는가 · 경비라 내역에 안 서는가 (2026-09-14 판정).
⚠ 산식 — 한국건설기술연구원(2012) 3.2: WA = 0.5 × π × (B/2)² × h × 1.3 × W1 × N · WR = WA × 15/85.
⚠ 실정보고 예(p26) 「V1 = 0.5×π×(0.16/2)²×10.0×1.3×134/1000×7,450 = 130.40㎥」 로
지상부 부피를 대 봄.
"""
from __future__ import annotations
import math
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from B08_Quantity.B08_Quantity_Engine_Preparation_TreeWaste import ( # noqa: E402
tree_waste_rows,
tree_waste_tons,
)
SLOPE = {"tree_removal_fill": 4000.0, "tree_removal_cut": 3450.0} # 7,450㎡
FIELD = {"stems_per_1000m2": 134, "dbh_cm": 16, "height_m": 10.0, "unit_weight_kg_m3": 1000}
def test_지상부는_실정보고_부피와_같다() -> None:
"""W1 = 1,000㎏/㎥ 로 두면 지상부 톤 = 지상부 부피(㎥) — 실정보고 130.40㎥."""
above, root = tree_waste_tons(7450.0, FIELD)
# 실정보고는 π 를 3.14 로 셈 — 같은 π 로 되돌리면 130.40 과 같다.
assert above * 3.14 / math.pi == pytest.approx(130.40, abs=0.01)
assert root == pytest.approx(above * 15 / 85)
def test_칸이_비면_톤이_안_서고_무엇이_빈지_적는다() -> None:
row = tree_waste_rows(SLOPE, {**FIELD, "height_m": None})[0]
assert row["amount"] is None and "평균 수고" in row["reason"]
assert row["reference_amount"] == 7450.0
def test_단가가_없으면_금액이_안_서고_있으면_미확정() -> None:
no_price = tree_waste_rows(SLOPE, FIELD)[0]
assert no_price["unit"] == "톤" and no_price["amount"] > 0
assert no_price["amount_krw"] is None and no_price["unconfirmed"] == 0
priced = tree_waste_rows(SLOPE, FIELD, 60000)[0]
assert priced["unconfirmed"] == 1
assert priced["amount_krw"] == int(priced["amount"] * 60000)
def test_톤_경계를_알린다() -> None:
big = tree_waste_rows(SLOPE, FIELD)[0] # 약 153톤
assert big["amount"] >= 100 and "100톤 이상" in big["reason"]
small = tree_waste_rows({"tree_removal_fill": 500.0}, FIELD)[0] # 약 10톤
assert 5 <= small["amount"] < 100 and "5톤 이상" in small["reason"]
def test_경비라_내역에_안_서고_제외_사유가_간다() -> None:
from B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff
from B08_Quantity.B08_Quantity_Engine_Preparation import build_table
table = build_table(SLOPE, tree_waste=FIELD, tree_waste_unit_price_krw_per_ton=60000)
handed = {r["name"]: r for r in build_handoff(preparation_table=table)["work_items"]}
row = handed["임목폐기물 처리"]
assert row["in_bill"] is False and row["blocked_kind"] is None
assert "경비" in row["in_bill_reason"]