fix(b09): 원가계산 나머지 세 형식 사유를 요율표 셋 결론으로 — 실적형 「임도 미적용 — 100억 미만(예정가격작성기준 §37②)」 · 수공 세부 경비 「법정 요율 없음 — 값을 넣어 주십시오(§34①)」 · 실적 안전표는 고시 편입이나 실적형 미적용 · 탭 말풍선도 같은 말
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
근거: STmate 분석 `12_원가계산_4형식과_RATE표_복원.md` §4~6 (DFM 복원 서식) ·
|
||||
`35_형식과_단계의_공통과_차이.md` §1·§2 (공통 사슬 · 형식별 차이 · 12번 정정 반영).
|
||||
|
||||
⚠ **금액을 안 낸다** — 요율 데이터가 없다(2026-09-14 확인: 수공 세부 경비 율표 `RateB` ·
|
||||
표준시장단가 제비율 `RATE_RA`·`RATE_RA1`·실적 안전표 `An_A`). 줄마다 무엇이 막혔는지만 적는다.
|
||||
⚠ **금액을 안 낸다** — 2026-09-14 요율표 셋 결론(PLAN 7장): 실적형 제비율 `RATE_RA`·`RATE_RA1` 은
|
||||
**임도 미적용**(100억 미만 · 예정가격작성기준 §37②) · 수공 세부 경비 `RateB` 는 **법정 요율 없음**
|
||||
(업체 실측 대상 §34① — 설계자 입력 칸) · 실적 안전표 `An_A` 는 고시 편입(제4조·별표1)이나 실적형
|
||||
자체가 임도 미적용. 줄마다 무엇이 막혔는지만 적는다.
|
||||
**0 원으로 채우지 않는다** — 0 원은 「없다」가 아니라 「공짜」로 읽혀 총액이 조용히 작아진다.
|
||||
⚠ 35번 §5 미확인은 「확인 대기」로 세운다 — 지금 남은 것은 **실적형 이윤 밑수** 하나다.
|
||||
실적수공 안전관리비는 2026-09-14 코덱스가 STmate 원문에서 **있음**을 확인해 별도내역으로 내렸다.
|
||||
@@ -17,9 +19,18 @@ from typing import Any
|
||||
#: 줄 상태 — 화면이 그대로 보인다.
|
||||
COMMON = "공통 요율 — 일반형식과 같은 표(형식 전체가 서면 금액이 섬)"
|
||||
SEPARATE = "별도내역 — 요율이 아니라 따로 산출한 금액"
|
||||
RATE_B = "요율표 미확보 — 수공 세부 경비 율표(STmate RateB)"
|
||||
RATE_RA = "요율표 미확보 — 표준시장단가(실적공사비) 제비율(STmate RATE_RA·RATE_RA1)"
|
||||
RATE_AN_A = "요율표 미확보 — 실적 산업안전보건관리비 표(STmate An_A·An_A1)"
|
||||
RATE_B = (
|
||||
"법정 요율 없음 — 값을 넣어 주십시오(업체 실측 대상 · 예정가격작성기준 §34①) · 수공 세부 경비"
|
||||
"(STmate RateB) · 입력 칸은 수공형식 금액 셈과 함께 섬"
|
||||
)
|
||||
RATE_RA = (
|
||||
"임도 미적용 — 100억 미만(예정가격작성기준 §37②) · 표준시장단가(실적공사비) 제비율"
|
||||
"(STmate RATE_RA·RATE_RA1)"
|
||||
)
|
||||
RATE_AN_A = (
|
||||
"임도 미적용 — 실적형 형식 전체가 100억 미만 임도에 안 씀(§37②) · 요율 자체는 고시 편입"
|
||||
"(건설업 산업안전보건관리비 계상 및 사용기준 제4조·별표1)"
|
||||
)
|
||||
TOTAL = "합계 — 위 줄이 다 서야 섬"
|
||||
PENDING_PROFIT = "확인 대기 — 실적형 이윤 밑수가 복원식과 화면 문구가 충돌(35번 §5-1)"
|
||||
DIRECT = "설계내역서 합계에서 옴"
|
||||
|
||||
@@ -87,8 +87,8 @@ def cost_from_bill(root: str, bill: dict[str, Any], direct: dict[str, Decimal]):
|
||||
async def get_cost_sheet(project_id: UUID, form: str = "general") -> JSONResponse:
|
||||
"""원가계산서 한 장 — 서식 줄 · 기준 입력 선택지 · 상태줄.
|
||||
|
||||
`form` — 일반형식만 금액을 냄. 수공·실적일반·실적수공은 **서식 차례만**(요율표 미확보 줄은
|
||||
막고 사유 · 0 원으로 안 채움).
|
||||
`form` — 일반형식만 금액을 냄. 수공·실적일반·실적수공은 **서식 차례만**(실적형 임도 미적용 ·
|
||||
수공 세부 경비 법정 요율 없음 줄은 막고 사유 · 0 원으로 안 채움).
|
||||
"""
|
||||
from B09_Estimation.B09_Estimation_Router import get_bill
|
||||
from common_util.common_util_project_settings import estimation_settings
|
||||
|
||||
@@ -73,6 +73,12 @@ const FORMS = [
|
||||
];
|
||||
/** DFM 본문 아래 탭 이름 그대로. */
|
||||
const FORM_TABS = ["general", "sugong", "actual_general", "actual_sugong"];
|
||||
/** 탭 말풍선 — 금액이 안 서는 까닭(2026-09-14 요율표 셋 결론 · 줄 사유는 서버 문구). */
|
||||
const FORM_TAB_NOTES: Record<string, string> = {
|
||||
sugong: "서식 차례만 — 세부 경비 법정 요율 없음(값 입력 대기 · 예정가격작성기준 §34①)",
|
||||
actual_general: "서식 차례만 — 임도 미적용(100억 미만 · 예정가격작성기준 §37②)",
|
||||
actual_sugong: "서식 차례만 — 임도 미적용(100억 미만 · 예정가격작성기준 §37②)",
|
||||
};
|
||||
/** 프로젝트별 고른 형식 탭 — 일반형식만 금액이 섬. */
|
||||
const formOf = new Map<string, string>();
|
||||
|
||||
@@ -320,7 +326,7 @@ function drawBody(ctx: B09TabContext, sheet: CostSheetDto, reload: () => void):
|
||||
label.append(el("span", "", row.label));
|
||||
if (row.formula) label.append(el("span", "b09cs__formula", `<${row.formula}>`));
|
||||
label.title = [row.formula, row.note].filter(Boolean).join(" · ");
|
||||
// 금액 없는 줄 — 「-」 + 막힌 까닭(요율표 미확보 · 확인 대기). 0 원으로 안 보임.
|
||||
// 금액 없는 줄 — 「-」 + 막힌 까닭(임도 미적용 · 법정 요율 없음 · 확인 대기). 0 원으로 안 보임.
|
||||
if (row.amount_krw === null && row.blocked) label.append(el("span", "b09cs__warn", row.note));
|
||||
line.append(
|
||||
label,
|
||||
@@ -334,7 +340,7 @@ function drawBody(ctx: B09TabContext, sheet: CostSheetDto, reload: () => void):
|
||||
for (const key of FORM_TABS) {
|
||||
const tab = el("button", "b09cs__tab", sheet.form_labels[key] ?? key);
|
||||
tab.setAttribute("aria-selected", String(key === sheet.form_key));
|
||||
if (key !== "general") tab.title = "서식 차례만 — 요율표 미확보로 금액 안 섬";
|
||||
if (FORM_TAB_NOTES[key]) tab.title = FORM_TAB_NOTES[key];
|
||||
tab.addEventListener("click", () => {
|
||||
formOf.set(ctx.projectId as string, key);
|
||||
reload();
|
||||
|
||||
@@ -60,3 +60,13 @@ def test_실적일반_보증_밑수는_직접공사비_환경은_재료직노산
|
||||
def test_모르는_형식은_멈춘다() -> None:
|
||||
with pytest.raises(ValueError):
|
||||
form_rows("general")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("form", ["sugong", "actual_general", "actual_sugong"])
|
||||
def test_사유는_요율표_미확보가_아니라_실제_결론(form) -> None:
|
||||
"""2026-09-14 요율표 셋 결론(PLAN 7장) — 「자료를 못 구함」 이 아니라 실적형은 **임도 미적용**
|
||||
(예정가격작성기준 §37② 100억 미만) · 수공 세부 경비는 **법정 요율 없음**(§34① 업체 실측)."""
|
||||
notes = [row["note"] for row in form_rows(form)]
|
||||
assert not any("요율표 미확보" in note for note in notes), notes
|
||||
assert "임도 미적용" in RATE_RA and "§37②" in RATE_RA
|
||||
assert "법정 요율 없음" in RATE_B and "값을 넣어 주십시오" in RATE_B and "§34①" in RATE_B
|
||||
|
||||
Reference in New Issue
Block a user