"""원가계산서 4형식 중 나머지 셋 — **서식 차례만** (수공 S · 실적일반 TA · 실적수공 SA). 근거: STmate 분석 `12_원가계산_4형식과_RATE표_복원.md` §4~6 (DFM 복원 서식) · `35_형식과_단계의_공통과_차이.md` §1·§2 (공통 사슬 · 형식별 차이 · 12번 정정 반영). ⚠ **금액을 안 낸다** — 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 원문에서 **있음**을 확인해 별도내역으로 내렸다. """ from __future__ import annotations from typing import Any #: 줄 상태 — 화면이 그대로 보인다. COMMON = "공통 요율 — 일반형식과 같은 표(형식 전체가 서면 금액이 섬)" SEPARATE = "별도내역 — 요율이 아니라 따로 산출한 금액" 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 = "설계내역서 합계에서 옴" _SUGONG_EXPENSES = ( "수도광열비", "복리후생비", "소모품·사무용품비", "여비·교통비·통신비", "세금·공과금", "폐기물처리비", "도서인쇄비", "지급수수료", ) FORM_LABELS = { "general": "일반형식", "sugong": "수공형식", "actual_general": "실적일반", "actual_sugong": "실적수공", } def _r(mark: str, label: str, formula: str, status: str, level: int) -> dict[str, Any]: return { "key": "", "mark": mark, "label": label, "level": level, "formula": formula, "rate_percent": None, "amount_krw": None, "note": status, "total": level == 0, "blocked": status not in (COMMON, DIRECT), } def _sugong() -> list[dict[str, Any]]: """수공 S — 12번 §4.1.""" rows = [ _r("1.", "순공사원가(가+나+다)", "", TOTAL, 0), _r("가.", "순공사비", "", DIRECT, 1), _r("나.", "간접노무비", "직접노무비 × 율", COMMON, 1), _r("다.", "경 비", "", TOTAL, 1), _r("1)", "산재보험료", "(직접노무비+간접노무비) × 율", COMMON, 2), _r("2)", "고용보험료", "(직접노무비+간접노무비) × 율", COMMON, 2), _r("3)", "건강보험료", "직접노무비 × 율", COMMON, 2), _r("4)", "장기요양보험료", "건강보험료 × 율", COMMON, 2), _r("5)", "연금보험료", "직접노무비 × 율", COMMON, 2), _r("6)", "퇴직공제부금비", "직접노무비 × 율", COMMON, 2), _r("7)", "산업안전보건관리비", "(재료비+직접노무비+도급자관급자재) × 율", COMMON, 2), _r("8)", "안전관리비", "", SEPARATE, 2), _r("9)", "품질관리비", "", SEPARATE, 2), ] rows += [ _r(f"{10 + i})", name, "(직노·노무·재료 중 고른 밑수) × 율", RATE_B, 2) for i, name in enumerate(_SUGONG_EXPENSES) ] rows += [ _r("18)", "공사이행 수수료", "[기초액 + (직공비−기준액) × 율] × 공기", COMMON, 2), _r("19)", "하도대금 수수료", "(재료비+직노+산출경비) × 율", COMMON, 2), _r("20)", "환 경 보 전 비", "(재료비+직노+산출경비) × 율", COMMON, 2), _r("21)", "건설기계 대여금", "(재료비+직노+산출경비) × 율", COMMON, 2), _r("22)", "석면분담금", "(직노+간노) × 율", COMMON, 2), _r("23)", "임금채권부담금", "(직노+간노) × 율", COMMON, 2), _r( "2.", "일반관리비", "(순공사비+간접노무비+경비) × 율 — 밑수에 수공 경비가 들어 미산출", RATE_B, 1, ), _r("3.", "이 윤", "(순공사원가+일반관리비−재료비) × 율 — 밑수 미산출", RATE_B, 1), _r("4.", "공급가액", "", TOTAL, 0), _r("5.", "도급공사비", "", TOTAL, 0), _r("6.", "총공사비", "", TOTAL, 0), ] return rows def _actual(sugong: bool) -> list[dict[str, Any]]: """실적일반 TA(§5 · 35번 정정) / 실적수공 SA(§6).""" labor_base = "(직접노무비+간접노무비)" if sugong else "노무비" rows = [ _r("1.", "직접공사비", "", DIRECT, 0), _r("2.", "간접공사비", "", TOTAL, 0), _r("1)", "간접노무비", "직접노무비 × 율", RATE_RA, 1), _r("2)", "산재보험료", f"{labor_base} × 율", COMMON, 1), _r("3)", "고용보험료", f"{labor_base} × 율", COMMON, 1), _r("4)", "건강보험료", "직접노무비 × 율", COMMON, 1), _r("5)", "장기요양보험료", "건강보험료 × 율", COMMON, 1), _r("6)", "연금보험료", "직접노무비 × 율", COMMON, 1), _r("7)", "퇴직공제부금비", "직접노무비 × 율", COMMON, 1), _r("8)", "산업안전보건관리비", "(직접공사비+도급자관급자재) × 율", RATE_AN_A, 1), # TA·SA 둘 다 별도내역 — SA 도 있음이 확인됨(2026-09-14 코덱스, 35번 §5-2 풀림). _r("9)", "안전관리비", "", SEPARATE, 1), _r("10)", "품질관리비", "", SEPARATE, 1), ] if sugong: rows += [ _r(f"{11 + i})", name, "(직노·노무·재료 중 고른 밑수) × 율", RATE_B, 1) for i, name in enumerate(_SUGONG_EXPENSES) ] guarantee_base = "(재료비+직노+산출경비)" tail = 19 else: rows.append(_r("11)", "기타경비", "직접공사비 × 율", RATE_RA, 1)) guarantee_base = "직접공사비" tail = 12 rows += [ _r(f"{tail})", "공사이행 수수료", "[기초액 + (직공비−기준액) × 율] × 공기", COMMON, 1), _r(f"{tail + 1})", "하도대금 수수료", f"{guarantee_base} × 율", COMMON, 1), _r(f"{tail + 2})", "환 경 보 전 비", "(재료비+직노+산출경비) × 율", COMMON, 1), _r(f"{tail + 3})", "건설기계 대여금", f"{guarantee_base} × 율", COMMON, 1), _r(f"{tail + 4})", "석면분담금", f"{labor_base} × 율", COMMON, 1), _r(f"{tail + 5})", "임금채권부담금", f"{labor_base} × 율", COMMON, 1), _r( "3.", "일반관리비", "(직접공사비+간접노무비) × 율" if sugong else "(직접공사비+간접공사비+관리품목자재) × 율", RATE_RA, 0, ), _r("4.", "이 윤", "", PENDING_PROFIT, 0), _r("5.", "공급가액", "", TOTAL, 0), _r("6.", "도급공사비", "", TOTAL, 0), _r("7.", "총공사비", "", TOTAL, 0), ] return rows def form_rows(form: str) -> list[dict[str, Any]]: """형식별 서식 줄(금액 없음). 일반형식은 엔진이 셈하므로 여기 없음.""" if form == "sugong": return _sugong() if form == "actual_general": return _actual(sugong=False) if form == "actual_sugong": return _actual(sugong=True) raise ValueError(f"서식이 없는 형식입니다: {form}")