- 개소를 넣어도 공종이 없어 단가가 안 서는 줄(국가지점번호판·안내판·차단기·수방대책 자재) — 「입력이 필요함」이면 넣고 기다려도 안 섬 - 개소가 선 줄은 자재총괄 사급 줄로 감 → 「자재 단가」 탭에 칸이 섬(화약류·치즐과 같은 통로) · 인계 공종 줄은 막힘 아님(두 번 안 셈) - 개소 안 넣은 줄은 종전대로 「입력이 필요함」 - 936be972: 국가지점번호판 3개소 넣음 → 셋째 상태 · 자재 단가 탭 「국가지점번호판 개소 3.0」 · 되돌림 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
139 lines
5.6 KiB
Python
139 lines
5.6 KiB
Python
"""준비공 — 부대시설·가설공사 다섯 줄.
|
|
|
|
⚠ `B08_Quantity_Engine_Preparation` 에서 갈라 나온 파일이다(2026-09-09, 700줄 제한).
|
|
**내용은 그대로 옮겼고 규칙도 그대로다** — 개소를 지어내지 않고, 「품셈에 공종이 없음」과
|
|
「개소 미입력」을 갈라 적으며, 값이 없어도 줄은 세운다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_Preparation_Status import (
|
|
REASON_NO_WORK_ITEM,
|
|
STATUS_NEEDS_INPUT,
|
|
STATUS_NO_WORK_ITEM,
|
|
STATUS_READY,
|
|
)
|
|
|
|
#: 공종 없는 줄에 개소가 들어온 뒤 할 일 — 자재총괄(사급) 줄로 가서 「자재 단가」 탭에 칸이 섬.
|
|
NO_WORK_ITEM_PRICE_PATH = "「자재 단가」 탭에 단가를 넣으면 자재총괄(사급) 줄로 금액이 섬"
|
|
|
|
#: 부대시설·가설공사 — **법이 요구하는데 우리가 안 내던 다섯 줄**(2026-09-09 사용자 확정 ⑬).
|
|
#: `key` 는 설정의 `ancillary_counts` 칸 이름, `code` 는 품셈 공종(없으면 `None`).
|
|
#: ⚠ 다섯 중 **품셈에 공종이 있는 것은 가설창고 하나뿐**이다(마스터 전수 확인).
|
|
#: 나머지 넷은 **금액이 못 선다** — 줄은 세우되 「공종 자체가 품셈에 없음」이라고 적는다.
|
|
#: 「아직 안 만든 것」과 갈라 적어야 다음에 할 일이 달라진다.
|
|
ANCILLARY_ITEMS: tuple[dict[str, Any], ...] = (
|
|
{
|
|
"key": "national_point_sign",
|
|
"item": "국가지점번호판",
|
|
"unit": "개소",
|
|
"code": None,
|
|
"legal": True,
|
|
"why": (
|
|
"⚠ 법정 의무 — 임도규정 제26조제5항 「국가지점번호판을 제작하여 500미터 마다 "
|
|
"설치·관리하되, 필요시 거리를 조정할 수 있으며」. ⚠ 기점 포함·종점 잔여·갈림길 "
|
|
"중복을 원문이 정하지 않아 **연장÷500 을 산식으로 쓰지 않는다** — 개소를 넣으면 섬"
|
|
),
|
|
},
|
|
{
|
|
"key": "guide_sign",
|
|
"item": "임도 안내판",
|
|
"unit": "개소",
|
|
"code": None,
|
|
"legal": True,
|
|
"why": (
|
|
"⚠ 법정 의무 — 임도규정 제26조제6항 「임도의 시점 및 종점에 안내판…을 설치하여야 "
|
|
"한다」. 노선을 이어 가면 최초 시점·최종 종점에 둘 수 있어 **개소는 설계 판단**임"
|
|
),
|
|
},
|
|
{
|
|
"key": "gate",
|
|
"item": "차단기",
|
|
"unit": "개소",
|
|
"code": None,
|
|
"legal": False,
|
|
"why": "임도기술교본 11장(실무 참고) — 법령·행정규칙에는 없음. 설치 개소는 설계 판단",
|
|
},
|
|
{
|
|
"key": "site_container",
|
|
"item": "가설창고(컨테이너)",
|
|
"unit": "개소",
|
|
"code": "FP-11-01",
|
|
"legal": False,
|
|
"why": "품셈 11-1 콘테이너형 가설건축물 — ⚠ 개소는 현장 조건이라 설계가 정함",
|
|
},
|
|
{
|
|
"key": "flood_supplies",
|
|
"item": "수방대책 자재",
|
|
"unit": "식",
|
|
"code": None,
|
|
"legal": False,
|
|
"why": (
|
|
"임도기술교본 11장 — 비닐·말뚝·마대·삽 등을 현장 입구에 비치. "
|
|
"품목·수량이 원문에 없어 **한 벌(식)로 받는다**"
|
|
),
|
|
},
|
|
)
|
|
|
|
#: 품셈에 그 이름의 공종이 아예 없는 줄에 적는 사유. 「아직 안 만든 것」과 갈라 쓴다.
|
|
|
|
|
|
def ancillary_rows(counts: dict[str, Any] | None = None) -> list[dict[str, Any]]:
|
|
"""부대시설·가설공사 줄. **개소를 안 넣어도 줄은 선다** — 빠진 것이 보이게.
|
|
|
|
⚠ 개소를 **지어내지 않는다**(확정 ⑬). 설정 `ancillary_counts` 에 넣은 값만 쓴다.
|
|
"""
|
|
given = {str(key): value for key, value in (counts or {}).items()}
|
|
rows: list[dict[str, Any]] = []
|
|
for spec in ANCILLARY_ITEMS:
|
|
raw = given.get(spec["key"])
|
|
try:
|
|
amount = float(raw) if raw is not None and str(raw).strip() != "" else None
|
|
except (TypeError, ValueError):
|
|
amount = None
|
|
reasons = [spec["why"]]
|
|
if spec["code"] is None:
|
|
reasons.append(REASON_NO_WORK_ITEM)
|
|
if amount is None:
|
|
reasons.append("개소가 아직 입력되지 않았습니다 — 넣으면 물량이 섭니다")
|
|
status = STATUS_NEEDS_INPUT
|
|
elif spec["code"]:
|
|
status = STATUS_READY
|
|
else:
|
|
reasons.append(NO_WORK_ITEM_PRICE_PATH)
|
|
status = STATUS_NO_WORK_ITEM
|
|
rows.append(
|
|
{
|
|
"group": "부대시설",
|
|
"item": spec["item"],
|
|
"unit": spec["unit"],
|
|
"amount": amount,
|
|
"status": status,
|
|
"work_item_code": spec["code"],
|
|
"legal_required": bool(spec["legal"]),
|
|
"reason": " · ".join(reasons),
|
|
}
|
|
)
|
|
return rows
|
|
|
|
|
|
def ancillary_material_rows(preparation_rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
"""공종 없는 부대시설 중 개소가 선 줄 → 자재총괄 성분(사급 기본) — 「자재 단가」 탭 통로.
|
|
|
|
⚠ 인계 공종 줄은 막힘 없이 `in_bill: False` 로 가므로 **여기 한 곳에서만** 금액이 선다.
|
|
"""
|
|
return [
|
|
{
|
|
"name": row["item"],
|
|
"spec": "",
|
|
"unit": row["unit"],
|
|
"amount": float(row["amount"]),
|
|
"destination": "material",
|
|
"source": str(row.get("group") or "부대시설"),
|
|
}
|
|
for row in preparation_rows
|
|
if row.get("status") == STATUS_NO_WORK_ITEM and row.get("amount")
|
|
]
|