B08_Quantity 86 · B09_Estimation 111 파일을 old_code/ 로 옮김(지우지 않음). 화면은 메뉴·주소·단계 막대만 남은 빈 틀 둘 — main.py 라우터 13 개는 끊음. B07 이 빌려 쓰던 비탈 길이·면적은 필요한 함수만 B07_DesignDetail_Engine_SlopeGeometry 로 옮겨 적음(면적 적분·노면 면적·측점 묶음은 안 옮김) · 시험 하나를 새로 둠. B07 구조물도 조립(Cad_StandardSheet)은 2026-09-13 에 이미 도면 목록에서 빠져 부르는 곳이 없어 old_code 로 같이 보냄 — 구조물 그림은 되살리지 않음. B06 구조물 몫 조회는 빈 값으로 두어 화면이 그대로 서게 함. B08·B09 를 부르던 시험 25 개도 old_code/resources/tester 로 옮김. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
129 lines
4.9 KiB
Python
129 lines
4.9 KiB
Python
"""운반 물량의 **상태** — 내역서 수량은 자연상태다 (2026-09-09).
|
|
|
|
「운반거리의 산정 시에 모든 수량은 다짐상태로 환산하여 계산하고, 내역서에 적용하는
|
|
수량은 자연상태로 한다」(설계실무 요령 — `config_system_design` 5-4-3 인용문).
|
|
|
|
⚠ 이 시험이 잠그는 것은 **방향**이다. 곱하면 토사가 0.9배가 되어 뒤집힌다.
|
|
⚠ `L`(1.3·1.35·1.625)을 쓰지 않는다는 것도 함께 잠근다 — 품셈이 `f = 1/L` 을 스스로 곱한다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
if str(PROJECT_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_EarthworkSummary import ( # noqa: E402
|
|
SummaryInput,
|
|
build_table as build_summary,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Engine_HaulSummary import ( # noqa: E402
|
|
build_table,
|
|
natural_m3,
|
|
summary_input_rows,
|
|
)
|
|
from config.config_system_design import EARTHWORK_CONVERSION_FACTORS # noqa: E402
|
|
|
|
_PLAN = {
|
|
"blocks": [
|
|
{
|
|
"bands": [
|
|
{
|
|
"equipment": "dozer",
|
|
"haul_distance_m": 40.0,
|
|
"haul_from_m": 0.0,
|
|
"haul_to_m": 40.0,
|
|
"ea_m3": 90.0,
|
|
"rr_m3": 115.0,
|
|
"br_m3": 0.0,
|
|
},
|
|
{
|
|
"equipment": "dump_truck",
|
|
"haul_distance_m": 300.0,
|
|
"haul_from_m": 0.0,
|
|
"haul_to_m": 300.0,
|
|
"ea_m3": 0.0,
|
|
"rr_m3": 0.0,
|
|
"br_m3": 130.0,
|
|
},
|
|
]
|
|
}
|
|
],
|
|
"transfers": [],
|
|
}
|
|
|
|
|
|
def _row(table: dict, equipment: str, ground: str) -> dict:
|
|
return next(
|
|
row for row in table["rows"] if row["equipment"] == equipment and row["ground"] == ground
|
|
)
|
|
|
|
|
|
def test_나누기다_곱하기가_아니다() -> None:
|
|
for ground, kind in (("토사", "soil"), ("리핑암", "ripping_rock"), ("발파암", "blasting_rock")):
|
|
factor = EARTHWORK_CONVERSION_FACTORS[kind]["compacted"]
|
|
assert natural_m3(100.0, ground) == pytest.approx(100.0 / factor)
|
|
# 방향이 뒤집히면 이 줄이 잡는다.
|
|
assert natural_m3(100.0, ground) != pytest.approx(100.0 * factor)
|
|
# 토사는 늘고(÷0.9) 암은 준다(÷1.15·÷1.30) — 부호가 갈래마다 다르다.
|
|
assert natural_m3(100.0, "토사") > 100.0
|
|
assert natural_m3(100.0, "리핑암") < 100.0
|
|
assert natural_m3(100.0, "발파암") < 100.0
|
|
|
|
|
|
def test_L_은_쓰지_않는다() -> None:
|
|
"""품셈 10-11·10-12 가 `f = 1/L` 을 스스로 곱하므로 우리가 또 들면 두 번 환산이다."""
|
|
for ground, loose in (("토사", 1.3), ("리핑암", 1.35), ("발파암", 1.625)):
|
|
assert natural_m3(100.0, ground) != pytest.approx(100.0 / loose)
|
|
|
|
|
|
def test_갈래를_모르면_환산하지_않는다() -> None:
|
|
assert natural_m3(100.0, "지반모름") is None
|
|
assert natural_m3(100.0, "") is None
|
|
|
|
|
|
def test_네_줄이_두_상태를_함께_낸다() -> None:
|
|
table = build_table(_PLAN)
|
|
dozer_soil = _row(table, "dozer", "토사")
|
|
assert dozer_soil["volume_m3"] == pytest.approx(90.0)
|
|
assert dozer_soil["volume_basis"] == "compacted"
|
|
assert dozer_soil["natural_m3"] == pytest.approx(100.0) # 90 ÷ 0.90
|
|
assert dozer_soil["conversion_c"] == pytest.approx(0.90)
|
|
assert _row(table, "dozer", "리핑암")["natural_m3"] == pytest.approx(100.0) # 115 ÷ 1.15
|
|
assert _row(table, "dump_truck", "발파암")["natural_m3"] == pytest.approx(100.0) # 130 ÷ 1.30
|
|
# 거리는 다짐 기준 그대로 — 환산이 거리를 건드리면 안 된다.
|
|
assert dozer_soil["average_distance_m"] == pytest.approx(40.0)
|
|
|
|
|
|
def test_집계표는_자연상태로_싣는다() -> None:
|
|
haul = build_table(_PLAN)
|
|
summary = build_summary(
|
|
SummaryInput(
|
|
earthwork_totals={},
|
|
slope_totals={},
|
|
haul_rows=summary_input_rows(haul),
|
|
rock_classes=[],
|
|
rock_ratios_pct={},
|
|
application_ratios={},
|
|
)
|
|
)
|
|
rows = [row for row in summary["rows"] if row["group"] in ("도자운반", "덤프운반")]
|
|
assert rows, "운반 줄이 서야 한다"
|
|
for row in rows:
|
|
assert row["amount"] == pytest.approx(100.0), row
|
|
assert "자연상태 환산" in row["note"]
|
|
|
|
|
|
def test_검산은_다짐상태끼리_한다() -> None:
|
|
"""환산값으로 검산하면 늘 어긋난다 — 계획이 다짐이기 때문이다."""
|
|
from B08_Quantity.B08_Quantity_Engine_HaulSummary import check_against_plan
|
|
|
|
plan = dict(_PLAN, hauled_m3=335.0, transferred_m3=0.0)
|
|
check = check_against_plan(build_table(plan), plan)
|
|
assert check.difference_m3 == pytest.approx(0.0)
|