Merge remote-tracking branch 'origin/main_laptop_1' into main_desktop_1
This commit is contained in:
@@ -39,6 +39,16 @@
|
||||
"default": "기슭막이",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "wing_wall_type",
|
||||
"label": "관보호공 날개벽",
|
||||
"input": "select",
|
||||
"choices": ["A-TYPE", "C-TYPE", "A-TYPE+집수정"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail",
|
||||
"empty_means": "비우면 날개벽을 안 셈 — 고르면 그 형식의 개소당 원단위로 한 줄이 섬(Ø800·Ø1000 만 있음)"
|
||||
},
|
||||
{
|
||||
"key": "inlet_basin_form",
|
||||
"label": "집수정 형식",
|
||||
|
||||
@@ -220,7 +220,11 @@ export function createFacilityOptionsForm(
|
||||
...["800", "1000", "1200", "1500"].map((size) => new Option(`Ø${size}`, size)),
|
||||
);
|
||||
pipeDiameter.value = "1000"; // 별표2 원칙값 + 사용자 확정 기본 (2026-08-17)
|
||||
// 관보호공 날개벽 — **개소당 원단위**가 형식마다 붙박이라 고르는 칸이 있어야 물량이 선다
|
||||
// (2026-09-09, 계획서 4-13 · 소광리 원본 탭 다섯). 비우면 날개벽을 안 센다.
|
||||
const wingWall = optionalSelect("안 놓음", ["A-TYPE", "C-TYPE", "A-TYPE+집수정"]);
|
||||
const pipeRow = grid(labeled("관종", pipeMaterial), labeled("관경", pipeDiameter));
|
||||
const wingRow = grid(labeled("관보호공 날개벽", wingWall));
|
||||
|
||||
// ── 유입구 — 집수정 또는 기슭막이 택일(사용자 지시 5~9) ─────────────────
|
||||
const inletGroup = group("유입구");
|
||||
@@ -441,6 +445,7 @@ export function createFacilityOptionsForm(
|
||||
// 월류 폭·높이 → 바닥 경사 → 수량 → 개략 단면 결과. 다른 시설에서는 전부 숨는다.
|
||||
root.append(
|
||||
pipeRow,
|
||||
wingRow,
|
||||
fordWidthRow,
|
||||
fordSlopeRow,
|
||||
fordRow,
|
||||
@@ -465,6 +470,8 @@ export function createFacilityOptionsForm(
|
||||
const isBox = current === "box_culvert";
|
||||
// 관종·관경은 배수관과 세월교가 공유한다.
|
||||
pipeRow.hidden = !isPipe && current !== "ford_bridge";
|
||||
// 관보호공 날개벽 원단위는 **배수관 Ø800·Ø1000** 것뿐이다 — 다른 시설에서는 숨긴다.
|
||||
wingRow.hidden = !isPipe;
|
||||
inletGroup.root.hidden = !isPipe;
|
||||
outletGroup.root.hidden = !isPipe;
|
||||
boxWrap.hidden = !isBox;
|
||||
@@ -520,7 +527,7 @@ export function createFacilityOptionsForm(
|
||||
callbacks.onChange?.();
|
||||
}
|
||||
|
||||
[inletType, outletType, basinForm, basinMaterial, basinLength].forEach((input) =>
|
||||
[inletType, outletType, wingWall, basinForm, basinMaterial, basinLength].forEach((input) =>
|
||||
input.addEventListener("change", emit),
|
||||
);
|
||||
inletRevet.onChange(emit);
|
||||
@@ -594,6 +601,7 @@ export function createFacilityOptionsForm(
|
||||
) ?? inletKindOf(savedType)
|
||||
).label;
|
||||
outletType.value = text("outlet_type") || "기슭막이";
|
||||
wingWall.value = text("wing_wall_type");
|
||||
basinForm.value = text("inlet_basin_form");
|
||||
basinMaterial.value = text("inlet_basin_material");
|
||||
basinLength.value = text("inlet_basin_length_m") || "2";
|
||||
@@ -648,6 +656,7 @@ export function createFacilityOptionsForm(
|
||||
options.pipe_diameter_mm = Number(pipeDiameter.value);
|
||||
options.pipe_kind = pipeMaterial.value;
|
||||
const inletKind = inletKindOf(inletType.value);
|
||||
if (wingWall.value) options.wing_wall_type = wingWall.value;
|
||||
options.inlet_type = inletKind.type;
|
||||
// B06 유입측 형식(조정창과 같은 값) — 병합 드롭다운이 함께 정한다(2026-08-29).
|
||||
options.inlet_structure = inletKind.structure;
|
||||
|
||||
@@ -1141,6 +1141,9 @@ OBSERVED_SPEC_KEYS: dict[str, tuple[str, ...]] = {
|
||||
"ford_pavement": ("thickness_cm",),
|
||||
# 배수관의 유입부 집수정은 관 자체와 **다른 줄**이다 — 관은 관대로 서고 집수정이 따로 선다.
|
||||
"pipe_inlet_basin": ("inlet_basin_form", "inlet_basin_material", "pipe_diameter_mm"),
|
||||
# 관보호공 날개벽 — **개소당**이고 치수가 형식마다 붙박이다(원본 탭 다섯). 형식을 고르지
|
||||
# 않으면 날개벽 줄 자체가 안 선다(안 놓은 것과 같다).
|
||||
"pipe_wing_wall": ("wing_wall_type", "pipe_diameter_mm"),
|
||||
}
|
||||
|
||||
EXPANDERS = {
|
||||
@@ -1216,9 +1219,27 @@ EXPANDER_WITHHELD: dict[str, str] = {}
|
||||
#: (품셈도 관부설과 집수정을 다른 공종으로 둔다). 한 줄로 합치면 어느 쪽 물량인지 못 가른다.
|
||||
ATTACHMENTS: dict[str, tuple[tuple[str, str, str], ...]] = {
|
||||
# (붙는 종류, 그것이 있는지 보는 옵션 칸, 줄 이름 꼬리)
|
||||
"pipe": (("pipe_inlet_basin", "inlet_basin_form", "유입부 집수정"),),
|
||||
"pipe": (
|
||||
("pipe_inlet_basin", "inlet_basin_form", "유입부 집수정"),
|
||||
("pipe_wing_wall", "wing_wall_type", "관보호공 날개벽"),
|
||||
),
|
||||
}
|
||||
|
||||
#: 날개벽 「A-TYPE+집수정」은 집수정을 **품은** 형식이다 — 집수정 줄을 따로 세우면 한 개소를
|
||||
#: 두 번 센다(원단위표 `double_count_rules` 와 짝).
|
||||
WING_WALL_WITH_BASIN = "A-TYPE+집수정"
|
||||
WING_WALL_DOUBLE_COUNT = (
|
||||
"⚠ 날개벽을 「A-TYPE+집수정」으로 골랐는데 집수정 형식도 차 있음 — "
|
||||
"그 날개벽 값이 집수정을 이미 품고 있어 **두 번 셀 수 있음**. 한쪽을 비울 것"
|
||||
)
|
||||
|
||||
|
||||
def wing_wall_double_count(options: dict[str, Any]) -> str | None:
|
||||
"""겹쳐 세는 자리면 사유 한 줄. 값을 고치지 않고 **드러내기만** 한다."""
|
||||
if str(options.get("wing_wall_type") or "") != WING_WALL_WITH_BASIN:
|
||||
return None
|
||||
return WING_WALL_DOUBLE_COUNT if options.get("inlet_basin_form") else None
|
||||
|
||||
|
||||
def attachments_of(structure: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""구조물에 딸린 **별도 줄**을 만든다. 제원은 원본을 그대로 물려준다(치수 두 벌 금지)."""
|
||||
@@ -1255,7 +1276,11 @@ def _observed_components(
|
||||
from B08_Quantity.B08_Quantity_Wording import option_missing
|
||||
|
||||
return [], [option_missing(keys[0], type_id)]
|
||||
return expand_observed(type_id, spec, structure, observed)
|
||||
components, notes = expand_observed(type_id, spec, structure, observed)
|
||||
warning = wing_wall_double_count(options)
|
||||
if warning:
|
||||
notes.append(warning)
|
||||
return components, notes
|
||||
|
||||
|
||||
def _observed_billing(
|
||||
|
||||
@@ -256,6 +256,266 @@
|
||||
"destination": "earthwork"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type_id": "pipe_wing_wall",
|
||||
"spec": {
|
||||
"wing_wall_type": "A-TYPE",
|
||||
"pipe_diameter_mm": "800"
|
||||
},
|
||||
"unit": "개소",
|
||||
"source": "uljin_library",
|
||||
"source_note": "§1 관보호공 날개벽 — 원본 탭 「날개벽(800)A-TYPE산출근거」",
|
||||
"components": [
|
||||
{
|
||||
"name": "기초잡석",
|
||||
"unit": "㎥",
|
||||
"amount": 1.152,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "T=0.2"
|
||||
},
|
||||
{
|
||||
"name": "콘크리트",
|
||||
"unit": "㎥",
|
||||
"amount": 2.0595,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 0.952 + 벽체 1.1075"
|
||||
},
|
||||
{
|
||||
"name": "유로폼",
|
||||
"unit": "㎡",
|
||||
"amount": 12.5376,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 1.92 + 벽체 10.6176 · 원본 「유로폼」"
|
||||
},
|
||||
{
|
||||
"name": "터파기",
|
||||
"unit": "㎥",
|
||||
"amount": 13.104,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "되메우기",
|
||||
"unit": "㎥",
|
||||
"amount": 6.504,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "잔토처리",
|
||||
"unit": "㎥",
|
||||
"amount": 6.61,
|
||||
"destination": "earthwork"
|
||||
}
|
||||
],
|
||||
"note": "⚠ 철근·면목 줄이 **원본에 없다** — 날개벽 탭 다섯에 그 줄이 없고 집수정구조도 탭에만 D13·면목이 있다. 지어내지 않는다."
|
||||
},
|
||||
{
|
||||
"type_id": "pipe_wing_wall",
|
||||
"spec": {
|
||||
"wing_wall_type": "C-TYPE",
|
||||
"pipe_diameter_mm": "800"
|
||||
},
|
||||
"unit": "개소",
|
||||
"source": "uljin_library",
|
||||
"source_note": "§1 관보호공 날개벽 — 원본 탭 「날개벽(800)C-TYPE산출근거」",
|
||||
"components": [
|
||||
{
|
||||
"name": "기초잡석",
|
||||
"unit": "㎥",
|
||||
"amount": 0.6821,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "T=0.2"
|
||||
},
|
||||
{
|
||||
"name": "콘크리트",
|
||||
"unit": "㎥",
|
||||
"amount": 1.109,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 0.4847 + 벽체 0.6243"
|
||||
},
|
||||
{
|
||||
"name": "유로폼",
|
||||
"unit": "㎡",
|
||||
"amount": 6.2309,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 1.4786 + 벽체 4.7523 · 원본 「유로폼」"
|
||||
},
|
||||
{
|
||||
"name": "터파기",
|
||||
"unit": "㎥",
|
||||
"amount": 7.7269,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "되메우기",
|
||||
"unit": "㎥",
|
||||
"amount": 4.7148,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "잔토처리",
|
||||
"unit": "㎥",
|
||||
"amount": 3.0122,
|
||||
"destination": "earthwork"
|
||||
}
|
||||
],
|
||||
"note": "⚠ 철근·면목 줄이 **원본에 없다** — 날개벽 탭 다섯에 그 줄이 없고 집수정구조도 탭에만 D13·면목이 있다. 지어내지 않는다."
|
||||
},
|
||||
{
|
||||
"type_id": "pipe_wing_wall",
|
||||
"spec": {
|
||||
"wing_wall_type": "A-TYPE",
|
||||
"pipe_diameter_mm": "1000"
|
||||
},
|
||||
"unit": "개소",
|
||||
"source": "uljin_library",
|
||||
"source_note": "§1 관보호공 날개벽 — 원본 탭 「날개벽(1000)A-TYPE산출근거」",
|
||||
"components": [
|
||||
{
|
||||
"name": "기초잡석",
|
||||
"unit": "㎥",
|
||||
"amount": 1.6,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "T=0.2"
|
||||
},
|
||||
{
|
||||
"name": "콘크리트",
|
||||
"unit": "㎥",
|
||||
"amount": 2.891,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 1.368 + 벽체 1.523"
|
||||
},
|
||||
{
|
||||
"name": "합판거푸집",
|
||||
"unit": "㎡",
|
||||
"amount": 18.255,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 2.24 + 벽체 16.015 · 원본 「거푸집 합판(4회)」"
|
||||
},
|
||||
{
|
||||
"name": "터파기",
|
||||
"unit": "㎥",
|
||||
"amount": 24.39,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "되메우기",
|
||||
"unit": "㎥",
|
||||
"amount": 10.478,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "잔토처리",
|
||||
"unit": "㎥",
|
||||
"amount": 13.912,
|
||||
"destination": "earthwork"
|
||||
}
|
||||
],
|
||||
"note": "⚠ 철근·면목 줄이 **원본에 없다** — 날개벽 탭 다섯에 그 줄이 없고 집수정구조도 탭에만 D13·면목이 있다. 지어내지 않는다."
|
||||
},
|
||||
{
|
||||
"type_id": "pipe_wing_wall",
|
||||
"spec": {
|
||||
"wing_wall_type": "C-TYPE",
|
||||
"pipe_diameter_mm": "1000"
|
||||
},
|
||||
"unit": "개소",
|
||||
"source": "uljin_library",
|
||||
"source_note": "§1 관보호공 날개벽 — 원본 탭 「날개벽(1000)C-TYPE산출근거」",
|
||||
"components": [
|
||||
{
|
||||
"name": "기초잡석",
|
||||
"unit": "㎥",
|
||||
"amount": 1.0271,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "T=0.2"
|
||||
},
|
||||
{
|
||||
"name": "콘크리트",
|
||||
"unit": "㎥",
|
||||
"amount": 1.9109,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 0.7736 + 벽체 1.1373"
|
||||
},
|
||||
{
|
||||
"name": "합판거푸집",
|
||||
"unit": "㎡",
|
||||
"amount": 10.722,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 1.9118 + 벽체 8.8102 · 원본 「거푸집 합판(4회)」"
|
||||
},
|
||||
{
|
||||
"name": "터파기",
|
||||
"unit": "㎥",
|
||||
"amount": 13.7179,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "되메우기",
|
||||
"unit": "㎥",
|
||||
"amount": 7.9134,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "잔토처리",
|
||||
"unit": "㎥",
|
||||
"amount": 5.8046,
|
||||
"destination": "earthwork"
|
||||
}
|
||||
],
|
||||
"note": "⚠ 철근·면목 줄이 **원본에 없다** — 날개벽 탭 다섯에 그 줄이 없고 집수정구조도 탭에만 D13·면목이 있다. 지어내지 않는다."
|
||||
},
|
||||
{
|
||||
"type_id": "pipe_wing_wall",
|
||||
"spec": {
|
||||
"wing_wall_type": "A-TYPE+집수정",
|
||||
"pipe_diameter_mm": "800"
|
||||
},
|
||||
"unit": "개소",
|
||||
"source": "uljin_library",
|
||||
"source_note": "§1 관보호공 날개벽 — 원본 탭 「날개벽(800)A-TYPE+집수정산출근거」",
|
||||
"components": [
|
||||
{
|
||||
"name": "기초잡석",
|
||||
"unit": "㎥",
|
||||
"amount": 1.152,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "T=0.2"
|
||||
},
|
||||
{
|
||||
"name": "콘크리트",
|
||||
"unit": "㎥",
|
||||
"amount": 2.6395,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 0.952 + 벽체 1.6875"
|
||||
},
|
||||
{
|
||||
"name": "합판거푸집",
|
||||
"unit": "㎡",
|
||||
"amount": 18.3376,
|
||||
"destination": "unit_price",
|
||||
"basis_note": "저판 1.92 + 벽체 16.4176 · 원본 「거푸집 합판(4회)」"
|
||||
},
|
||||
{
|
||||
"name": "터파기",
|
||||
"unit": "㎥",
|
||||
"amount": 16.256,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "되메우기",
|
||||
"unit": "㎥",
|
||||
"amount": 8.44,
|
||||
"destination": "earthwork"
|
||||
},
|
||||
{
|
||||
"name": "잔토처리",
|
||||
"unit": "㎥",
|
||||
"amount": 7.816,
|
||||
"destination": "earthwork"
|
||||
}
|
||||
],
|
||||
"note": "⚠ 철근·면목 줄이 **원본에 없다** — 날개벽 탭 다섯에 그 줄이 없고 집수정구조도 탭에만 D13·면목이 있다. 지어내지 않는다."
|
||||
}
|
||||
],
|
||||
"not_found": {
|
||||
@@ -299,6 +559,14 @@
|
||||
"why": "물구멍을 자재 줄로 세우면 규격·수량이 눈에 보이고 되짚을 수 있다. 제잡비 윗단은 같은 것을 품 안에 녹이는 다른 방식이라 어느 쪽이든 하나만 골라야 한다.",
|
||||
"scope": "⚠ 지금 쓰는 돌쌓기(13-4 계열)에는 **제잡비 행 자체가 없어** 겹치지 않는다(전수 확인). 이 규칙은 13-6·13-7 을 쓰게 될 때 걸린다.",
|
||||
"guard": "제잡비 윗단과 물구멍 줄이 함께 서면 멈출 것 — B09 ㉥ 가드와 짝."
|
||||
},
|
||||
{
|
||||
"key": "날개벽 「A-TYPE+집수정」 ↔ 유입부 집수정 줄",
|
||||
"where": "원본 탭 「날개벽(800)집수정산출근거」",
|
||||
"quote": "A-TYPE 날개벽에 집수정을 **결합한** 형식의 개소당 물량(터파기 16.256㎥ 등)",
|
||||
"our_choice": "이 형식을 고르면 **집수정 줄을 따로 세우지 않는다** — 날개벽 값이 이미 품고 있다.",
|
||||
"why": "따로 세우면 한 개소를 두 번 센다(터파기·콘크리트·거푸집 전부).",
|
||||
"guard": "`wing_wall_type` 이 「A-TYPE+집수정」인데 `inlet_basin_form` 도 차 있으면 사유로 알린다."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
"""관보호공 날개벽 원단위 — 소광리 원본 다섯 탭에서 옮긴 값 (2026-09-09, 계획서 4-13).
|
||||
|
||||
값은 **개소당·붙박이**다. 원본 탭(`07-구조도-소광리.xlsx`)의 소계를 그대로 옮겼고
|
||||
비례로 늘리지 않는다 — Ø800·Ø1000, A·C-TYPE, 그리고 「A-TYPE+집수정」 다섯뿐이다.
|
||||
|
||||
⚠ 겹쳐 세는 자리 하나 — 「A-TYPE+집수정」은 집수정을 **품은** 형식이라 집수정 줄을 따로
|
||||
세우면 한 개소를 두 번 센다. 값을 고치지 않고 **사유로 드러낸다.**
|
||||
⚠ 철근·면목 줄은 원본 날개벽 탭에 **없다**(집수정구조도 탭에만 있음) — 지어내지 않는다.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
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_ObservedUnit import load_observed_table # noqa: E402
|
||||
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import ( # noqa: E402
|
||||
ATTACHMENTS,
|
||||
OBSERVED_SPEC_KEYS,
|
||||
attachments_of,
|
||||
wing_wall_double_count,
|
||||
)
|
||||
|
||||
|
||||
def _registry_choices() -> list[str]:
|
||||
payload = json.loads(
|
||||
(ROOT / "B05_Profile" / "B05_Profile_Structure_Types.json").read_text(encoding="utf-8")
|
||||
)
|
||||
types = payload if isinstance(payload, list) else payload["types"]
|
||||
pipe = next(item for item in types if item["type_id"] == "pipe")
|
||||
option = next(o for o in pipe["options"] if o["key"] == "wing_wall_type")
|
||||
return list(option["choices"])
|
||||
|
||||
|
||||
def test_다섯_형식이_표에_있다() -> None:
|
||||
table = load_observed_table()
|
||||
specs = {
|
||||
(spec.get("wing_wall_type"), spec.get("pipe_diameter_mm"))
|
||||
for spec in table.specs_for("pipe_wing_wall")
|
||||
}
|
||||
assert specs == {
|
||||
("A-TYPE", "800"),
|
||||
("C-TYPE", "800"),
|
||||
("A-TYPE", "1000"),
|
||||
("C-TYPE", "1000"),
|
||||
("A-TYPE+집수정", "800"),
|
||||
}
|
||||
|
||||
|
||||
def test_원본_소계와_같다() -> None:
|
||||
"""Ø800 A-TYPE — 원본 탭 소계(터파기 13.104 · 저판 0.952 + 벽체 1.1075 …)."""
|
||||
found = load_observed_table().find(
|
||||
"pipe_wing_wall", {"wing_wall_type": "A-TYPE", "pipe_diameter_mm": "800"}
|
||||
)
|
||||
assert found is not None
|
||||
amounts = {c["name"]: c["amount"] for c in found["components"]}
|
||||
assert amounts["터파기"] == 13.104
|
||||
assert amounts["되메우기"] == 6.504
|
||||
assert amounts["잔토처리"] == 6.61
|
||||
assert amounts["기초잡석"] == 1.152
|
||||
assert abs(amounts["콘크리트"] - (0.952 + 1.1075)) < 1e-9
|
||||
assert abs(amounts["유로폼"] - (1.92 + 10.6176)) < 1e-9
|
||||
|
||||
|
||||
def test_거푸집_종류가_탭마다_다르다() -> None:
|
||||
"""Ø800 A 는 유로폼, Ø1000 은 합판(4회) — 단가가 갈리므로 이름을 뭉개지 않는다."""
|
||||
table = load_observed_table()
|
||||
small = table.find("pipe_wing_wall", {"wing_wall_type": "A-TYPE", "pipe_diameter_mm": "800"})
|
||||
big = table.find("pipe_wing_wall", {"wing_wall_type": "A-TYPE", "pipe_diameter_mm": "1000"})
|
||||
assert "유로폼" in [c["name"] for c in small["components"]]
|
||||
assert "합판거푸집" in [c["name"] for c in big["components"]]
|
||||
|
||||
|
||||
def test_철근_면목은_안_지어낸다() -> None:
|
||||
table = load_observed_table()
|
||||
for spec in table.specs_for("pipe_wing_wall"):
|
||||
found = table.find("pipe_wing_wall", spec)
|
||||
names = [c["name"] for c in found["components"]]
|
||||
assert not any("철근" in name or "면목" in name for name in names), spec
|
||||
|
||||
|
||||
def test_형식을_고르면_줄이_선다() -> None:
|
||||
rows = attachments_of(
|
||||
{
|
||||
"structure_id": "s1",
|
||||
"type_id": "pipe",
|
||||
"options": {"wing_wall_type": "A-TYPE", "pipe_diameter_mm": "800"},
|
||||
}
|
||||
)
|
||||
assert [row["type_id"] for row in rows] == ["pipe_wing_wall"]
|
||||
# 안 고르면 줄이 없다 — 안 놓은 것과 같다.
|
||||
assert attachments_of({"structure_id": "s2", "type_id": "pipe", "options": {}}) == []
|
||||
|
||||
|
||||
def test_집수정_결합형은_두_번_세는_것을_알린다() -> None:
|
||||
assert wing_wall_double_count({"wing_wall_type": "A-TYPE+집수정"}) is None
|
||||
warn = wing_wall_double_count(
|
||||
{"wing_wall_type": "A-TYPE+집수정", "inlet_basin_form": "□형(기본형)"}
|
||||
)
|
||||
assert warn is not None and "두 번" in warn
|
||||
assert (
|
||||
wing_wall_double_count({"wing_wall_type": "A-TYPE", "inlet_basin_form": "□형(기본형)"})
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
def test_등록부_선택지와_표가_한_벌이다() -> None:
|
||||
"""칸에서 고를 수 있는데 표에 없으면 「원단위 미확보」로 끝난다 — 둘을 붙여 둔다."""
|
||||
table_types = {
|
||||
spec.get("wing_wall_type") for spec in load_observed_table().specs_for("pipe_wing_wall")
|
||||
}
|
||||
assert set(_registry_choices()) == table_types
|
||||
assert OBSERVED_SPEC_KEYS["pipe_wing_wall"] == ("wing_wall_type", "pipe_diameter_mm")
|
||||
assert any(item[0] == "pipe_wing_wall" for item in ATTACHMENTS["pipe"])
|
||||
Reference in New Issue
Block a user