"""원가계산서 탭(일반형식) — STmate 서식 차례로 우리 엔진 줄을 늘어놓는가 (PLAN 12장). ⚠ 금액을 박지 않는다 — 차례·표기·자리(경비 안/총원가 밖)와 「줄 = 엔진 값」만 잰다. """ from __future__ import annotations import sys from decimal import Decimal from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from B09_Estimation.B09_Estimation_CostSheet import ( # noqa: E402 clean_settings, cost_input, field_options, sheet_rows, ) from B09_Estimation.B09_Estimation_Engine_Cost import calculate_cost # noqa: E402 from B09_Estimation.B09_Estimation_Rates import load_rate_dataset # noqa: E402 from B09_Estimation.B09_Estimation_RateTable import amount_label, rate_sections # noqa: E402 DIRECT = { "material": Decimal(30_000_000), "labor": Decimal(40_000_000), "expense": Decimal(10_000_000), } def _sheet(waste: Decimal = Decimal(0), separate: bool = False, stored: dict | None = None): data = cost_input(DIRECT, stored or {}, waste, separate) return sheet_rows(calculate_cost(data), data), calculate_cost(data) def test_큰_묶음이_STmate_차례로_선다() -> None: rows, _ = _sheet() marks = [ row["mark"] for row in rows if row["mark"] in ("나.", "ㄱ.", "ㄴ.", "ㄷ.", "다.", "라.", "마.", "바.") ] assert marks == ["나.", "ㄱ.", "ㄴ.", "ㄷ.", "다.", "라.", "마.", "바."] def test_줄_금액은_엔진_값_그대로() -> None: rows, result = _sheet() by_key = {row["key"]: row for row in rows} for key in ("net_construction_cost", "general_overhead", "profit", "total_cost", "grand_total"): assert Decimal(by_key[key]["amount_krw"]) == result.amount(key) assert Decimal(by_key["subtotal"]["amount_krw"]) == result.amount( "net_construction_cost" ) + result.amount("general_overhead") def test_경비_세목은_2번부터_차례로_번호() -> None: rows, _ = _sheet() expense = [row for row in rows if row["level"] == 2 and row["mark"].endswith(")")] numbers = [ int(row["mark"][:-1]) for row in expense if row["key"] not in ("direct_labor", "indirect_labor_cost") ] assert numbers[0] == 1 and numbers[1:] == list(range(2, len(numbers) + 1)) def test_폐기물은_기본_경비_안_분리발주면_도급공사비_뒤() -> None: rows, _ = _sheet(Decimal(1_000_000)) keys = [row["key"] for row in rows] assert keys.index("waste_disposal") < keys.index("general_overhead") rows, _ = _sheet(Decimal(1_000_000), separate=True) keys = [row["key"] for row in rows] assert keys.index("waste_disposal") > keys.index("contract_amount") def test_저장값은_데이터에_있는_공종만_받는다() -> None: dataset = load_rate_dataset() cleaned = clean_settings( { "work_type_safety": "civil", "environment_work_type": "moon_base", "duration_days": "200", "owner_supplied_material_krw": "-5", "profit_adjustment_krw": "", }, dataset, ) assert cleaned == { "work_type_safety": "civil", "duration_days": 200, "owner_supplied_material_krw": "0", } assert {o["value"] for o in field_options(dataset)["work_type_indirect_labor"]} == { "civil", "landscape", "industrial_facilities_civil", } def test_저장한_기간이_간접노무비_구간을_바꾼다() -> None: short = {r["key"]: r for r in _sheet(stored={"duration_days": 100})[0]} long = {r["key"]: r for r in _sheet(stored={"duration_days": 800})[0]} assert ( short["indirect_labor_cost"]["rate_percent"] != long["indirect_labor_cost"]["rate_percent"] ) def test_요율표_구간_표기와_묶음() -> None: assert amount_label("lt_5_billion") == "50억 미만" assert amount_label("5_to_30_billion") == "50억~300억 미만" titles = [section["title"] for section in rate_sections(load_rate_dataset())] assert titles[0] == "일반관리비 · 이윤" and "산업안전보건관리비" in titles for section in rate_sections(load_rate_dataset()): assert all(len(row) == len(section["columns"]) for row in section["rows"]), section["title"] def test_10_11_12_칸이_저장값을_엔진으로_옮긴다() -> None: dataset = load_rate_dataset() stored = clean_settings( { "overhead_class": "specialty_electric_communication_fire_other", "cut_basis": "grand_total", "cut_unit_krw": "1000", "vat_mode": "forest_coop", "tax_exempt_material_krw": "5000", "cut_unit_krw_bad": "7", }, dataset, ) assert stored["cut_unit_krw"] == 1000 and stored["vat_mode"] == "forest_coop" data = cost_input(DIRECT, stored) assert (data.overhead_class, data.cut_basis, data.cut_unit_krw) == ( "specialty_electric_communication_fire_other", "grand_total", 1000, ) rows = {r["key"]: r for r in sheet_rows(calculate_cost(data), data)} assert int(rows["grand_total"]["amount_krw"]) % 1000 == 0 assert clean_settings({"cut_unit_krw": "7", "vat_mode": "moon"}, dataset) == {}