- _Base(110줄) 성분 계약·갈 곳(DESTINATION)·배합 성분(MIX_COMPONENTS) — 이중계상 경계 - _StoneSpec(525줄) 돌쌓기 제원·계수표·표준경사 판정·벽 두께·버림/기초잡석 상수 - _Masonry(523줄) 돌쌓기·큰돌쌓기 전개식(버림·터파기 줄) - UnitQuantity(581줄) 종류→전개식 표·관측 원단위·딸린 줄·build_table — 옮긴 이름은 다시 내보내 부르는 쪽 44곳 그대로 - 코드 줄은 옮기기만 함 · 검증 프로젝트 응답 여섯(원단위·구조물 집계·구조물도·운반·인계·내역) 지문이 쪼개기 전과 같음 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
113 lines
5.7 KiB
Python
113 lines
5.7 KiB
Python
"""구조물 원단위 — **성분 계약과 갈 곳**(이중계상 경계) · 2026-09-14 `UnitQuantity` 에서 가름.
|
|
|
|
⚠⚠ 이 파일의 `DESTINATION`·`MIX_COMPONENTS` 가 이중계상 경계다 — 규칙 셋은 `UnitQuantity` 머리글.
|
|
㉢ 배합을 분해하지 않음(`MIX_COMPONENTS`) · ㉠ 할증 안 붙임 ·
|
|
터파기·되메우기·잔토는 토공으로(`DESTINATION`).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_ObservedUnit import BASIS_DERIVED
|
|
|
|
#: 기초잡석 줄 이름 — 갈 곳 표(`DESTINATION`)가 이 이름을 키로 씀. 두께 상수는 `_StoneSpec`.
|
|
RUBBLE_BASE_NAME = "기초잡석"
|
|
|
|
|
|
DESTINATION = {
|
|
"터파기": "earthwork",
|
|
"되메우기": "earthwork",
|
|
"잔토처리": "earthwork",
|
|
"돌쌓기": "unit_price",
|
|
"돌붙임": "unit_price",
|
|
"깬돌": "material",
|
|
"고임돌": "material",
|
|
"막자갈": "material",
|
|
# ⭐ 2026-09-09 사용자 확정 3차 ⑥ — **콘크리트는 자재 축에 세운다**(사용자 명시).
|
|
# ⚠ 타설 줄(품셈 12-1)은 **품만** 주고 재료를 안 준다(서브 일위대가도 재료 0원).
|
|
# 그래서 자재로 안 보내면 **재료비가 통째로 빠진다** — B09 매김에서 드러난 자리다.
|
|
# ⚠ 배합을 분해하지 않는 규칙(㉢)은 그대로다 — 「콘크리트 ㎥」에서 멈춘다.
|
|
"콘크리트": "material",
|
|
"채움콘크리트": "material",
|
|
"버림콘크리트": "material",
|
|
"모르터": "unit_price",
|
|
"거푸집": "unit_price",
|
|
"물구멍관": "material",
|
|
# ⚠ 자재도 토공도 아닌 자리 — **유토곡선이 사토에서 뺄 밑수**다. 자재총괄은
|
|
# `material` 만 모으므로 여기 섞이지 않는다.
|
|
"채집석": "haul_deduction", # ⚠ 자재 카탈로그가 이름으로 찾는다 — 공백 없는 한 낱말(B09 규약)
|
|
# ⚠ **보여 주기만 하는 줄** — 자재도 토공도 일위대가도 아니다. 정본 계산표 좌측 열에
|
|
# 「입적」으로 실려 있어 그 이름 그대로 낸다(2026-09-08 확정 ⑦). 값은 이미 식 안에
|
|
# 있던 것을 줄로 꺼낸 것뿐이고, `material`·`earthwork` 어디에도 안 섞인다.
|
|
# ⚠ 「석적」은 정본에 없고 소광리 시트에만 있으나 **확정 5차로 세운다** — 같은
|
|
# 보여 주기 줄이고, 「소광리에만 있는 줄」임을 사유에 적는다.
|
|
"입적": "reference",
|
|
"석적": "reference",
|
|
# 돌 줄은 **이름 「돌」 + 규격(`spec`)에 종류**다(명세 13장 Ⓒ) — 정본 계산표 줄 이름 그대로
|
|
# (「돌 ℓ3=45cm」). 자재총괄이 (이름·규격·단위)로 묶으므로 종류 이름을 따로 두지 않는다.
|
|
"돌": "material",
|
|
# 기초잡석(품셈 12-25) — 운반·부설·다짐 품이 붙는 **공종**이라 일위대가로 간다.
|
|
# 자재총괄로 보내면 같은 잡석이 재료로 한 번 더 선다.
|
|
RUBBLE_BASE_NAME: "unit_price",
|
|
}
|
|
|
|
# ⚠ 배합 성분 — 산출물에 나타나면 안 된다(㉢). B09 일위대가가 배합표로 분해한다.
|
|
# ⚠ **정확히 같은 이름**으로만 본다. 부분문자열로 재면 `막자갈`(뒤채움 재료)이 배합 `자갈` 로
|
|
# 오탐된다 — 개발 중 실제로 걸렸던 자리다.
|
|
MIX_COMPONENTS = frozenset(
|
|
{"시멘트", "모래", "자갈", "친모래", "친자갈", "잔골재", "굵은골재", "부순돌"}
|
|
)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class Component:
|
|
"""전개 결과 한 성분. `basis` 는 어떤 식으로 나왔는지 사람이 읽는 근거다."""
|
|
|
|
name: str
|
|
unit: str
|
|
amount: float
|
|
destination: str
|
|
basis: str = ""
|
|
# ⚠ 값이 어디서 왔나 — `derived`(치수에서 식으로) / `observed`(실무 관측 원단위표).
|
|
# 두 근거가 한 표에 섞이므로 줄마다 단다. 안 적으면 나중에 못 되짚는다.
|
|
basis_kind: str = BASIS_DERIVED
|
|
source: str = ""
|
|
#: 규격 — 같은 이름이라도 단가가 갈리는 값(채움 콘크리트 강도 등). 받는 쪽이 읽는다.
|
|
spec: str = ""
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class StructureQuantity:
|
|
"""구조물 하나의 원단위 전개 결과."""
|
|
|
|
structure_id: str | None
|
|
type_id: str
|
|
name: str
|
|
length_m: float = 0.0
|
|
height_m: float = 0.0
|
|
# 측점 — 내역 줄에 「어디부터 어디까지」를 적으려면 여기서 따라가야 한다(B09 인계).
|
|
start_m: float | None = None
|
|
end_m: float | None = None
|
|
# 저장된 제원 — **형식(반중력식…)처럼 뒤 단계가 봐야 하는 값**이 여기 있다.
|
|
# 치수를 다시 쓰라는 뜻이 아니라 **읽으라고** 실어 나른다(치수 정본은 여전히 하나).
|
|
options: dict[str, Any] = field(default_factory=dict)
|
|
components: list[Component] = field(default_factory=list)
|
|
notes: list[str] = field(default_factory=list)
|
|
#: 내역 줄이 설 **단위와 그 단위로 센 수량**. 관측 원단위가 「개소당」·「㎡당」인
|
|
#: 종류는 연장(m)으로 세면 축이 어긋난다(2026-09-08 ㉕ 실증).
|
|
#: 비어 있으면 종전대로 「m · 연장」으로 선다.
|
|
billing_unit: str = ""
|
|
billing_quantity: float = 0.0
|
|
#: 구조물이 놓인 자리의 지반 갈래(`soil`·`ripping_rock`·`blasting_rock`)와 그 판정 근거.
|
|
#: 품셈 9-13 구조물터파기의 **토질 축**이 이 값으로 갈린다. 못 가르면 `None` 이다.
|
|
ground_type: str | None = None
|
|
ground_type_basis: str = ""
|
|
#: 양식으로 성분을 세웠으면 그 양식 이름(PLAN 3장 ④-2). 비면 지금 전개 값.
|
|
library_item: str = ""
|
|
|
|
|
|
def _num(value: Any, fallback: float = 0.0) -> float:
|
|
return float(value) if isinstance(value, (int, float)) else fallback
|