refactor(B08,B09): 폴더째 old_code 로 옮기고 빈 화면 둘만 남김 (PLAN 7-3)

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
This commit is contained in:
2026-09-22 12:27:45 +09:00
co-authored by Claude Opus 5
parent 185f800d23
commit 8472fc9f40
231 changed files with 1617 additions and 1216 deletions
@@ -74,15 +74,13 @@ async def haul_inputs_for(project_id: Any) -> dict[str, Any]:
⚠ **여기서 다시 세지 않는다** — 두 값 다 B08 전개에서 나오는 것이라 이쪽이 세면
같은 계산이 두 벌이 된다(CLAUDE.md 5장). 못 읽으면 빈 값으로 두고 **0 으로 눅이지 않는다**.
"""
try:
from B08_Quantity.B08_Quantity_Router_Material import project_haul_inputs
data = await project_haul_inputs(project_id)
return data if isinstance(data, dict) else {}
except Exception:
logger.exception("구조물 몫(공제·잔토) 조회 실패 — 값 없이 진행: project_id=%s", project_id)
return {}
⚠ **지금은 늘 빈 값이다**(PLAN 7-3) — B08 구조물 전개가 `old_code/B08_Quantity/` 로 가고
화면이 빈 틀이라 낼 값이 없다. 값을 지어내지 않고 빈 값으로 두어 화면은 그대로 선다.
B08 을 마스터 얼개로 다시 지을 때 그쪽이 낼 값을 여기로 이으면 된다.
"""
_ = project_id
return {}
async def conversion_factors_for(project_id: Any) -> dict[str, dict[str, float]]:
@@ -9,12 +9,13 @@
표가 `source["quantities"]` 를 보는데 **그 키가 원본 파일에 아예 없다**(실측:
`cross_00960m.json` 에 `samples`·`center_z`·`frame` 뿐). 반면 **저장된 횡단 설계에는
단면적이 그대로 있고**(`cut_soil_area_m2` 등), **사면길이도 그 설계선에서 유도된다**
(`B08_Quantity_Engine_SlopeLength.station_slope`). 즉 **통로만 없었다.**
(`B07_DesignDetail_Engine_SlopeGeometry.station_slope`). 즉 **통로만 없었다.**
⚠ 계산을 새로 짜지 않는다 (CLAUDE.md 5장)
단면적은 B06 이 낸 저장값을 **그대로 읽고**, 사면 계열은 **B08 이 쓰는 그 함수**를 부른다.
계열 이름과 「어느 면을 쓰나」도 `B08_Quantity_Engine_SlopeArea` 의 정의를 빌려 쓴다 —
거기서 밑수가 바뀌면 이 표도 같이 움직여야 하기 때문이다.
단면적은 B06 이 낸 저장값을 **그대로 읽고**, 사면 계열은 `_SlopeGeometry` 의 함수를 부른다.
계열 이름과 「어느 면을 쓰나」도 그 파일의 정의를 빌려 쓴다 — 거기서 밑수가 바뀌면 이 표도
같이 움직여야 하기 때문이다. (옛 자리 = `old_code/B08_Quantity/…_SlopeLength`·`_SlopeArea`,
PLAN 7-3 에서 B07 로 옮겨 적음.)
⚠ 사면 계열 칸의 **단위**
B08 은 측점 사이를 평균단면적법으로 적분해 **면적(㎡)** 을 내지만, 그것은 두 측점이 있어야
@@ -34,8 +35,12 @@ from __future__ import annotations
from typing import Any
from B08_Quantity.B08_Quantity_Engine_SlopeArea import PROTECTION_SOURCE, _key, _length_of
from B08_Quantity.B08_Quantity_Engine_SlopeLength import station_slope
from B07_DesignDetail.B07_DesignDetail_Engine_SlopeGeometry import (
PROTECTION_SOURCE,
length_of,
series_key,
station_slope,
)
#: 저장된 설계 단면적을 그대로 옮기는 칸 — `표 키 → 설계 키`.
#: ⚠ 측구 둘은 B06 이 **절토 분리와 같은 근거**(지반 유형 + 암반 경계선)로 갈라 낸 값이다
@@ -115,9 +120,9 @@ def derived_cells(chainage_m: float, design: dict[str, Any] | None) -> dict[str,
slope = station_slope(float(chainage_m), design)
lengths = {
_key(series, face): _length_of(slope, series, face)
series_key(series, face): length_of(slope, series, face)
for _table_key, series, face in SLOPE_KEYS
}
for table_key, series, face in SLOPE_KEYS:
cells[table_key] = lengths[_key(series, face)]
cells[table_key] = lengths[series_key(series, face)]
return cells
@@ -0,0 +1,284 @@
"""횡단 사면 기하 — 저장된 횡단 설계선에서 절토·성토 사면 구간을 가려낸다.
어디서 왔나 (PLAN 7-3)
옛 `B08_Quantity_Engine_SlopeLength` · `_SlopeArea` 에 있던 것을 **B07 이 쓰는 몫만**
옮겨 적었다. 옛 코드는 `old_code/B08_Quantity/` 에 그대로 있다(지우지 않음).
흐름이 B07 → B08 → B09 이므로 도면(B07)이 수량(B08)을 부르던 거꾸로를 여기서 끊는다.
옮겨 적지 않은 것 — 면적 적분(`build_rows`·`totals`·`build_table`) · 노면 면적
(`road_surface_area`) · 측점 묶음(`station_slopes`). 수량 쪽 몫이라 B07 이 안 쓴다.
왜 유도하나 (B06 무접촉)
설계 엔진이 `cut_slope_segments` 를 내기는 하나 **정본에 저장되지 않는다**. 저장되는 것은
화면이 보낸 설계 지정이고 조회는 저장분을 그대로 싣는다. 그래서 그 값을 원천으로 쓰면
사면적이 조용히 0 이 된다. 대신 **`design_line`(설계선 폴리라인) + 저장된 경사비**로
유도한다. 필요한 입력이 전부 정본에 있어 B06 을 고치지 않아도 된다.
가려내는 방법
노체 끝(`road_edges`)에서 바깥으로 나아가며, 구간 기울기가 **저장된 설계 경사비와 맞는
동안**이 사면이다. 원지반은 기울기가 안 맞아 저절로 끊긴다. 2단 사면(암/토사)도 경사비가
달라 그대로 갈린다.
⚠ 두 가지를 조심한다
· **끝 조각은 딱 안 떨어진다** — 샘플 격자에 걸려 잘리면 `n=1.025` 처럼 나온다. 허용오차를 둔다.
· **지형이 우연히 같은 경사면** 사면이 길게 잡힐 수 있다. 노체에서 바깥으로 **연속**인
구간만 세고 끊기면 멈추는 것으로 막는다.
"""
from __future__ import annotations
import math
from dataclasses import dataclass
from typing import Any
# 경사비 일치 허용오차(비율). 끝 조각이 격자에 잘려 생기는 오차를 덮는 크기다.
_RATIO_TOLERANCE = 0.12
# 평탄부로 볼 기울기 — 소단·측구 바닥은 오름이 거의 없다.
_FLAT_RISE_M = 1e-6
# 법면보호공이 참조하는 계열 — 기본은 면고르기다(같은 사면길이를 쓴다).
PROTECTION_SOURCE = "face_dressing"
@dataclass(slots=True)
class SlopeSegment:
"""사면 한 조각. `side` 는 `left`/`right`, `role` 은 `cut`/`fill`."""
side: str
role: str
from_offset_m: float
to_offset_m: float
rise_m: float
length_m: float
ratio: float
material: str | None = None
@dataclass(slots=True)
class StationSlope:
"""측점 하나의 사면길이 묶음."""
chainage_m: float
cut_length_m: float = 0.0
fill_length_m: float = 0.0
#: 절토 사면길이의 토사·암 몫 — 면고르기가 9-19-1(토사)·9-19-2·3(암)으로 갈림.
#: 둘의 합이 `cut_length_m` 보다 작으면 그 차이는 **못 가른 몫**(설계 지반 프리셋 없음).
cut_soil_length_m: float = 0.0
cut_rock_length_m: float = 0.0
#: 층따기 밑수 — **원지반 표면**의 경사길이(m). B06 설계가 측점마다 낸다
#: (`design.bench_cut_length_m`).
#: ⚠ **성토 비탈면 길이와 다른 면이다** — 층따기는 성토부 **아래 원지반**을 계단으로
#: 깎는 일이라(교본 6장 4절) 비탈면이 아니라 지표면을 따라간다.
bench_cut_length_m: float = 0.0
berm_width_m: float = 0.0
# 성토고(m) — 성토 사면 조각들의 **수직 낙차 합**. 노면 끝에서 원지반까지 내려간 높이다.
# ⚠ 좌우가 다르면 **큰 쪽**을 쓴다. 「중심점 성토고 5m 이상」(품셈 11-3 [주]①) 판정은
# 가장 높은 쪽이 기준이고, 양쪽을 더하면 실제보다 두 배가 된다.
fill_height_m: float = 0.0
#: 노면 폭(m) — 노체 끝(`road_edges`) 좌우 사이.
#: 노체 끝이 저장에 없으면 `None` — 0 으로 때우지 않는다.
roadbed_width_m: float | None = None
segments: tuple[SlopeSegment, ...] = ()
# 사면이 샘플 범위 끝까지 원지반을 못 만나 **면적이 잘린** 측점.
# 설계 엔진이 `slope_unclosed` 로 이미 경고하는 값을 그대로 물고 온다.
unclosed: bool = False
def _num(value: Any) -> float | None:
return float(value) if isinstance(value, (int, float)) else None
def _ratios(design: dict[str, Any]) -> dict[str, list[float]]:
"""역할별로 받아들일 경사비 목록. 2단 사면이면 암·토사 둘 다 절토로 본다."""
cut = [
value
for value in (
_num(design.get("cut_slope_ratio")),
_num(design.get("soil_cut_slope_ratio")),
)
if value is not None and value > 0
]
fill = [value for value in (_num(design.get("fill_slope_ratio")),) if value and value > 0]
return {"cut": cut, "fill": fill}
def _match(ratio: float, candidates: list[float]) -> float | None:
"""구간 경사비가 후보 중 하나와 맞으면 그 후보를 돌려준다."""
for candidate in candidates:
if abs(ratio - candidate) <= max(_RATIO_TOLERANCE * candidate, _RATIO_TOLERANCE):
return candidate
return None
def _outward(
line: list[dict[str, float]], edge_offset: float, side: str
) -> list[tuple[float, float, float, float]]:
"""노체 끝에서 **바깥으로** 향하는 구간 목록 `(시작오프셋, 끝오프셋, run, rise)`.
좌측은 오프셋이 커지는 쪽, 우측은 작아지는 쪽이 바깥이다(설계선 좌표 관례).
"""
points = sorted(
((float(p["offset_m"]), float(p["elevation_m"])) for p in line), key=lambda p: p[0]
)
if side == "left":
outer = [p for p in points if p[0] >= edge_offset]
else:
outer = [p for p in points if p[0] <= edge_offset][::-1]
return [
(
outer[i - 1][0],
outer[i][0],
abs(outer[i][0] - outer[i - 1][0]),
outer[i][1] - outer[i - 1][1],
)
for i in range(1, len(outer))
]
def slope_start_offset(design: dict[str, Any], side: str) -> float | None:
"""사면이 시작하는 오프셋 — 노체 끝, 측구가 있으면 **측구 바깥 끝**.
⚠ 이것이 없으면 **측구 바깥 벽이 사면으로 잡힌다.** 측구 벽 경사가 토사 절토비와 같으면
그대로 걸린다. 측구는 노체 배수 시설이지 사면이 아니므로 그 바깥 끝에서부터 세어야 한다.
"""
edges = design.get("road_edges") or {}
edge = _num((edges.get(side) or {}).get("offset_m"))
if edge is None:
return None
if not design.get("ditch_enabled"):
return edge
ditch_side = design.get("ditch_side")
if ditch_side not in (side, "both", None):
return edge
width = _num((design.get("ditch") or {}).get("top_width_m")) or 0.0
# 좌측은 오프셋이 커지는 쪽, 우측은 작아지는 쪽이 바깥이다.
return edge + width if side == "left" else edge - width
def _material(design: dict[str, Any], ratio: float) -> str | None:
"""경사비로 재료를 가른다 — 그린 대로 적는다(B06 `cut_slope_segments` 와 같은 규칙)."""
if not design.get("two_stage_slope"):
return None
rock = _num(design.get("cut_slope_ratio"))
soil = _num(design.get("soil_cut_slope_ratio"))
if rock is None or soil is None or abs(rock - soil) < 1e-9:
return None
return "rock" if abs(ratio - rock) < abs(ratio - soil) else "soil"
def _side_segments(
design: dict[str, Any], side: str, ratios: dict[str, list[float]]
) -> list[SlopeSegment]:
"""한쪽 사면 구간 목록. 경사비가 안 맞는 구간을 만나면 거기서 멈춘다."""
line = design.get("design_line") or []
edge = slope_start_offset(design, side)
if not line or edge is None:
return []
berm = design.get("berm") or {}
berm_width = _num(berm.get("width_m")) or 0.0
# 소단 안쪽 기울기(°) 만큼은 평탄부로 봄 — 기울인 소단이 비탈로 읽혀 끊기지 않게.
berm_grade = math.tan(math.radians(_num(berm.get("slope_deg")) or 0.0))
# 설계선 표고는 넷째 자리 반올림 — 기울인 소단 조각이 그만큼 더 가파르게 읽힘.
berm_slack = 2e-4 if berm_width > 0 else 0.0
segments: list[SlopeSegment] = []
started = False
# ⚠ 설계선이 격자(0.5m)로 찍혀 소단 평탄부가 **여러 조각**으로 쪼개짐 — 이어진 평탄 조각을 모아
# 합이 소단 폭일 때만 소단으로 넘김(한 조각만 보면 첫 소단에서 사면이 끊긴다).
flat_run = 0.0
for start, end, run, rise in _outward(line, float(edge), side):
if run <= 1e-9:
continue
if abs(rise) <= _FLAT_RISE_M + run * berm_grade + berm_slack:
# 평탄부 — 측구 바닥·소단. 사면이 시작된 뒤라면 모아 두고 다음 조각에서 판정.
if started:
flat_run += run
continue
if flat_run > 0:
if not (berm_width > 0 and abs(flat_run - berm_width) < 0.05):
break # 사면이 끝나고 평지를 만난 것이다
flat_run = 0.0
ratio = run / abs(rise)
# 절토는 바깥으로 갈수록 오르고, 성토는 내려간다.
role = "cut" if rise > 0 else "fill"
matched = _match(ratio, ratios[role])
if matched is None:
if started:
break # 원지반에 닿았다
continue # 아직 노체·측구 구간이다
started = True
segments.append(
SlopeSegment(
side=side,
role=role,
from_offset_m=start,
to_offset_m=end,
rise_m=rise,
length_m=math.hypot(run, rise),
ratio=matched,
material=_material(design, matched),
)
)
return segments
def _roadbed_width(design: dict[str, Any]) -> float | None:
"""노면 폭 — 노체 끝 좌(+)·우(−) 오프셋 사이. 한쪽이라도 없으면 `None`."""
edges = design.get("road_edges") or {}
left = _num((edges.get("left") or {}).get("offset_m"))
right = _num((edges.get("right") or {}).get("offset_m"))
return None if left is None or right is None else abs(left - right)
def station_slope(chainage_m: float, design: dict[str, Any]) -> StationSlope:
"""측점 하나의 사면길이. 좌우를 합쳐 절토·성토 각각의 총 사면길이를 낸다."""
ratios = _ratios(design)
segments: list[SlopeSegment] = []
for side in ("left", "right"):
segments.extend(_side_segments(design, side, ratios))
berm = design.get("berm") or {}
fill_by_side = {
side: sum(abs(s.rise_m) for s in segments if s.role == "fill" and s.side == side)
for side in ("left", "right")
}
# 2단 비탈은 경사비가 토사·암을 가름 · 1단은 그 측점 설계의 지반 프리셋(토사/암)이 비탈 전체
preset = {"soil": "soil", "rock": "rock"}.get(str(design.get("geometry_preset") or ""))
cut_by = {"soil": 0.0, "rock": 0.0}
for segment in segments:
material = segment.material or preset
if segment.role == "cut" and material in cut_by:
cut_by[material] += segment.length_m
return StationSlope(
chainage_m=float(chainage_m),
cut_length_m=sum(s.length_m for s in segments if s.role == "cut"),
cut_soil_length_m=cut_by["soil"],
cut_rock_length_m=cut_by["rock"],
fill_length_m=sum(s.length_m for s in segments if s.role == "fill"),
# ⚠ 없는 측점은 0 이다 — 성토 사면길이로 **대신 채우지 않는다**(면이 다름).
bench_cut_length_m=_num(design.get("bench_cut_length_m")) or 0.0,
fill_height_m=max(fill_by_side.values(), default=0.0),
roadbed_width_m=_roadbed_width(design),
berm_width_m=_num(berm.get("width_m")) or 0.0,
segments=tuple(segments),
unclosed=bool(design.get("slope_unclosed")),
)
def series_key(series: str, face: str) -> str:
"""계열·면 묶음 키. 옛 `B08_Quantity_Engine_SlopeArea._key` 와 같은 글자를 낸다."""
return f"{series}_{face}"
def length_of(slope: StationSlope, series: str, face: str) -> float:
"""계열·면별 「거리」 = 그 측점의 사면길이.
법면보호공은 면고르기를 참조한다 — 같은 사면길이를 쓴다. 끊고 싶으면 이 함수만 고친다.
층따기는 성토면만 대상이다.
"""
if series == "bench_cut":
# ⚠ 층따기는 **원지반 표면**을 깎는 일이라 밑수가 성토 비탈면이 아니다(교본 6장 4절).
# B06 설계가 측점마다 내는 값을 그대로 쓴다. 없으면 0 — 성토 사면길이로 대신 채우면
# **다른 면을 세게 된다**.
return slope.bench_cut_length_m if face == "fill" else 0.0
return slope.fill_length_m if face == "fill" else slope.cut_length_m
File diff suppressed because it is too large Load Diff
+15 -82
View File
@@ -1,106 +1,39 @@
/* =============================================================================
* B09_Estimation_UI_Shell.ts
* 로그인 후 09: 6차 워크플로우 (원가계산) — 화면 **틀** (PLAN 12장 · 2026-09-14 브레인 판정)
* 로그인 후 09: 6차 워크플로우 (원가계산) — **빈 화면** (PLAN 7-3)
*
* - 틀은 탭 줄과 등록만. 탭마다 파일 하나(`B09_Estimation_UI_Tab_<이름>.ts`) — 계약은 `_Shell_Types`.
* - ⚠ 등록 권한 = 랩탑_서브. 다른 창은 탭 파일을 만들고 이름을 알려 등록을 부탁함.
* - 탭을 고를 때마다 본문·좌측 칸을 비우고 `render(ctx, arg)`. `ctx.open(key, arg)` = 다른 탭으로 들어가기.
* - 옛 원가계산 코드는 통째로 `old_code/B09_Estimation/` 에 있음(지우지 않음).
* - 다시 짤 때까지 메뉴와 주소만 남김 — 제목·단계 막대만 뜨고 탭·계산은 없음.
* ========================================================================== */
import { createWorkflowLayout } from "@ui/ui_template_workflow_layout";
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
import { CURRENT_PROJECT_ID_KEY } from "@config/config_frontend";
import { workflowSteps } from "../A00_Common/b_page_scaffold";
import { goToWorkflowStage, WORKFLOW_STEP_ROUTES } from "../A00_Common/b_workflow_nav";
import type { B09Tab, B09TabContext } from "./B09_Estimation_UI_Shell_Types";
import { L, el, injectSheetStyles } from "./B09_Estimation_UI_Sheet";
import { costSheetTab } from "./B09_Estimation_UI_Tab_CostSheet";
import { rateTableTab } from "./B09_Estimation_UI_Tab_RateTable";
import { billTab } from "./B09_Estimation_UI_Tab_Bill";
import { unitPriceTab } from "./B09_Estimation_UI_Tab_UnitPrice";
import { priceBasisTab } from "./B09_Estimation_UI_Tab_PriceBasis";
import { machineTab } from "./B09_Estimation_UI_Tab_Machine";
import { priceCompareTab } from "./B09_Estimation_UI_Tab_PriceCompare";
import { materialPricesTab } from "./B09_Estimation_UI_Tab_MaterialPrices";
import { summaryTab } from "./B09_Estimation_UI_Tab_Summary";
import { listsTab } from "./B09_Estimation_UI_Tab_Lists";
import { designDocTab } from "./B09_Estimation_UI_Tab_DesignDoc";
import { basisSheetTab } from "./B09_Estimation_UI_Tab_BasisSheet";
import { supplyTab } from "./B09_Estimation_UI_Tab_Supply";
import { baseDataTab } from "./B09_Estimation_UI_Tab_BaseData";
import { contractTab } from "./B09_Estimation_UI_Tab_Contract";
import { executionTab } from "./B09_Estimation_UI_Tab_Execution";
import { progressTab } from "./B09_Estimation_UI_Tab_Progress";
import { completionTab } from "./B09_Estimation_UI_Tab_Completion";
/** 탭 등록 — 한 줄에 탭 하나. */
const TABS: B09Tab[] = [
costSheetTab, // 랩탑_메인
rateTableTab, // 랩탑_메인
billTab,
unitPriceTab,
priceBasisTab,
machineTab,
priceCompareTab,
materialPricesTab, // 랩탑_메인 — 자재단가대비표 옆(자재 수동 단가)
summaryTab,
listsTab,
supplyTab,
baseDataTab,
designDocTab,
basisSheetTab,
contractTab, // 랩탑_메인 — 설계 뒤 계약 단계라 맨 끝
executionTab, // 랩탑_메인 — 계약 뒤 실행 단계
progressTab, // 랩탑_메인 — 실행 뒤 기성 단계
completionTab, // 랩탑_메인 — 기성 뒤 준공 단계
];
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
}
export async function renderB09Estimation(root: HTMLElement): Promise<void> {
injectSheetStyles();
export function renderB09Estimation(root: HTMLElement): void {
const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY);
const page = el("div", "b09s-page");
const bar = el("div", "b09s-tabs");
const body = el("div", "b09s-body");
const panel = el("div");
page.append(bar, body);
let active = TABS[0].key;
const open = (key: string, arg?: string): void => {
const tab = TABS.find((item) => item.key === key);
if (!tab) return;
active = key;
drawBar();
body.replaceChildren();
panel.replaceChildren();
const ctx: B09TabContext = { projectId, body, panel, root, open };
tab.render(ctx, arg);
};
const drawBar = (): void => {
bar.replaceChildren(
...TABS.map((tab) => {
const button = el(
"button",
`b09s-tab${tab.key === active ? " is-active" : ""}`,
tab.label(),
);
button.type = "button";
button.dataset.tab = tab.key;
button.addEventListener("click", () => open(tab.key));
return button;
}),
);
};
const note = document.createElement("p");
note.className = "b09-estimation__rebuilding";
note.textContent = L("B09_Estimation_Rebuilding");
const body = document.createElement("div");
body.append(note);
const layout = createWorkflowLayout({
title: L("B09_Estimation_Title"),
steps: workflowSteps(),
activeStep: 6,
leftPanel: panel,
mainContent: page,
mainContent: body,
routes: WORKFLOW_STEP_ROUTES,
onStepClick: (stepIndex) => {
onStepClick: (stepIndex: number) => {
if (projectId) goToWorkflowStage(projectId, WORKFLOW_STEP_ROUTES[stepIndex]);
},
});
root.append(layout.root);
open(active);
}
+1 -28
View File
@@ -60,21 +60,6 @@ from B06_Section.B06_Section_Router_HaulPlan import (
)
from B07_DesignDetail.B07_DesignDetail_Router import router as b07_design_router
from B07_DesignDetail.B07_DesignDetail_Router_Frame import router as b07_frame_router
from B08_Quantity.B08_Quantity_Router import router as b08_quantity_router
from B08_Quantity.B08_Quantity_Router_Earthwork import router as b08_earthwork_router
from B08_Quantity.B08_Quantity_Router_Material import router as b08_material_router
from B08_Quantity.B08_Quantity_Router_StructureSheet import router as b08_structure_sheet_router
from B08_Quantity.B08_Quantity_Router_StmateLibrary import router as b08_stmate_library_router
from B09_Estimation.B09_Estimation_Router import router as b09_estimation_router
from B09_Estimation.B09_Estimation_Router_Contract import router as b09_contract_router
from B09_Estimation.B09_Estimation_Router_Execution import router as b09_execution_router
from B09_Estimation.B09_Estimation_Router_Progress import router as b09_progress_router
from B09_Estimation.B09_Estimation_Router_CostSheet import router as b09_cost_sheet_router
from B09_Estimation.B09_Estimation_Router_Edits import router as b09_edits_router
from B09_Estimation.B09_Estimation_Router_Factors import router as b09_factors_router
from B09_Estimation.B09_Estimation_Router_MaterialPrices import (
router as b09_material_prices_router,
)
from M01_MasterData.M01_MasterData_Router import router as m01_master_data_router
from common_util.common_util_audit import note_api_call, record_call_burst
from common_util.common_util_auth import (
@@ -643,19 +628,7 @@ app.include_router(b06_section_confirm_router, dependencies=protected_with_compa
app.include_router(b06_section_haul_plan_router, dependencies=protected_with_company)
app.include_router(b07_design_router, dependencies=protected_with_company)
app.include_router(b07_frame_router, dependencies=protected_with_company)
app.include_router(b08_quantity_router, dependencies=protected_with_company)
app.include_router(b08_earthwork_router, dependencies=protected_with_company)
app.include_router(b08_material_router, dependencies=protected_with_company)
app.include_router(b08_structure_sheet_router, dependencies=protected_with_company)
app.include_router(b08_stmate_library_router, dependencies=protected_with_company)
app.include_router(b09_estimation_router, dependencies=protected_with_company)
app.include_router(b09_cost_sheet_router, dependencies=protected_with_company)
app.include_router(b09_contract_router, dependencies=protected_with_company)
app.include_router(b09_execution_router, dependencies=protected_with_company)
app.include_router(b09_progress_router, dependencies=protected_with_company)
app.include_router(b09_edits_router, dependencies=protected_with_company)
app.include_router(b09_factors_router, dependencies=protected_with_company)
app.include_router(b09_material_prices_router, dependencies=protected_with_company)
# B08 수량·B09 원가계산 라우터 13 개는 끊음 — 코드는 `old_code/` 에 있고 화면은 빈 틀만 뜬다(PLAN 7-3).
# 마스터 데이터 — 회사·프로젝트가 아니라 시스템 관리자만 본다.
system_admin_only = [Depends(verify_session), Depends(require_system_admin)]
app.include_router(m01_master_data_router, dependencies=system_admin_only)
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More