① 버그 — BillRow.note 한 칸에 덮어쓰던 13곳·이어 붙이던 7곳을 조각 배열 notes 로 옮김. 한 줄에 사유가 둘이면 하나가 조용히 사라지던 것이 멈춤. 조각마다 닿는 열 키를 함께 실어 호버가 그 칸에만 띄우게 함. 화면 비고 칸은 종전과 같은 꼴 유지. ② 사전 — B09_Estimation_Provenance.py 신설(기존 B09 파일이 700줄 초과). 8장 57열. 이미 있던 formula_text·source_label·base_label 은 그대로 쓰고 없는 것만 새로 적음. ③ 배선 — 라우터 5개 응답에 _with_provenance(), 표 여섯에 markProvenanceCell + attachProvenance. 개발환경이 아니면 응답에 칸 자체가 안 생김(로직 보안). ④ 등급색 토글을 탭 줄 끝에. 사전이 안 오면 단추도 안 세움. ⚠ 원가계산서 금액은 같은 열에서 중간줄과 마지막줄의 성격이 갈리는데 등급이 열에 하나뿐이라 calc 로 두고 rule 에 어느 줄이 final 인지 적음(PLAN 8-36 ① 에 남김). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
479 lines
22 KiB
Python
479 lines
22 KiB
Python
"""B09 원가 화면의 **근거 사전** — 어느 숫자가 어디서 와서 어떻게 나왔나 (PLAN 8-36 ④).
|
||
|
||
⚠⚠ **개발 전용.** 사전은 `provenance_payload()` 를 거쳐 나가고, 개발환경이 아니면 `None`
|
||
이라 응답에 칸 자체가 안 생긴다. 화면에서 숨기는 것이 아니라 **안 보내는 것**이다.
|
||
|
||
왜 이 파일인가
|
||
「식」과 「원천」의 정답은 값을 낳는 엔진이 안다. 화면 TS 에 손으로 적어 두면 엔진을
|
||
고칠 때 설명만 옛것으로 남는다. 엔진 옆에 두어 같이 눈에 들어오게 한다.
|
||
⚠ `B09_Estimation_UI_Page.ts`(1415줄)·`B09_Estimation_UnitPrice.py`(1173줄) 가 이미
|
||
700줄을 크게 넘어 **새 파일로 뺐다**(PLAN 8-36 끝 ⚠).
|
||
|
||
⚠ **열 단위로 적는다.** 줄마다 갈리는 사유는 줄이 `notes` 로 들고 오고(내역서는 그 사유가
|
||
**닿는 열 키**까지 함께 들고 온다 — `BillRow.notes`), 화면이 그 열의 칸에만 덧붙인다.
|
||
|
||
토적표와 맞대 본 것 (데스크탑 메인 요청)
|
||
· B08 토적표에는 `final` 이 **한 열도 없었다** — 중간 장부이기 때문이다.
|
||
· B09 는 반대로 `final` 이 분명히 있다 — 내역서 금액·자재대 금액이 그 자리다.
|
||
⇒ 등급 여섯은 **한 장이 아니라 두 장을 합쳐야** 다 쓰인다.
|
||
· 그래도 **원가계산서 「금액」은 열 단위로 `final` 을 못 붙였다.** 같은 열 안에서
|
||
중간줄(간접노무비 따위)과 마지막줄(총원가·도급금액·총계)의 성격이 갈리는데 등급은
|
||
**열에 하나**뿐이라서다. `calc` 로 두고 `rule` 에 어느 줄이 `final` 인지 적었다.
|
||
⇒ 이 어긋남은 PLAN 8-36 ① 에 남긴다(칸 단위 등급이 필요한 첫 자리).
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from common_util.common_util_provenance import (
|
||
TIER_CALC,
|
||
TIER_EXCLUDED,
|
||
TIER_FINAL,
|
||
TIER_INPUT,
|
||
TIER_STANDARD,
|
||
TIER_SURVEY,
|
||
TIER_UNCLASSIFIED,
|
||
ColumnProvenance,
|
||
provenance_payload,
|
||
sheet_provenance,
|
||
)
|
||
|
||
#: 요율이 어디서 오는지 — 원가계산서 여러 열이 같은 문장을 쓴다.
|
||
_RATE_SOURCE = (
|
||
"요율 판 `resources/data_cost_input_value/rates_2026.json` — "
|
||
"공사금액·공사기간 구간으로 골라 씀(`B09_Estimation_Rates.py:180 select_bracket`). "
|
||
"어느 판으로 섰는지는 좌측 패널 「요율 판」과 산출기초 ① 에 지문까지 남음"
|
||
)
|
||
|
||
#: 이름표 열(코드·명칭·규격·단위)이 공통으로 쓰는 문장.
|
||
_CATALOG_SOURCE = "단가판·품셈 표의 이름을 그대로 옮긴 자리 — 여기서 짓지 않음"
|
||
|
||
#: 「비고」가 왜 미분류인지 — 표마다 같은 말을 쓴다.
|
||
_NOTE_RULE = (
|
||
"이 칸은 등급을 붙일 열이 아니라 **다른 열의 사유를 담는 그릇**이다. "
|
||
"안에 든 조각마다 닿는 열이 다르므로(갈래 근거는 규격, 반영률은 수량, "
|
||
"막힘 사유는 단가) 호버는 조각을 그 열의 칸에만 띄운다"
|
||
)
|
||
|
||
|
||
def _label(key: str, label: str, extra: str = "") -> ColumnProvenance:
|
||
"""이름표 열 — 값을 낳은 것이 아니라 옮겨 적은 자리."""
|
||
return ColumnProvenance(
|
||
key=key,
|
||
label=label,
|
||
tier=TIER_STANDARD,
|
||
formula="옮겨 적은 값 (여기서 계산하지 않음)",
|
||
source=_CATALOG_SOURCE + (f" · {extra}" if extra else ""),
|
||
)
|
||
|
||
|
||
def _note_column(code: str) -> ColumnProvenance:
|
||
"""「비고」 열 — 여섯 어디에도 안 맞아 `unclassified` 로 둔다(PLAN 8-36 ㉮)."""
|
||
return ColumnProvenance(
|
||
key="note",
|
||
label="비고",
|
||
tier=TIER_UNCLASSIFIED,
|
||
formula="줄에 달린 사유 조각을 차례로 이어 붙인 글",
|
||
source="조각마다 원천이 다름 — 조각별 원천은 그 조각이 닿는 열의 카드에 뜸",
|
||
rule=_NOTE_RULE,
|
||
code=code,
|
||
)
|
||
|
||
|
||
# =============================================================================
|
||
# ① 공사원가계산서
|
||
# =============================================================================
|
||
|
||
|
||
def cost_sheet() -> dict[str, Any]:
|
||
"""열 키는 화면 `buildCostSheetTable` 이 심는 낱말과 같아야 한다."""
|
||
return sheet_provenance(
|
||
[
|
||
ColumnProvenance(
|
||
key="name",
|
||
label="비목",
|
||
tier=TIER_STANDARD,
|
||
formula="법이 정한 비목 이름 (차례도 법이 정함)",
|
||
source="법정경비 14 비목은 `B09_Estimation_Statutory.py:58 STATUTORY_ITEMS` "
|
||
"— 그 차례가 곧 원가계산서 줄 차례",
|
||
code="B09_Estimation_Engine_Cost.py:115 CostLine.name",
|
||
),
|
||
ColumnProvenance(
|
||
key="amount_krw",
|
||
label="금액",
|
||
tier=TIER_CALC,
|
||
formula="밑수 × 요율% (+ 정액) 을 원 단위로 버림",
|
||
source="밑수는 비목마다 다름 — 「산출근거」 칸에 그 줄의 실제 밑수가 적힘. "
|
||
"버림은 `B09_Estimation_Engine_Cost.py:44 floor_won`",
|
||
rule="⚠ **총원가·도급금액·총계 줄은 `final`** — 계약으로 나가는 값이다. "
|
||
"등급이 열에 하나뿐이라 그 셋을 따로 못 적었다(PLAN 8-36 ①). "
|
||
"도급금액만 천원 단위 **올림**(`:49 ceil_thousand`)이라 끝자리가 다르다",
|
||
code="B09_Estimation_Engine_Cost.py:175 _emitter",
|
||
),
|
||
ColumnProvenance(
|
||
key="rate_percent",
|
||
label="요율",
|
||
tier=TIER_STANDARD,
|
||
formula="공사금액·공사기간이 든 구간의 요율을 그대로 씀",
|
||
source=_RATE_SOURCE,
|
||
code="B09_Estimation_Rates.py:180 select_bracket",
|
||
),
|
||
ColumnProvenance(
|
||
key="formula_text",
|
||
label="산출근거",
|
||
tier=TIER_CALC,
|
||
formula="그 줄이 실제로 쓴 밑수와 요율을 사람이 읽게 적은 한 줄",
|
||
source="엔진이 셈하면서 같이 지음 — 화면이 따로 짓지 않는다",
|
||
rule="⚠ **산업안전보건관리비만 「× %」 꼴이 아니다** — A(요율식)·B(대상액×1.2) "
|
||
"중 **작은 쪽**을 쓰므로 값 안에 고름이 숨어 있다"
|
||
"(`B09_Estimation_Statutory.py:154 safety_management_cost`)",
|
||
code="B09_Estimation_Engine_Cost.py:128 CostLine.formula_text",
|
||
),
|
||
_note_column("B09_Estimation_Engine_Cost.py:125 CostLine.note"),
|
||
]
|
||
)
|
||
|
||
|
||
# =============================================================================
|
||
# ② 설계내역서
|
||
# =============================================================================
|
||
|
||
|
||
def boq_sheet() -> dict[str, Any]:
|
||
return sheet_provenance(
|
||
[
|
||
_label("item_no", "No.", "마스터 목차가 매긴 번호"),
|
||
_label("name", "공종", "B08 이 보낸 이름, 없으면 마스터 이름"),
|
||
ColumnProvenance(
|
||
key="spec",
|
||
label="규격",
|
||
tier=TIER_STANDARD,
|
||
formula="마스터 규격 (갈래가 정해진 줄은 갈래 이름을 뒤에 이음)",
|
||
source="갈래를 어떻게 골랐는지는 그 줄의 사유에 적힘 — B08 문구를 그대로 옮김",
|
||
code="B09_Estimation_BillOfQuantities_Rows.py:149",
|
||
),
|
||
_label("unit", "단위"),
|
||
ColumnProvenance(
|
||
key="quantity",
|
||
label="수량",
|
||
tier=TIER_SURVEY,
|
||
formula="B08 이 보낸 값을 그대로 씀 (여기서 다시 곱하지 않음)",
|
||
source="⚠ **반영률은 B08 이 이미 곱했다** — 여기서 또 곱하면 두 번 곱해진다. "
|
||
"찍는 자리수는 품셈 1-2-2 종목별(`B09_Estimation_QuantityDigits.py`)이고 "
|
||
"값 자체는 전정밀로 남는다",
|
||
code="B09_Estimation_BillOfQuantities_Rows.py:151",
|
||
),
|
||
ColumnProvenance(
|
||
key="unit_price_krw",
|
||
label="단가",
|
||
tier=TIER_CALC,
|
||
formula="그 공종의 일위대가 본표 합계 (1단위 값)",
|
||
source="일위대가 탭에서 같은 표를 그대로 봄. 묶음 줄은 조각들의 "
|
||
"`단가 × 조각수량` 을 더한 값",
|
||
rule="⚠ **못 세우면 0 으로 때우지 않고 비운다.** 일위대가가 없음·성분이 빠짐·"
|
||
"밑수를 모름·일부만 섬·단위가 안 맞음 — 사유는 그 줄의 사유에 적히고 "
|
||
"「금액을 못 세운 줄」 목록에도 오른다",
|
||
code="B09_Estimation_BillOfQuantities_Rows.py:134 _leaf_row",
|
||
),
|
||
ColumnProvenance(
|
||
key="amount_krw",
|
||
label="금액",
|
||
tier=TIER_FINAL,
|
||
formula="수량 × 단가",
|
||
source="이 값들의 합이 공사원가계산서의 직접비로 나간다 — 화면 밖으로 나가는 값",
|
||
rule="단가가 안 선 줄은 **금액도 안 세운다**. 단위가 안 맞는 줄도 비운다 — "
|
||
"곱하면 조용히 틀린 금액이 내역서에 든다",
|
||
code="B09_Estimation_BillOfQuantities_Rows.py:134 _leaf_row",
|
||
),
|
||
_note_column("B09_Estimation_BillOfQuantities.py:BillRow.note"),
|
||
]
|
||
)
|
||
|
||
|
||
# =============================================================================
|
||
# ③ 일위대가
|
||
# =============================================================================
|
||
|
||
|
||
def unit_price_list_sheet() -> dict[str, Any]:
|
||
"""목록표 — 「무엇이 있나」."""
|
||
common = "단가판(`PriceBook`)이 성분을 풀어 낸 값 — 본표를 열면 줄마다 보인다"
|
||
return sheet_provenance(
|
||
[
|
||
_label("name", "명칭", "단가판 제목"),
|
||
_label("unit", "단위", "단가판 기준 단위"),
|
||
ColumnProvenance(
|
||
key="material",
|
||
label="재료비",
|
||
tier=TIER_CALC,
|
||
formula="본표 재료비 줄의 합",
|
||
source=common,
|
||
code="B09_Estimation_UnitPrice_View.py:149 list_unit_prices",
|
||
),
|
||
ColumnProvenance(
|
||
key="labor",
|
||
label="노무비",
|
||
tier=TIER_CALC,
|
||
formula="본표 노무비 줄의 합",
|
||
source=common,
|
||
code="B09_Estimation_UnitPrice_View.py:149 list_unit_prices",
|
||
),
|
||
ColumnProvenance(
|
||
key="expense",
|
||
label="경비",
|
||
tier=TIER_CALC,
|
||
formula="본표 경비 줄의 합",
|
||
source=common,
|
||
code="B09_Estimation_UnitPrice_View.py:149 list_unit_prices",
|
||
),
|
||
ColumnProvenance(
|
||
key="total",
|
||
label="합계",
|
||
tier=TIER_CALC,
|
||
formula="재료비 + 노무비 + 경비",
|
||
source=common,
|
||
code="B09_Estimation_UnitPrice_View.py:149 list_unit_prices",
|
||
),
|
||
]
|
||
)
|
||
|
||
|
||
def unit_price_detail_sheet() -> dict[str, Any]:
|
||
"""본표 — 「무엇으로 이루어졌나」."""
|
||
money = (
|
||
"성분 단위값 × 수량을 성분별로 자른 값. ⚠ 행마다 자르므로 **전정밀 합과 끝자리가 "
|
||
"어긋난다 — 정상이다.** 숨기면 나중에 「합계가 안 맞는다」며 계산을 고치려 든다"
|
||
)
|
||
return sheet_provenance(
|
||
[
|
||
_label("name", "명칭", "성분 이름. 제잡비·공구손료는 품셈 [주]가 만든 줄"),
|
||
_label("spec", "규격", "성분 규격. 비율 줄은 「노무비의 N%」 꼴"),
|
||
ColumnProvenance(
|
||
key="source",
|
||
label="원천",
|
||
tier=TIER_STANDARD,
|
||
formula="그 성분이 어느 판에서 왔는지 + 그 판에서의 순번",
|
||
source="자재 · 노임 · 기계경비 · 일위대가 · 단가산출 · 일식견적 여섯 중 하나"
|
||
"(`B09_Estimation_UnitPrice.py:1026 SOURCE_LABEL`)",
|
||
rule="기계경비·일위대가·단가산출 줄은 **눌러서 한 층 아래로 내려갈 수 있다**"
|
||
"(`:1037 DRILLABLE_KINDS`)",
|
||
code="B09_Estimation_UnitPrice_View.py:257",
|
||
),
|
||
_label("unit", "단위"),
|
||
ColumnProvenance(
|
||
key="quantity",
|
||
label="수량",
|
||
tier=TIER_STANDARD,
|
||
formula="품셈 표가 정한 1단위당 소요량",
|
||
source="비율 줄(제잡비·공구손료)은 수량 칸에 **퍼센트**가 들어간다",
|
||
code="B09_Estimation_UnitPrice_View.py:259",
|
||
),
|
||
ColumnProvenance(
|
||
key="material",
|
||
label="재료비",
|
||
tier=TIER_CALC,
|
||
formula="성분 단위 재료비 × 수량",
|
||
source=money,
|
||
code="B09_Estimation_UnitPrice_View.py:264",
|
||
),
|
||
ColumnProvenance(
|
||
key="labor",
|
||
label="노무비",
|
||
tier=TIER_CALC,
|
||
formula="성분 단위 노무비 × 수량",
|
||
source=money,
|
||
code="B09_Estimation_UnitPrice_View.py:265",
|
||
),
|
||
ColumnProvenance(
|
||
key="expense",
|
||
label="경비",
|
||
tier=TIER_CALC,
|
||
formula="성분 단위 경비 × 수량",
|
||
source=money,
|
||
code="B09_Estimation_UnitPrice_View.py:266",
|
||
),
|
||
ColumnProvenance(
|
||
key="total",
|
||
label="합계",
|
||
tier=TIER_CALC,
|
||
formula="자른 성분 셋을 더한 값 (표에서 합계 = 재료비+노무비+경비 가 서게)",
|
||
source=money,
|
||
code="B09_Estimation_UnitPrice_View.py:267",
|
||
),
|
||
]
|
||
)
|
||
|
||
|
||
# =============================================================================
|
||
# ④ 관급·사급 자재대
|
||
# =============================================================================
|
||
|
||
|
||
def _material_columns(*, excluded: bool) -> list[ColumnProvenance]:
|
||
"""자재대 열 일곱. 「안 갈린 것」 표만 통째로 `excluded` 로 선다."""
|
||
if excluded:
|
||
why = (
|
||
"⚠ **관급·사급이 안 갈린 줄** — 어느 합계에도 넣지 않는다. 못 세운 것이 아니라 "
|
||
"**세면 안 되는** 자리다. 관급자재대에도 도급 재료비에도 넣으면 이중계상이 된다"
|
||
)
|
||
return [
|
||
ColumnProvenance(
|
||
key=key,
|
||
label=label,
|
||
tier=TIER_EXCLUDED,
|
||
source=why,
|
||
code="B09_Estimation_BillOfQuantities_Rows.py:398",
|
||
)
|
||
for key, label in (
|
||
("name", "자재"),
|
||
("spec", "규격"),
|
||
("unit", "단위"),
|
||
("total_amount", "수량"),
|
||
("unit_price_krw", "단가"),
|
||
("amount_krw", "금액"),
|
||
("note", "비고"),
|
||
)
|
||
]
|
||
return [
|
||
_label("name", "자재"),
|
||
_label("spec", "규격"),
|
||
_label("unit", "단위"),
|
||
ColumnProvenance(
|
||
key="total_amount",
|
||
label="수량",
|
||
tier=TIER_SURVEY,
|
||
formula="B08 이 낸 자재 수량 × 할증률",
|
||
source="할증 사유는 그 줄의 사유에 적힘. 할증률이 아직 없는 자재는 "
|
||
"**할증 전 값**으로 서고 그 사실이 표 밑에 뜬다",
|
||
code="B09_Estimation_MaterialSheet.py:47 MaterialSheetRow",
|
||
),
|
||
ColumnProvenance(
|
||
key="unit_price_krw",
|
||
label="단가",
|
||
tier=TIER_STANDARD,
|
||
formula="단가판에서 찾은 값",
|
||
source="⚠ **관급과 사급은 원천이 다르다** — 관급은 나라장터, 사급은 물가지·견적. "
|
||
"관급을 「사급 단가 없음」으로 적으면 안 된다",
|
||
rule="못 찾으면 **0 으로 때우지 않고 비운다** — 사유가 그 줄에 적힌다",
|
||
code="B09_Estimation_MaterialSheet.py:117 build_material_sheet",
|
||
),
|
||
ColumnProvenance(
|
||
key="amount_krw",
|
||
label="금액",
|
||
tier=TIER_FINAL,
|
||
formula="수량 × 단가",
|
||
source="⚠ **사급만 도급 재료비로 든다.** 관급은 총원가 **밖** 별도 표기라 "
|
||
"여기 합계가 원가계산서 재료비와 같지 않다",
|
||
code="B09_Estimation_MaterialSheet.py:117 build_material_sheet",
|
||
),
|
||
_note_column("B09_Estimation_BillOfQuantities.py:BillRow.note"),
|
||
]
|
||
|
||
|
||
# =============================================================================
|
||
# ⑤ 중기목록표 · 기초자료 목록표
|
||
# =============================================================================
|
||
|
||
|
||
def machine_sheet() -> dict[str, Any]:
|
||
hourly = "시간당 사용료 — 「각종 중기경비계산서」에 셈 과정이 그대로 펼쳐진다"
|
||
return sheet_provenance(
|
||
[
|
||
_label("code", "코드번호"),
|
||
_label("name", "명 칭"),
|
||
_label("spec", "규 격"),
|
||
_label("unit", "단위"),
|
||
ColumnProvenance(
|
||
key="total_krw",
|
||
label="합 계",
|
||
tier=TIER_CALC,
|
||
formula="노무비 + 재료비 + 경비",
|
||
source=hourly,
|
||
code="B09_Estimation_Lists.py:105 machine_list",
|
||
),
|
||
ColumnProvenance(
|
||
key="labor_krw",
|
||
label="노 무 비",
|
||
tier=TIER_CALC,
|
||
formula="조종원 노임 ÷ 8시간 × 16/12 × 25/20 (약 1.667배)",
|
||
source="공표 노임은 기본급여액뿐이라 제수당·상여금·퇴직급여충당금을 따로 "
|
||
"계상함(건협 임금적용요령 4-나 · 기재부 집행기준 제76조의3). "
|
||
"⚠ 계수 자체의 예규 원문은 아직 못 봐 실무 관행을 따름",
|
||
code="B09_Estimation_MachineCost.py:74 OPERATOR_ALLOWANCE_FACTOR",
|
||
),
|
||
ColumnProvenance(
|
||
key="material_krw",
|
||
label="재 료 비",
|
||
tier=TIER_CALC,
|
||
formula="주연료(L/hr) × 유가 + 잡재료(주연료의 %)",
|
||
source="유가는 전국 또는 고른 시도의 공시가 — 기초자료 탭에서 고른다. "
|
||
"잡재료는 연료 소요량에 포함되어 있어 따로 세지 않는다",
|
||
rule="같은 기종이라도 **조합 사용이면 잡재료가 16% 로 줄어** 재료비가 달라진다 "
|
||
"— 그래서 층이 따로 선다(건설품셈 제8장 [주]⑤)",
|
||
code="B09_Estimation_MachineExpenseSheet.py:81 machine_expense_sheets",
|
||
),
|
||
ColumnProvenance(
|
||
key="expense_krw",
|
||
label="경 비",
|
||
tier=TIER_CALC,
|
||
formula="취득가격 × 손료계수(상각비 + 정비비 + 관리비, 10⁻⁷)",
|
||
source="취득가격·내용시간·연간표준가동시간·계수 셋은 모두 품셈 표 값",
|
||
code="B09_Estimation_MachineExpenseSheet.py:81 machine_expense_sheets",
|
||
),
|
||
_note_column("B09_Estimation_Lists.py:105 machine_list"),
|
||
]
|
||
)
|
||
|
||
|
||
def catalog_sheet() -> dict[str, Any]:
|
||
"""기초자료 탭의 목록표 셋(노무비·재료비·경비)이 같이 쓰는 사전."""
|
||
return sheet_provenance(
|
||
[
|
||
_label("code", "코드번호"),
|
||
_label("name", "명 칭"),
|
||
_label("spec", "규 격"),
|
||
_label("unit", "단위"),
|
||
ColumnProvenance(
|
||
key="unit_price_krw",
|
||
label="단 가",
|
||
tier=TIER_STANDARD,
|
||
formula="단가판 값을 그대로 옮김 (여기서 셈하지 않음)",
|
||
source="어느 판·어느 기준일인지는 산출기초 ① 에 지문까지 남음. "
|
||
"⚠ 경비목록표의 값은 **기계 취득가격(천원)** 이고 시간당 사용료가 아니다",
|
||
rule="자재단가대비표에서 **원천 다섯 중 하나를 골라** 적용 단가가 선다 — "
|
||
"값 안에 고름이 숨은 자리(PLAN 8-36 ㉯)",
|
||
code="B09_Estimation_Lists.py:50 catalog_list",
|
||
),
|
||
_note_column("B09_Estimation_Lists.py:50 catalog_list"),
|
||
]
|
||
)
|
||
|
||
|
||
# =============================================================================
|
||
# 응답에 싣기
|
||
# =============================================================================
|
||
|
||
|
||
def estimation_provenance() -> dict[str, Any] | None:
|
||
"""B09 응답에 실을 사전 — **개발환경이 아니면 `None`.**
|
||
|
||
시트를 늘릴 때는 여기 한 줄만 더한다. 화면은 시트 이름으로 찾아 쓴다.
|
||
|
||
⚠ 아직 사전이 없는 장 — 단가산출근거·설계서 구성·산출기초·환율및기초자료·
|
||
자재단가대비표·산출 조건. 앞 넷은 **값을 낳는 표가 아니라 모으는 표**라
|
||
열 사전보다 먼저 「사전 대상인가」를 정해야 한다(PLAN 8-36 ㉴).
|
||
"""
|
||
return provenance_payload(
|
||
{
|
||
"cost_sheet": cost_sheet(),
|
||
"boq": boq_sheet(),
|
||
"unit_price_list": unit_price_list_sheet(),
|
||
"unit_price_detail": unit_price_detail_sheet(),
|
||
"material": sheet_provenance(_material_columns(excluded=False)),
|
||
"material_unknown": sheet_provenance(_material_columns(excluded=True)),
|
||
"machine": machine_sheet(),
|
||
"catalog": catalog_sheet(),
|
||
}
|
||
)
|