feat(B08): 암 시공법 칸 · 관급구분 표 입력 · 산출 크기 요약

- 암 시공법(ripping/blasting)을 갈래 비율 칸 아래에 붙임. 갈래 이름만으로는
  품셈 공종(암절취 FP-09-04 / 발파암 FP-09-05)을 못 고르던 자리. 기본은
  「안 정함」이고, 안 정하면 인계에서 사유와 함께 드러남. 비율 미입력 상태의
  「암」 한 줄에도 칸을 냄.
- 관급/사급은 표 안에서 줄마다 고름. 관급 줄에만 설치주체가 열리고 사급으로
  되돌리면 잠기며 비워짐. 만진 줄은 표시가 남음.
- 산출 요약(최소·중앙·최대)을 원단위·자재총괄·인계에 붙임. 단위별로 갈라 냄 —
  값이 있기만 하면 시험이 못 잡는 자릿수 어긋남을 사람이 훑게 하는 장치.

화면에서 걸려 고친 것 둘
- 관급을 골라도 설치주체 칸이 잠긴 채 남던 것. 고른 즉시 열고 닫게 함.
- 한 번 고른 시공법을 되돌릴 길이 없던 것. 설정 저장이 병합이라 빈 값을 보내도
  옛 값이 남았음. `save_section(replace_keys=…)` 로 되돌릴 수 있어야 하는 칸만
  통째로 갈아 끼움. 나머지는 그대로 병합.

앞 커밋에서 온 타입 오류 2건도 고침 (`slopeColumnCount` 미사용,
`variant: "outlined"` 는 없는 값). 앞선 확인에서 npx 가 엉뚱한 패키지를 실행해
「오류 없음」으로 잘못 봤음 — tsc 는 config/node_modules 것으로 부를 것.

검증 — 새 시험 5건 + 인계 28건 통과, 전체 509 passed. tsc 오류 0.
화면 실조작으로 시공법 저장·되돌리기, 관급/설치주체 저장·되돌리기 확인 후
검증으로 바꾼 값은 원래대로 복원.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 00:18:00 +09:00
co-authored by Claude Opus 5
parent ab39c174aa
commit c7d917864c
12 changed files with 402 additions and 28 deletions
+36 -4
View File
@@ -33,7 +33,7 @@ from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from typing import Any, Iterable
from common_util.common_util_json import atomic_write_json
@@ -57,6 +57,17 @@ ROCK_CLASS_SETS: dict[str, tuple[str, ...]] = {
}
DEFAULT_ROCK_CLASS_SET = "geochang5"
# 암 시공법 — 품셈이 공종을 가르는 기준. `None` 은 「아직 안 정함」이고 기본값이다.
ROCK_METHOD_RIPPING = "ripping" # 긁어내기 — 암절취
ROCK_METHOD_BLASTING = "blasting" # 터뜨리기 — 발파암
ROCK_METHODS = (ROCK_METHOD_RIPPING, ROCK_METHOD_BLASTING)
def rock_method(settings: dict[str, Any], rock_class: str) -> str | None:
"""갈래 하나의 시공법. 안 정했으면 `None` — **기본값으로 때우지 않는다.**"""
value = (settings.get("rock_methods") or {}).get(rock_class)
return value if value in ROCK_METHODS else None
def default_settings() -> dict[str, Any]:
"""빈 설정. `estimation` 은 **자리만** 만든다 — 채우는 것은 B09 몫이다."""
@@ -68,10 +79,17 @@ def default_settings() -> dict[str, Any]:
# 갈래별 비율(%). 설계자가 넣는 값이라 기본은 비워 둔다 —
# 측점별 암질 판정에 기대지 않는다는 것이 8-1 사용자 확정이다.
"rock_ratios_pct": {},
# 갈래별 **시공법** — `{갈래이름: "ripping"|"blasting"}`.
# ⚠ 갈래 이름(연암·보통암…)만으로는 **긁어내는 암인지 터뜨리는 암인지** 알 수 없고,
# 품셈은 그 둘을 다른 공종으로 둔다(암절취 FP-09-04 / 발파암 FP-09-05).
# 기본은 **비워 둔다** — 찍으면 공종이 조용히 틀린다. 안 정하면 인계에서
# 「시공법 미지정」으로 드러난다(2026-09-07 일감 9 에서 드러난 자리).
"rock_methods": {},
"conversion_factors_override": None,
"haul_limits_m_override": None,
"application_ratios_pct": {key: 100 for key in APPLICATION_RATIO_KEYS},
# 자재총괄의 관급/사급 구분 — `{자재명: "public"|"private"}`.
# 자재총괄의 관급/사급 구분 — `{자재명: "owner_supplied"|"contractor_supplied"}`
# 또는 `{자재명: {"supply": …, "install_by": "contractor"|"owner"}}`.
# ⚠ **법이 아니라 발주 결정**이라 기본은 비워 둔다. 안 정한 자재는 「미분류」로
# 화면에 드러난다 — 사급으로 조용히 넘기면 관급자재대가 새 나간다.
"material_supply": {},
@@ -124,16 +142,30 @@ def _merge(base: dict[str, Any], stored: dict[str, Any]) -> dict[str, Any]:
SECTIONS = ("quantity", "estimation")
def save_section(project_root: str | Path, section: str, values: dict[str, Any]) -> dict[str, Any]:
def save_section(
project_root: str | Path,
section: str,
values: dict[str, Any],
*,
replace_keys: Iterable[str] = (),
) -> dict[str, Any]:
"""한 구획만 갈아 끼운다 — 남의 구획은 **손대지 않는다**.
두 페이지가 같은 파일을 쓰므로 통째로 덮으면 상대 값이 사라진다. 그래서 **통째로 쓰는
함수를 두지 않는다** — 쓰려면 반드시 구획 이름을 대야 한다.
⚠ `replace_keys` — **지울 수 있어야 하는 칸**은 병합이 아니라 통째로 갈아 끼운다.
「고른 값을 안 정함으로 되돌리기」가 병합으로는 안 되기 때문이다(2026-09-07 화면에서
걸린 자리 — 시공법을 한 번 고르면 되돌릴 길이 없었다).
"""
if section not in SECTIONS:
raise ValueError(f"모르는 구획: {section} (쓸 수 있는 것: {', '.join(SECTIONS)})")
settings = load_settings(project_root)
settings[section] = _merge(settings.get(section) or {}, values)
merged = _merge(settings.get(section) or {}, values)
for key in replace_keys:
if key in values:
merged[key] = values[key]
settings[section] = merged
settings["schema_version"] = SCHEMA_VERSION
atomic_write_json(settings_path(project_root), settings)
return settings