Files
Aislo/B09_Estimation/B09_Estimation_DesignDocIndex.py
T
eomsangdonandClaude Opus 5 89effeca07 feat(B09): 산출기초 — 줄에 달린 근거를 한 장으로 접음
별표2 (5)(가) 열셋째. 근거는 줄마다 이미 있었고 묶는 자리만 없었음.
원가계산에 「산출기초」 탭으로 세움. 넷으로 접음 —
① 어느 판으로 계산했나(데이터 기준일·지문) ② 무엇을 골랐나(고른 값만)
③ 공종마다 무엇을 근거로 했나(줄 문구 그대로) ④ 못 채운 자리(0 으로 안 때운 자리).

- 판 목록은 장부(_manifest.json)를 그대로 읽음 — 목록을 따로 적으면 한쪽만 고쳐짐.
- ⚠ 여기서 값을 다시 계산하지 않음 — 금액 칸이 아예 없음(두 벌 방지, 시험으로 못 박음).

⇒ 「설계서 구성」의 산출기초가 반쪽 → 있음. 법이 정한 13 중 9 가 서고,
  우리가 더 낼 것은 공사설명서 하나(서식·설계하중 표기는 사용자에게 받아야 함).

곁들여: 자재총괄의 「미분류」를 「미정(발주기관 결정)」으로 고침 — 발주기관이 정할
자리인데 우리가 못 만든 것처럼 읽히던 문구(V-14). 값·판정은 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 00:06:22 +09:00

192 lines
7.7 KiB
Python

"""설계서 구성표 — **법이 정한 목차와 우리가 내는 것을 맞대 보는 표** (2026-09-09).
**왜 있나** — 「무엇을 내야 하나」가 법에 목록으로 박혀 있는데, 우리가 그중 무엇을 내고
무엇을 못 내는지가 **계획서에만** 있었다. 설계서를 묶는 사람이 화면에서 바로 봐야 한다.
산림자원법 시행규칙 [별표2] (5)(가)
「설계서는 **목차·공사설명서·일반시방서·특별시방서·예정공정표·예산내역서·일위대가표·
단가산출서·각종중기경비계산서·공종별 수량계산서·각종 소요자재총괄표·토적표·산출기초**
순으로 작성한다」
⚠ **법이 목차를 정했다고 그 열셋을 다 프로그램이 만들 것은 아니다.** 시방서·예정공정표는
**설계자·발주청이 쓰는 문서**다. 그래서 줄마다 「누가 만드나」를 함께 적는다 —
못 내는 것과 **애초에 우리 몫이 아닌 것**을 갈라야 다음에 할 일이 달라진다.
⚠ **사방사업은 목록이 다르다** — 사방사업법 시행규칙 [별표0] 은 **위치도·관계지적조서·
공사원가계산서·설계도면**을 더 두고 예산내역서 대신 「설계내역서」라 적는다. 지금 이 표는
**임도(별표2)** 기준이다.
"""
from __future__ import annotations
from typing import Any
#: 상태 — 세 갈래. 「없음」과 「우리 몫 아님」을 **갈라 적는다.**
STATUS_READY = "있음"
STATUS_PARTIAL = "반쪽"
STATUS_MISSING = "없음"
OWNER_PROGRAM = "프로그램"
OWNER_DESIGNER = "설계자·발주청"
LAW_SOURCE = (
"산림자원의 조성 및 관리에 관한 법률 시행규칙 [별표2] 산림관리기반시설의 설계 및 시설기준"
" (5)(가) — 설계서 작성 순서"
)
#: 별표2 가 적은 **그 차례 그대로**. 순서를 바꾸지 않는다(법이 순서를 정한 목록이다).
DESIGN_DOC_ITEMS: tuple[dict[str, Any], ...] = (
{
"order": 1,
"name": "목차",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "이 표(설계서 구성)",
"note": "법이 정한 차례대로 무엇이 서고 무엇이 안 서는지를 이 표가 그대로 보인다.",
},
{
"order": 2,
"name": "공사설명서",
"status": STATUS_MISSING,
"owner": OWNER_PROGRAM,
"where": "",
"note": (
"값은 거의 다 우리가 갖고 있다 — 공사명·총공사비(원가계산서) · 유효폭·노견·설계속도·"
"종단구배·최소곡선반경(설계 기준). 받아야 할 것은 서식과 설계하중 표기"
"(실무 거창은 「DB-18(32.45T)」로 적었는데 우리 값이 아니다)."
),
},
{
"order": 3,
"name": "일반시방서",
"status": STATUS_MISSING,
"owner": OWNER_DESIGNER,
"where": "",
"note": (
"표준시방서를 인용하는 문서다 — 프로그램이 지어낼 것이 아니다. "
"원문도 아직 안 갖고 있다(실무 자료에 「임도시설공사 표준시방서」가 있으나 미보유)."
),
},
{
"order": 4,
"name": "특별시방서",
"status": STATUS_MISSING,
"owner": OWNER_DESIGNER,
"where": "",
"note": "그 현장의 특기사항을 설계자가 쓴다 — 현장을 아는 사람만 쓸 수 있는 문서다.",
},
{
"order": 5,
"name": "예정공정표",
"status": STATUS_MISSING,
"owner": OWNER_DESIGNER,
"where": "",
"note": (
"공기를 공종에 어떻게 나누는지는 설계 판단이다. 우리는 공사기간(일)만 받아 "
"요율 구간에 쓴다 — 그것으로 공정표를 지어내지 않는다."
),
},
{
"order": 6,
"name": "예산내역서",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "원가계산 → 설계내역서",
"note": "",
},
{
"order": 7,
"name": "일위대가표",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "원가계산 → 일위대가",
"note": "",
},
{
"order": 8,
"name": "단가산출서",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "원가계산 → 단가산출근거",
"note": "",
},
{
"order": 9,
"name": "각종 중기경비계산서",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "원가계산 → 중기(중기목록표 + 기종별 계산서)",
"note": (
"목록표가 「얼마」라면 계산서는 「왜 그 값인가」다 — 기종마다 취득가·내용시간·"
"손료계수(상각·정비·관리) · 주연료와 유가 · 조종원 일당과 환산을 그대로 보인다. "
"수송비는 「회당」으로 서는 별개 공종이라 이 장에서는 어디서 서는지만 가리킨다."
),
},
{
"order": 10,
"name": "공종별 수량계산서",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "수량산출 → 토공집계·구조물 원단위",
"note": "",
},
{
"order": 11,
"name": "각종 소요자재총괄표",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "수량산출 → 자재총괄",
"note": "",
},
{
"order": 12,
"name": "토적표",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "수량산출 → 토적표",
"note": "",
},
{
"order": 13,
"name": "산출기초",
"status": STATUS_READY,
"owner": OWNER_PROGRAM,
"where": "원가계산 → 산출기초",
"note": (
"줄에 달린 근거를 한 장으로 모은 장이다 — 어느 판으로 계산했나(데이터 기준일) · "
"무엇을 골랐나(산출 조건) · 공종마다 무엇을 근거로 했나 · 못 채운 자리. "
"여기서 값을 다시 계산하지 않는다."
),
},
)
def design_doc_index() -> dict[str, Any]:
"""설계서 구성표 한 장 — 법 순서·상태·누가 만드나·어디서 나오나."""
counts = {STATUS_READY: 0, STATUS_PARTIAL: 0, STATUS_MISSING: 0}
for item in DESIGN_DOC_ITEMS:
counts[item["status"]] += 1
ours_missing = [
item["name"]
for item in DESIGN_DOC_ITEMS
if item["owner"] == OWNER_PROGRAM and item["status"] != STATUS_READY
]
theirs = [item["name"] for item in DESIGN_DOC_ITEMS if item["owner"] == OWNER_DESIGNER]
return {
"law": LAW_SOURCE,
"items": [dict(item) for item in DESIGN_DOC_ITEMS],
"counts": counts,
"summary": (
f"법이 정한 {len(DESIGN_DOC_ITEMS)} 가운데 {counts[STATUS_READY]} 이 서 있고,"
f" {len(theirs)} 은 설계자·발주청이 쓰는 문서이며,"
f" 우리가 더 내야 할 것은 {len(ours_missing)} 입니다"
+ (f" — {' · '.join(ours_missing)}." if ours_missing else ".")
),
"notes": [
"⚠ 법이 목차를 정했다고 열셋을 다 프로그램이 만들 것은 아닙니다 —"
" 시방서·예정공정표는 현장을 아는 사람이 쓰는 문서입니다.",
"⚠ 사방사업은 목록이 다릅니다 — 사방사업법 [별표0] 은 위치도·관계지적조서·"
"공사원가계산서·설계도면을 더 둡니다. 이 표는 임도(별표2) 기준입니다.",
],
}