- 마스터 부모 94곳에 parent_mode — 기본 choose_one, 합산형은 사람이 적은 셋(9-4·9-5·12-38)만 단계·가중치 - 9-4 암절취 = 암파쇄(연암·보통암·경암, 브레이커+굴착기 조합 1/Q) + 집토(굴착기 0.7 공식) 합으로 조립 - 표에 없는 암질은 9-4-1 [주]① 평균으로만 섬 · 9-5 발파암은 발파 단계(착암기 층 없음) 사유로 막힘 - B08 인계가 흙깎기 암 갈래 이름을 갈래 값으로 넘김 · 갈래 고르기형 부모를 가리키는 줄은 오류로 막음 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
71 lines
3.2 KiB
Python
71 lines
3.2 KiB
Python
"""공종 마스터 — 부모 공종의 모양 `parent_mode` (명세 2장 · 2026-09-13 축 C Ⓐ).
|
|
|
|
아래 절이 있는 공종(부모)은 두 모양이고 규칙이 다르다.
|
|
|
|
choose_one 갈래 고르기형 — 잎 하나를 고른다. **부모에 금액을 붙이지 않는다.** (기본)
|
|
sum_steps 단계 합산형 — 내역 한 줄이 곧 부모이고, 일위대가는 **잎들의 합**으로 조립한다.
|
|
|
|
⚠ **자동 판정 금지** — 표 모양으로 짐작하면 조용히 틀린다. 합산형은 아래에 **사람이 적은 것**만.
|
|
⚠ 가중치(`weight`)도 사람이 적는다 — 원문 절 제목이 준 비율만(「발파 10%」·「깎기(90%)」).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
PARENT_CHOOSE_ONE = "choose_one"
|
|
PARENT_SUM_STEPS = "sum_steps"
|
|
|
|
#: 단계 합산형 부모 — (잎 코드, 가중치) 차례와 근거. ⚠ 여기 없는 부모는 전부 `choose_one`.
|
|
SUM_STEPS: dict[str, dict[str, Any]] = {
|
|
"FP-09-04": {
|
|
"steps": (("FP-09-04-01", "1"), ("FP-09-04-02", "1")),
|
|
"basis": (
|
|
"품셈 9-4 암절취 = 9-4-1 암파쇄 + 9-4-2 집토 — 같은 ㎥ 를 깨고 모음"
|
|
"(지식DB 토공_수량 「암절취 (암파쇄ㆍ집토) | 9-4」)"
|
|
),
|
|
},
|
|
"FP-09-05": {
|
|
"steps": (("FP-09-05-01", "0.1"), ("FP-09-05-02", "0.9"), ("FP-09-05-03", "1")),
|
|
"basis": (
|
|
"품셈 9-5 발파암 — 절 제목 「9-5-1 육상, 암석 절취(발파 10%)」·「9-5-2 깎기(90%)」·"
|
|
"「9-5-3 집토」(지식DB 토공_수량 「발파암 (절취 10 %ㆍ깎기 90 %ㆍ집토) | 9-5」)"
|
|
),
|
|
},
|
|
"FP-12-38": {
|
|
"steps": (("FP-12-38-02", "1"), ("FP-12-38-03", "1")),
|
|
"basis": (
|
|
"품셈 12-38 유로폼 = 12-38-2 사용수량(자재) + 12-38-3 설치 및 해체(품) — "
|
|
"12-38-1 사용횟수는 금액 단계가 아니라 사용수량의 잔존율 조건"
|
|
),
|
|
},
|
|
}
|
|
|
|
|
|
def apply_parent_modes(nodes: list[dict[str, Any]]) -> None:
|
|
"""부모 공종에 `parent_mode`(합산형이면 `steps`·`steps_basis` 까지)를 단다 — 자리에서.
|
|
|
|
⚠ 선언한 잎이 그 부모의 자식이 아니면 멈춘다 — 판이 바뀌어 절 번호가 옮겨 간 자리다.
|
|
"""
|
|
children: dict[str, list[str]] = {}
|
|
for node in nodes:
|
|
if node.get("parent_code"):
|
|
children.setdefault(node["parent_code"], []).append(node["work_item_code"])
|
|
for node in nodes:
|
|
code = node["work_item_code"]
|
|
if code not in children:
|
|
continue
|
|
declared = SUM_STEPS.get(code)
|
|
if declared is None:
|
|
node["parent_mode"] = PARENT_CHOOSE_ONE
|
|
continue
|
|
strays = [step for step, _ in declared["steps"] if step not in children[code]]
|
|
if strays:
|
|
raise ValueError(f"{code} 합산 단계가 자식이 아닙니다: {strays}")
|
|
node["parent_mode"] = PARENT_SUM_STEPS
|
|
node["steps"] = [{"code": step, "weight": weight} for step, weight in declared["steps"]]
|
|
node["steps_basis"] = declared["basis"]
|
|
missing = [code for code in SUM_STEPS if code not in children]
|
|
if missing:
|
|
raise ValueError(f"합산형으로 적은 부모가 마스터에 없습니다: {missing}")
|