feat(B05): 세월교 · 박스 유출 = 「추가 흙막이(단)」 공용 스테퍼 · 「+ 흙막이」 없앰 · 집계 단 수로 상자(90-1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
This commit is contained in:
@@ -40,13 +40,16 @@ import {
|
||||
INLET_REVET_KEYS,
|
||||
type InletStructureKind,
|
||||
labeled,
|
||||
numberInput,
|
||||
OUTLET_REVET_KEYS,
|
||||
stepper,
|
||||
WING_IN_KEYS,
|
||||
WING_OUT_KEYS,
|
||||
} from "./B05_Profile_UI_Drainage_Facility_Fields";
|
||||
import { guardChoiceFields, revetChoiceRow } from "./B05_Profile_UI_Drainage_Revet_Choice";
|
||||
import {
|
||||
guardChoiceFields,
|
||||
guardSoilCount,
|
||||
outletTiersRow,
|
||||
revetChoiceRow,
|
||||
} from "./B05_Profile_UI_Drainage_Revet_Choice";
|
||||
import { optionDefaults } from "./B05_Profile_UI_Structures_Fields";
|
||||
import {
|
||||
createSpecForm,
|
||||
@@ -67,7 +70,6 @@ import {
|
||||
pipeDrawn,
|
||||
pipeExtraCount,
|
||||
pipeLengthM,
|
||||
setPipeExtraCount,
|
||||
} from "../A00_Common/design/design_structure_pipe_calc";
|
||||
import {
|
||||
hasLinks,
|
||||
@@ -296,25 +298,11 @@ export function createFacilityOptionsForm(
|
||||
return drawnMemo;
|
||||
};
|
||||
// 유출 「추가 흙막이(단)」(54-27) — 값 = 횡단 조정 단 수(같은 저장 자리) · 흙막이 상자 수가 따라감
|
||||
const tiersInput = numberInput("1", "0");
|
||||
tiersInput.max = "9";
|
||||
const tiersRow = labeled("추가 흙막이(단)", stepper(tiersInput, 1, 0));
|
||||
tiersRow.dataset.specItem = "outlet.tiers";
|
||||
tiersRow
|
||||
.querySelectorAll("button")
|
||||
.forEach((b, i) => (b.title = `1단 ${i ? "늘리기" : "줄이기"}`));
|
||||
const paintTiers = (values: Record<string, string>): HTMLElement => {
|
||||
const count = pipeExtraCount(chainage);
|
||||
tiersInput.value = count === null ? "" : String(count);
|
||||
tiersInput.disabled = count === null;
|
||||
tiersRow.hidden = !!values.structure && values.structure !== "기슭막이";
|
||||
return tiersRow;
|
||||
};
|
||||
tiersInput.addEventListener("change", () => {
|
||||
const count = Math.max(0, Math.min(9, Math.round(Number(tiersInput.value) || 0)));
|
||||
// 지형이 못 세운 단은 횡단 기하가 자름 — 끝난 뒤 세운 만큼으로 다시 그림
|
||||
void setPipeExtraCount(chainage, count).then(() => pipeForm.recount());
|
||||
});
|
||||
const tiersRow = outletTiersRow(
|
||||
() => chainage,
|
||||
() => pipeForm.recount(),
|
||||
(structure) => !structure || structure === "기슭막이",
|
||||
);
|
||||
const inletChoice = revetChoiceRow(
|
||||
() => chainage,
|
||||
() => pipeForm.refresh(),
|
||||
@@ -327,7 +315,7 @@ export function createFacilityOptionsForm(
|
||||
// 관 보호공 [연동] · [경사](54-30) — 유입 · 유출 상자 각각 한 줄(같은 값) · 길이 있는 흙막이만(54-40 · 집수정 · 안 고름은 숨김)
|
||||
fields: (c, values) =>
|
||||
c.id === "outlet"
|
||||
? [paintTiers(values), outletChoice.paint(values.structure !== "기슭막이")]
|
||||
? [tiersRow.paint(values), outletChoice.paint(values.structure !== "기슭막이")]
|
||||
: c.id === "inlet"
|
||||
? [inletChoice.paint(values.structure !== "기슭막이")]
|
||||
: c.id === "soil_add" // 추가 흙막이 상자도 같은 줄(54-36 · 상자마다 한 줄 · 같은 값)
|
||||
@@ -407,11 +395,17 @@ export function createFacilityOptionsForm(
|
||||
};
|
||||
};
|
||||
const fordFlowBox = overflow(() => fordForm, "ford");
|
||||
// 유출 흙막이 단 수 = 흙막이 상자 수(관보호공과 같은 방향 · 「+ 흙막이」 없음 · 90-1)
|
||||
const fordForm: SpecForm = createSpecForm(specLinks, {
|
||||
onChange: fordFlowBox.onChange,
|
||||
fields: guardChoiceFields(
|
||||
() => chainage,
|
||||
() => fordForm.refresh(),
|
||||
() => fordForm.recount(),
|
||||
),
|
||||
count: guardSoilCount(
|
||||
() => chainage,
|
||||
() => fordForm.state().outlet?.[0]?.structure,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -473,6 +467,11 @@ export function createFacilityOptionsForm(
|
||||
fields: guardChoiceFields(
|
||||
() => chainage,
|
||||
() => boxForm.refresh(),
|
||||
() => boxForm.recount(),
|
||||
),
|
||||
count: guardSoilCount(
|
||||
() => chainage,
|
||||
() => boxForm.state().outlet?.[0]?.structure,
|
||||
),
|
||||
});
|
||||
// 날개벽 칸 — 세월교 · BOX 가 같은 조각을 쓰던 자리 · 조정 행은 명세 유입 · 유출 칸으로 옮겨 붙음
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import { toggleButton } from "./B05_Profile_UI_Panel_Fields";
|
||||
import { labeled, numberInput, stepper } from "./B05_Profile_UI_Drainage_Facility_Fields";
|
||||
import {
|
||||
pipeExtraCount,
|
||||
pipeRevetChoice,
|
||||
setPipeExtraCount,
|
||||
setPipeRevetChoice,
|
||||
} from "../A00_Common/design/design_structure_pipe_calc";
|
||||
|
||||
@@ -54,20 +57,67 @@ export function revetChoiceRow(
|
||||
return { paint };
|
||||
}
|
||||
|
||||
/** 세월교 · 박스 흙막이 상자 줄(65-2 · 배관과 같은 줄) — 흙막이를 고른 유입 · 유출 · 추가 흙막이 상자마다 한 줄.
|
||||
* 명세 폼 `fields` 자리에 그대로 씀. */
|
||||
/** 유출 「추가 흙막이(단)」(54-27 · 90-1 배관 · 세월교 · 박스 공용) — 값 = 횡단 조정 단 수(같은 저장 자리) ·
|
||||
* 흙막이 상자 수가 따라감(폼 `count` 훅 = `pipeExtraCount`). `shown` = 유출 구조 값이 벽인지. */
|
||||
export function outletTiersRow(
|
||||
chainageOf: () => number | null,
|
||||
/** 쓴 뒤 — 지형이 못 세운 단은 횡단 기하가 자름 · 세운 만큼으로 상자를 다시 셈. */
|
||||
recount: () => void,
|
||||
shown: (structure: string | undefined) => boolean,
|
||||
): { paint: (values: Record<string, string>) => HTMLElement } {
|
||||
const input = numberInput("1", "0");
|
||||
input.max = "9";
|
||||
const row = labeled("추가 흙막이(단)", stepper(input, 1, 0));
|
||||
row.dataset.specItem = "outlet.tiers";
|
||||
row.querySelectorAll("button").forEach((b, i) => (b.title = `1단 ${i ? "늘리기" : "줄이기"}`));
|
||||
input.addEventListener("change", () => {
|
||||
const count = Math.max(0, Math.min(9, Math.round(Number(input.value) || 0)));
|
||||
void setPipeExtraCount(chainageOf(), count).then(recount);
|
||||
});
|
||||
return {
|
||||
paint: (values) => {
|
||||
const count = pipeExtraCount(chainageOf());
|
||||
input.value = count === null ? "" : String(count);
|
||||
input.disabled = count === null;
|
||||
row.hidden = !shown(values.structure);
|
||||
return row;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** 세월교 · 박스 흙막이 상자 줄(65-2 · 배관과 같은 줄) — 흙막이를 고른 유입 · 유출 · 추가 흙막이 상자마다 한 줄 ·
|
||||
* 유출 상자엔 「추가 흙막이(단)」(90-1). 명세 폼 `fields` 자리에 그대로 씀. */
|
||||
export function guardChoiceFields(
|
||||
chainageOf: () => number | null,
|
||||
written: () => void,
|
||||
recount: () => void,
|
||||
): (c: { id: string }, values: Record<string, string>) => HTMLElement[] {
|
||||
const sides = {
|
||||
inlet: revetChoiceRow(chainageOf, written),
|
||||
outlet: revetChoiceRow(chainageOf, written),
|
||||
};
|
||||
const tiers = outletTiersRow(chainageOf, recount, (structure) => structure === "흙막이");
|
||||
return (c, values) =>
|
||||
c.id === "soil_add"
|
||||
? [revetChoiceRow(chainageOf, written).paint(false)]
|
||||
: c.id === "inlet" || c.id === "outlet"
|
||||
? [sides[c.id].paint(values.structure !== "흙막이")]
|
||||
? [
|
||||
...(c.id === "outlet" ? [tiers.paint(values)] : []),
|
||||
sides[c.id].paint(values.structure !== "흙막이"),
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
/** 세월교 · 박스 흙막이 상자 수(90-1) — 유출이 흙막이면 지형이 세운 유출 단 수 · 아니면 0(옛 상자는
|
||||
* 숨기고 값은 파일에 남김). 명세 폼 `count` 훅 자리. */
|
||||
export function guardSoilCount(
|
||||
chainageOf: () => number | null,
|
||||
outletStructure: () => string | undefined,
|
||||
): (c: { id: string }) => number | null | undefined {
|
||||
return (c) =>
|
||||
c.id !== "soil_add"
|
||||
? undefined
|
||||
: outletStructure() === "흙막이"
|
||||
? pipeExtraCount(chainageOf())
|
||||
: 0;
|
||||
}
|
||||
|
||||
@@ -175,10 +175,11 @@ function relocateSideRows(panelRoot: HTMLElement, scroll = true): void {
|
||||
const group = target.closest<HTMLElement>("fieldset");
|
||||
if (!group) return;
|
||||
const ownerSlot = slotOf(panelRoot.dataset.extraSide === "inlet" ? "inlet" : "outlet");
|
||||
// 배관 유출 다단 = 그 단의 「흙막이」 컨테이너(54-10) — 옛 추가 기슭막이 칸 대신 그 상자를 켬 ·
|
||||
// 단 수 · 옵션은 부모(유출) 칸에 그대로
|
||||
// 배관 · 세월교 · 박스 유출 다단 = 그 단의 「흙막이」 컨테이너(54-10 · 90-1) — 옛 추가 기슭막이 칸
|
||||
// 대신 그 상자를 켬 · 단 수 · 옵션은 부모(유출) 칸에 그대로
|
||||
const soil =
|
||||
ownerSlot === sideSlots.outlet && slotUsable(ownerSlot)
|
||||
(ownerSlot === sideSlots.outlet || ownerSlot === sideSlots.wingOutlet) &&
|
||||
slotUsable(ownerSlot)
|
||||
? ownerSlot
|
||||
.closest(".b05-structure__spec")
|
||||
?.querySelectorAll<HTMLElement>('fieldset[data-spec-container="soil_add"]')[
|
||||
@@ -186,7 +187,7 @@ function relocateSideRows(panelRoot: HTMLElement, scroll = true): void {
|
||||
]
|
||||
: undefined;
|
||||
if (soil) {
|
||||
moveRows(panelRoot, PIPE_OUTLET_ROWS, ownerSlot);
|
||||
moveRows(panelRoot, rowsFor(ownerSlot), ownerSlot);
|
||||
setGroupLabel(soil, "");
|
||||
soil.classList.add("is-active");
|
||||
if (scroll) soil.scrollIntoView({ block: "nearest" });
|
||||
|
||||
@@ -142,13 +142,6 @@ export function applyPipeOptionsToCache(
|
||||
});
|
||||
}
|
||||
}
|
||||
// 세월교 · 박스 추가 흙막이 = 폼 상자 수가 유출 다단 수(배관은 횡단이 정함 · 73-4)
|
||||
const soil = body ? soilCount(patch) : null;
|
||||
if (soil !== null && soil !== (owner.design?.extra_wall_counts?.outlet ?? 0))
|
||||
// 늦게 불러옴 — 흙막이 세트 때만 쓰는 횡단 기하 묶음(배관 폼 길은 안 끌어옴)
|
||||
void import("../A00_Common/design/design_structure_pipe_calc").then((calc) =>
|
||||
calc.setPipeExtraCount(owner.chainage_m, soil),
|
||||
);
|
||||
if (!culvert.hidden_pipe || body) applySoilTiers(ctx, owner, patch, whole);
|
||||
own(culvert.inlet, "basin_length_m", num("inlet_basin_length_m"));
|
||||
own(culvert.inlet, "basin_before_m", num("inlet_basin_before_m"));
|
||||
@@ -190,14 +183,6 @@ function syncBodyGuard(
|
||||
return !!guard;
|
||||
}
|
||||
|
||||
/** 추가 흙막이 상자 수 — 가장 큰 `soil_add_{n}_*` 의 n. */
|
||||
function soilCount(patch: Record<string, number | string>): number {
|
||||
return Math.max(
|
||||
0,
|
||||
...Object.keys(patch).map((key) => Number(/^soil_add_(\d+)_/.exec(key)?.[1] ?? 0)),
|
||||
);
|
||||
}
|
||||
|
||||
/** 흙막이 컨테이너가 마지막으로 보낸 높이 · 형태(`측점:extra{n}`) — 기하가 다시 그릴 때마다 키를 지형에
|
||||
* 맞춰 고쳐 되받으므로(syncApplied) 되받은 값과 견주면 안 바꾼 단도 다시 보냄(54-10). */
|
||||
const soilSent = new Map<string, { h: number | null; m: string | null }>();
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
짝: `A00_Common/design/design_structure_guard.ts` · `_road.ts` 선택 컨테이너(머리 · 잇기 · 제목) —
|
||||
시험이 대조.
|
||||
기타(52-14) = 사용자가 적은 상세 종류 이름이 집계 건 이름(`그룹`) · 비면 「기타」.
|
||||
배관 흙막이 = 지형이 세운 유출 다단 수(`흙막이단`)까지만 — 넘친 컨테이너 값은 파일에만(54-11).
|
||||
배관 · 세월교 · 박스 흙막이 = 지형이 세운 유출 다단 수(`흙막이단`)까지만 — 넘친 컨테이너 값은
|
||||
파일에만(54-11 · 90-1) · 세월교 · 박스 유출이 흙막이가 아니면 0.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -30,6 +31,9 @@ SPEC_CONTAINERS: dict[str, tuple[tuple[str, str, str], ...]] = {
|
||||
"etc": (("etc_detail", "getcdetail", "상세 내용"),),
|
||||
}
|
||||
_TEXT = ("structure", "form", "note")
|
||||
#: 흙막이 상자 수 = 지형이 세운 유출 다단 수인 종류(54-11 · 90-1) · 세월교 · 박스 유출 구조 칸
|
||||
_TIERED = ("pipe", "box_culvert", "ford_bridge")
|
||||
_BODY_OUTLET = {"box_culvert": "wing_out", "ford_bridge": "outlet_type"}
|
||||
|
||||
|
||||
def etc_label(type_id: str, options: dict[str, Any] | None) -> dict[str, str]:
|
||||
@@ -70,6 +74,9 @@ def container_rows(item: dict[str, Any], links: dict[str, Any]) -> list[dict[str
|
||||
"""한 구조물의 선택 컨테이너 인스턴스마다 한 건(n 차례) — 컨테이너 없는 종류는 빈 목록."""
|
||||
rows: list[dict[str, Any]] = []
|
||||
tiers = item.get("흙막이단") # None = 모름(저장된 것 그대로)
|
||||
guard_key = _BODY_OUTLET.get(item["type_id"])
|
||||
if guard_key and str(item["options"].get(guard_key) or "").strip() != "흙막이":
|
||||
tiers = 0 # 유출이 날개벽 · 없음 — 옛 상자는 숨김 · 값은 파일에 남김(90-1)
|
||||
for prefix, link, title in SPEC_CONTAINERS.get(item["type_id"], ()):
|
||||
head = re.compile(rf"^{prefix}_(\d+)_(.+)$")
|
||||
found: dict[int, dict[str, Any]] = {}
|
||||
@@ -80,7 +87,7 @@ def container_rows(item: dict[str, Any], links: dict[str, Any]) -> list[dict[str
|
||||
for n in sorted(found):
|
||||
if (
|
||||
prefix == "soil_add"
|
||||
and item["type_id"] == "pipe"
|
||||
and item["type_id"] in _TIERED
|
||||
and tiers is not None
|
||||
and n > tiers
|
||||
):
|
||||
|
||||
@@ -118,6 +118,8 @@ const PIPE_CALC = {
|
||||
pipeDrawn: () => null,
|
||||
pipeLengthM: () => null,
|
||||
pipeExtraCount: () => Math.min(stored, LIMIT),
|
||||
pipeRevetChoice: () => null,
|
||||
setPipeRevetChoice: () => Promise.resolve(),
|
||||
setPipeExtraCount: (chainage, count) => {
|
||||
writes.push([chainage, count]);
|
||||
stored = count;
|
||||
@@ -127,11 +129,8 @@ const PIPE_CALC = {
|
||||
const STUBS = {
|
||||
"@config/config_frontend": { FORD_MANNING_N: 0.03, FORD_SLOPE: 0.02 },
|
||||
"../A00_Common/design/design_structure_pipe_calc": PIPE_CALC,
|
||||
// 관 보호공 [연동] · [경사] 줄(54-30) — 여기서는 자리만
|
||||
"./B05_Profile_UI_Drainage_Revet_Choice": {
|
||||
revetChoiceRow: () => ({ paint: () => new FakeNode("div") }),
|
||||
guardChoiceFields: () => () => [],
|
||||
},
|
||||
// 관 보호공 [연동] · [경사] 단추(54-30) — 여기서는 자리만 · 단 칸(90-1 공용)은 실제 파일
|
||||
"./B05_Profile_UI_Panel_Fields": { toggleButton: () => new FakeNode("button") },
|
||||
"../../B05_Profile/B05_Profile_UI_Structures_Summary_Row": {
|
||||
buildSummaryRow: () => {
|
||||
const root = new FakeNode("div");
|
||||
@@ -169,7 +168,13 @@ const form = createFacilityOptionsForm();
|
||||
form.setChainage(100);
|
||||
form.setFacility("pipe", { pipe_diameter_mm: 1000 });
|
||||
|
||||
const spec = form.root.querySelector(".b05-structure__spec");
|
||||
// 시설마다 명세 폼이 따로 — 지금 시설의 폼(본체 상자 id 로 찾음)
|
||||
let body = null;
|
||||
const specOf = () =>
|
||||
form.root
|
||||
.querySelectorAll(".b05-structure__spec")
|
||||
.find((s) => !body || s.children.some((k) => k.dataset?.specContainer === body));
|
||||
let spec = specOf();
|
||||
const boxesOf = (id) => spec.children.filter((k) => k.dataset?.specContainer === id);
|
||||
const tierRow = () =>
|
||||
boxesOf("outlet")[0]
|
||||
@@ -199,10 +204,41 @@ async function main() {
|
||||
stored = 2;
|
||||
form.recount();
|
||||
out.fromCross = snap();
|
||||
out.writes = writes;
|
||||
// 다른 구조(옛 값)면 칸을 가림
|
||||
form.setFacility("pipe", { pipe_diameter_mm: 1000, outlet_type: "옛값" });
|
||||
out.otherHidden = tierRow()?.hidden ?? null;
|
||||
// 세월교 · 박스 유출 흙막이(90-1) — 같은 단 칸 · 단 수 = 흙막이 상자 수 · 「+ 흙막이」 없음 ·
|
||||
// 유출이 흙막이가 아니면 단 칸 · 옛 상자 숨김(값은 남김)
|
||||
const addButton = () =>
|
||||
spec.children.find((k) => k.dataset?.specAdd === "soil_add") ? true : false;
|
||||
const old = { soil_add_1_form: "바자", soil_add_2_form: "돌망태", soil_add_3_form: "바자" };
|
||||
for (const [facility, key, container] of [
|
||||
["ford_bridge", "outlet_type", "ford"],
|
||||
["box_culvert", "wing_out", "body"],
|
||||
]) {
|
||||
stored = 0;
|
||||
body = container;
|
||||
form.setFacility(facility, { [key]: "흙막이", ...old });
|
||||
spec = specOf();
|
||||
const steps = {};
|
||||
for (const n of ["2", "0"]) {
|
||||
const input = tierInput();
|
||||
input.value = n;
|
||||
input.dispatchEvent(new Event("change"));
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
steps[`set${n}`] = { ...snap(), hidden: tierRow()?.hidden ?? null, add: addButton() };
|
||||
}
|
||||
form.setFacility(facility, { [key]: "날개벽", ...old });
|
||||
steps.wing = {
|
||||
boxes: boxesOf("soil_add").length,
|
||||
hidden: tierRow()?.hidden ?? null,
|
||||
add: addButton(),
|
||||
kept: Object.keys(form.readOptions()).filter((k) => k.startsWith("soil_add_")).length,
|
||||
};
|
||||
out[facility] = steps;
|
||||
}
|
||||
out.writes = writes;
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
}
|
||||
main().catch((error) => {
|
||||
|
||||
@@ -89,6 +89,8 @@ def test_다단_벽_고르기는_흙막이_컨테이너로() -> None:
|
||||
dock = (ROOT / "B06_Section" / "B06_Section_UI_Adjust_Dock.ts").read_text(encoding="utf-8")
|
||||
assert 'fieldset[data-spec-container="soil_add"]' in dock
|
||||
assert "panelRoot.dataset.extraIndex" in dock
|
||||
# 세월교 · 박스 유출 다단도 그 상자로(90-1 · 유출 자리 = 날개벽 칸)
|
||||
assert "ownerSlot === sideSlots.outlet || ownerSlot === sideSlots.wingOutlet" in dock
|
||||
panel = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Structure_Panel.ts").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
@@ -45,7 +45,19 @@ def test_지형_한도를_넘으면_세운_만큼(out) -> None:
|
||||
|
||||
|
||||
def test_좌측_칸은_횡단_단_수_자리에_씀(out) -> None:
|
||||
assert out["writes"] == [[100, 2], [100, 1], [100, 5], [100, 0]]
|
||||
assert out["writes"][:4] == [[100, 2], [100, 1], [100, 5], [100, 0]]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("facility", ["ford_bridge", "box_culvert"])
|
||||
def test_세월교_박스_유출도_같은_단_칸(out, facility) -> None:
|
||||
"""90-1 — 단 수 = 흙막이 상자 수 · 「+ 흙막이」 없음 · 유출이 흙막이 아니면 칸 · 옛 상자 숨김(값 남김)."""
|
||||
steps = out[facility]
|
||||
assert (steps["set2"]["value"], steps["set2"]["boxes"]) == ("2", 2)
|
||||
assert (steps["set0"]["value"], steps["set0"]["boxes"]) == ("0", 0)
|
||||
assert steps["set2"]["structures"] == ["형태", "형태"]
|
||||
assert not steps["set2"]["hidden"] and not steps["set2"]["add"]
|
||||
assert steps["wing"] == {"boxes": 0, "hidden": True, "add": False, "kept": 3}
|
||||
assert out["writes"][4:] == [[100, 2], [100, 0]] * 2
|
||||
|
||||
|
||||
def test_횡단에서_바꾸면_좌측_칸이_따라감(out) -> None:
|
||||
|
||||
@@ -134,18 +134,28 @@ def test_자동_배치_새_세월교는_기본값과_월류_높이():
|
||||
assert "ford_height_m" not in blind.options # 유량 없으면 빈칸
|
||||
|
||||
|
||||
def test_집계표_세월교_흙막이_상자_건():
|
||||
item = {
|
||||
"type_id": "ford_bridge",
|
||||
"options": {"soil_add_1_form": "바자", "soil_add_2_form": "돌망태"},
|
||||
"복사본": "pipe@50.0",
|
||||
"흙막이단": 0, # 배관 단 수는 세월교에 안 걸림
|
||||
}
|
||||
rows = container_rows(item, {"gsoiladd2": "SS000001"})
|
||||
assert [(r["그룹"], r["summary_item"]) for r in rows] == [
|
||||
("흙막이 1", None),
|
||||
("흙막이 2", "SS000001"),
|
||||
]
|
||||
def test_집계표_세월교_박스_흙막이_상자는_유출_단_수만큼():
|
||||
"""90-1 — 관보호공과 같은 방향(단 수 → 상자) · 유출이 흙막이가 아니면 옛 상자는 집계에서 뺌."""
|
||||
soil = {"soil_add_1_form": "바자", "soil_add_2_form": "돌망태"}
|
||||
|
||||
def groups(type_id: str, outlet: str, tiers: int | None) -> list[tuple[str, object]]:
|
||||
key = {"ford_bridge": "outlet_type", "box_culvert": "wing_out"}[type_id]
|
||||
item = {
|
||||
"type_id": type_id,
|
||||
"options": {**soil, key: outlet},
|
||||
"복사본": "pipe@50.0",
|
||||
"흙막이단": tiers,
|
||||
}
|
||||
rows = container_rows(item, {"gsoiladd2": "SS000001"})
|
||||
return [(r["그룹"], r["summary_item"]) for r in rows]
|
||||
|
||||
for type_id in ("ford_bridge", "box_culvert"):
|
||||
both = [("흙막이 1", None), ("흙막이 2", "SS000001")]
|
||||
assert groups(type_id, "흙막이", 2) == both
|
||||
assert groups(type_id, "흙막이", 1) == both[:1]
|
||||
assert groups(type_id, "흙막이", None) == both # 모름 = 저장된 것 그대로
|
||||
assert groups(type_id, "날개벽", 2) == []
|
||||
assert groups(type_id, "", None) == []
|
||||
|
||||
|
||||
def test_B06_측벽_읽기_줄은_세월교_박스_칸에_안_옮김():
|
||||
|
||||
Reference in New Issue
Block a user