목록에만 있고 화면에 없으면 사용자는 그것이 잠정인 줄도 모름. 셋 다 「지금 어떤 값으로 돌고 있는지 + 왜 잠정인지」를 함께 보임. - 콘크리트 타설 방식을 좌측 패널 칸으로 냄. ⚠ 금액에 바로 걸리는 값이라 기본값으로 돌고 있으면 「기본값 「레디믹스트」로 계산 중 — 아직 안 정한 값」 안내를 띄움. 설정 기본을 None 으로 바꿔 「안 정함」과 「일부러 레디믹스트를 고른 것」을 가름 — 값을 미리 넣으면 그 구별이 사라짐. 되돌리기도 됨. - 물구멍 근거에 잠정값을 적음 — 「관 Ø 미정(법 3~6㎝ / 실무 Ø50) · 간격 2.0㎡당 1개소(법 2~3㎡당 1개소 이상)」. 「미확정」만으로는 무엇을 정해야 하는지 모름. - 준비공의 벌목 줄에 공종 미확정 사유와 후보를 함께 적음(수확베기·단목베기· 위험목 베기 중 어느 것인지 원본이 말하지 않음). 검증 — 전체 580 passed, tsc 오류 0. 화면에서 셋 다 뜨는 것과 타설 방식 저장·되돌리기까지 확인 후 검증으로 바꾼 값은 원래대로 복원. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
143 lines
6.0 KiB
Python
143 lines
6.0 KiB
Python
"""준비공·사방공 — **자리를 만들되 없는 값을 지어내지 않는다** (B08 일감 ⑪ · PLAN 8-3).
|
||
|
||
8-3 대응표에서 ❌ 로 남아 있던 둘이다. 여기서 하는 일은 **줄을 세우고, 설 수 있는 줄은
|
||
값을 채우고, 못 서는 줄은 왜 못 서는지 적는 것**이다. 빈 표를 내면 「빠뜨린 것」과
|
||
「원래 없는 것」이 구별되지 않는다.
|
||
|
||
⚠⚠ 지장목제거와 겹치지 않는다 (이중계상)
|
||
벌목·지장목제거는 **이미 토공집계의 사면 계열로 서 있다**(`tree_removal_*` × 반영률).
|
||
여기서 또 세우면 같은 나무를 두 번 벤다. 그래서 준비공의 벌목 줄은 **값을 내지 않고
|
||
「토공집계 지장목제거로 이미 섬」이라고 가리키기만** 한다.
|
||
|
||
⚠ 값이 없는 줄의 사유를 적는다
|
||
· 표토제거(9-15) — 면적은 사면적에서 나오나 **두께·대상 구간이 설계로 안 정해져 있다**.
|
||
· 제근·뿌리다듬기(9-20~21) — 단위가 **「개」(그루 수)**인데 입목 본수를 우리가 안 든다.
|
||
· 규준틀(11-2) — **개소** 산정 기준(구조물·절성토 구간별 몇 개소)이 안 정해져 있다.
|
||
|
||
⚠ 사방공은 이 노선에 실물이 없으면 「해당 없음」이다
|
||
있는 것처럼 0 을 적지 않는다. 구조물 목록에 사방 시설이 서면 그때 값이 선다.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any, Iterable
|
||
|
||
#: 사방 시설로 보는 구조물 종류 — **레지스트리의 실제 `type_id` 를 쓴다**(D 그룹 + 흙막이).
|
||
#: 목록에 없으면 그 노선에 사방공이 **없는** 것이다. 이름을 지어내면 영영 안 걸린다.
|
||
EROSION_CONTROL_TYPES = frozenset(
|
||
{
|
||
"erosion_check", # 골막이
|
||
"bed_sill", # 바닥막이
|
||
"check_dam_small", # 소형사방댐(복합형)
|
||
"revetment", # 기슭막이
|
||
"soil_guard", # 흙막이
|
||
}
|
||
)
|
||
|
||
STATUS_COUNTED_ELSEWHERE = "다른 표에서 이미 섬"
|
||
STATUS_PENDING = "값을 낼 근거가 없음"
|
||
STATUS_NOT_APPLICABLE = "해당 없음"
|
||
STATUS_READY = "값 있음"
|
||
|
||
|
||
def preparation_rows(slope_totals: dict[str, float] | None = None) -> list[dict[str, Any]]:
|
||
"""준비공 줄 — 값이 서는 것과 안 서는 것을 **한 목록에** 낸다."""
|
||
slope = slope_totals or {}
|
||
tree_area = float(slope.get("tree_removal_fill", 0.0)) + float(
|
||
slope.get("tree_removal_cut", 0.0)
|
||
)
|
||
return [
|
||
{
|
||
"group": "준비공",
|
||
"item": "벌목·지장목제거",
|
||
"unit": "㎡",
|
||
"amount": None,
|
||
"status": STATUS_COUNTED_ELSEWHERE,
|
||
# ⚠ 값을 여기서 또 내면 같은 나무를 두 번 벤다. 참고로 면적만 보인다.
|
||
"reference_amount": tree_area,
|
||
"reason": (
|
||
"토공집계의 「지장목제거」로 이미 섬 — 여기서 또 세우면 이중계상. "
|
||
"⚠ 다만 **공종 미확정** — 품셈 4장이 벌목을 목적별로 갈라(수확베기·단목베기·"
|
||
"위험목 베기) 임도 지장목이 어디에 붙는지 원본이 말하지 않음. 지금은 공종코드 없이 감."
|
||
),
|
||
"work_item_code": None,
|
||
},
|
||
{
|
||
"group": "준비공",
|
||
"item": "표토제거",
|
||
"unit": "㎥",
|
||
"amount": None,
|
||
"status": STATUS_PENDING,
|
||
"reason": "면적은 사면적에서 나오나 **두께·대상 구간**이 설계로 안 정해져 있음 (품셈 9-15)",
|
||
"work_item_code": "FP-09-15",
|
||
},
|
||
{
|
||
"group": "준비공",
|
||
"item": "제근·뿌리다듬기",
|
||
"unit": "개",
|
||
"amount": None,
|
||
"status": STATUS_PENDING,
|
||
"reason": "단위가 「개」(그루 수)인데 입목 본수를 들고 있지 않음 (품셈 9-20~21)",
|
||
"work_item_code": "FP-09-21",
|
||
},
|
||
{
|
||
"group": "준비공",
|
||
"item": "규준틀",
|
||
"unit": "개소",
|
||
"amount": None,
|
||
"status": STATUS_PENDING,
|
||
"reason": "개소 산정 기준(구조물·절성토 구간별 몇 개소)이 안 정해져 있음 (품셈 11-2)",
|
||
"work_item_code": "FP-11-02",
|
||
},
|
||
]
|
||
|
||
|
||
def erosion_rows(structures: Iterable[dict[str, Any]] = ()) -> list[dict[str, Any]]:
|
||
"""사방공 줄 — 이 노선에 사방 시설이 **있을 때만** 값이 선다."""
|
||
found = sorted(
|
||
{
|
||
str(item.get("type_id"))
|
||
for item in structures
|
||
if str(item.get("type_id")) in EROSION_CONTROL_TYPES
|
||
}
|
||
)
|
||
if not found:
|
||
return [
|
||
{
|
||
"group": "사방공",
|
||
"item": "사방 시설",
|
||
"unit": "",
|
||
"amount": None,
|
||
"status": STATUS_NOT_APPLICABLE,
|
||
"reason": "이 노선에 사방 시설이 배치돼 있지 않음 — 있는 것처럼 0 을 적지 않음",
|
||
"work_item_code": None,
|
||
}
|
||
]
|
||
return [
|
||
{
|
||
"group": "사방공",
|
||
"item": type_id,
|
||
"unit": "개소",
|
||
"amount": None,
|
||
"status": STATUS_PENDING,
|
||
"reason": "구조물 원단위가 아직 없음 — 전개식·관측값 모두 미확보",
|
||
"work_item_code": None,
|
||
}
|
||
for type_id in found
|
||
]
|
||
|
||
|
||
def build_table(
|
||
slope_totals: dict[str, float] | None = None,
|
||
structures: Iterable[dict[str, Any]] = (),
|
||
) -> dict[str, Any]:
|
||
"""화면·인계가 그대로 쓰는 모양. **못 서는 줄도 목록에 남는다.**"""
|
||
rows = preparation_rows(slope_totals) + erosion_rows(structures)
|
||
return {
|
||
"columns": ["구분", "공종", "단위", "수량", "상태", "사유"],
|
||
"rows": rows,
|
||
"ready_count": sum(1 for row in rows if row["status"] == STATUS_READY),
|
||
"pending_count": sum(1 for row in rows if row["status"] == STATUS_PENDING),
|
||
"row_count": len(rows),
|
||
}
|