- 장 나눔·제원 입력 엔진과 기울기 판정 대상을 B08 로 옮김 - 창구를 /quantity/structure-sheets 로 옮기고 기초잡석 두께·지반 갈래를 함께 넘김 (옛 B07 창구는 두께를 안 넘겨 원단위 탭과 값이 갈렸음) - 구조물도 탭 조각 renderStructureSheets 신설 — 탭 등록은 브레인 몫이라 안 붙임 - B07 표준도 목록은 탭 배선 날까지 B08 엔진·창구를 불러 그대로 둠 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
96 lines
3.9 KiB
Python
96 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""표준도(구조물도) 하단표에 **칸이 서는지** — 날개벽·집수정·옹벽 (계획서 4-13).
|
|
|
|
4-13 표의 「⚠ 칸만 오면 됨」 줄을 닫는 자리다. 하단표는 B08 전개를 접기만 하므로
|
|
(`build_standard_sheets`), **관측 원단위가 들어온 종류는 저절로 선다**. 반대로 자료가
|
|
없는 규격은 줄이 0개이고 **사유만** 뜬다 — 값을 지어내지 않는 것이 확정이다(확정 5차 3번).
|
|
|
|
⚠ 이 시험은 수량값을 검산하지 않는다(그것은 `test_b08_wing_wall` · `test_b08_observed_unit`
|
|
몫이다). 여기서 보는 것은 **표준도 하단표까지 값이 실려 오는가**다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_StructureSheet import ( # noqa: E402
|
|
build_standard_sheets,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table # noqa: E402
|
|
|
|
|
|
def _sheets(structures: list[dict], names: dict[str, str]) -> dict[str, dict]:
|
|
payload = build_standard_sheets(build_table(structures, names, {}), {})
|
|
return {sheet["type_id"]: sheet for sheet in payload["sheets"]}
|
|
|
|
|
|
def _배수관(**options) -> dict:
|
|
return {
|
|
"structure_id": "p1",
|
|
"type_id": "pipe",
|
|
"name": "배수관 1",
|
|
"start_m": 60.0,
|
|
"end_m": 68.0,
|
|
"length_m": 8.0,
|
|
"options": {"pipe_diameter_mm": "800", "station": 60.0, **options},
|
|
}
|
|
|
|
|
|
def _옹벽(form: str, height_m: float) -> dict:
|
|
return {
|
|
"structure_id": "w1",
|
|
"type_id": "retaining_wall",
|
|
"name": "옹벽",
|
|
"start_m": 100.0,
|
|
"end_m": 110.0,
|
|
"length_m": 10.0,
|
|
"height_m": height_m,
|
|
"options": {"form": form, "height_m": height_m, "length_m": 10.0, "station": 100.0},
|
|
}
|
|
|
|
|
|
def test_날개벽_집수정_칸이_선다() -> None:
|
|
"""관에 형식을 채우면 **딸린 두 장**이 저절로 서고 줄마다 단위당 값이 붙는다."""
|
|
sheets = _sheets(
|
|
[
|
|
_배수관(
|
|
inlet_basin_form="돌집수정 ㄷ형",
|
|
inlet_basin_material="콘크리트",
|
|
wing_wall_type="C-TYPE",
|
|
)
|
|
],
|
|
{"pipe": "배수관"},
|
|
)
|
|
for type_id in ("pipe_inlet_basin", "pipe_wing_wall"):
|
|
sheet = sheets.get(type_id)
|
|
assert sheet is not None, f"{type_id} 장이 안 섰다"
|
|
# 개소당 — 관측 원단위가 개소 기준이라 연장으로 접지 않는다(4-1: 단위를 통일하지 않는다).
|
|
assert sheet["billing_unit"] == "개소"
|
|
assert sheet["rows"], f"{type_id} 하단표가 비었다"
|
|
# 「값이 없다」를 0 으로 때우지 않는다 — 단위당을 못 낸 줄이 있으면 이름으로 드러난다.
|
|
assert sheet["unpriced_rows"] == []
|
|
assert all(row["amount"] > 0 for row in sheet["rows"])
|
|
|
|
|
|
def test_형식을_안_고르면_장이_안_선다() -> None:
|
|
"""안 놓은 것과 같다 — 빈 장을 만들지 않는다(`ATTACHMENTS` 문턱)."""
|
|
sheets = _sheets([_배수관()], {"pipe": "배수관"})
|
|
assert "pipe_inlet_basin" not in sheets
|
|
assert "pipe_wing_wall" not in sheets
|
|
|
|
|
|
def test_옹벽은_자료가_있는_규격만_선다() -> None:
|
|
"""반중력식 H=2.0 은 소광리 「옹벽2.0」에서 왔고, 식생옹벽블럭은 **자료가 없다**."""
|
|
있음 = _sheets([_옹벽("반중력식", 2.0)], {"retaining_wall": "옹벽"})["retaining_wall"]
|
|
assert 있음["rows"], "관측 원단위가 있는데 하단표가 비었다"
|
|
assert 있음["unpriced_rows"] == []
|
|
|
|
없음 = _sheets([_옹벽("식생옹벽블럭", 2.0)], {"retaining_wall": "옹벽"})["retaining_wall"]
|
|
assert 없음["rows"] == [], "자료 없는 규격에 값이 지어졌다"
|
|
assert any("자료에 없습니다" in note for note in 없음["notes"]), 없음["notes"]
|