diff --git a/B09_Estimation/B09_Estimation_MachineExpenseSheet.py b/B09_Estimation/B09_Estimation_MachineExpenseSheet.py index 75a66fa7..4d5d8692 100644 --- a/B09_Estimation/B09_Estimation_MachineExpenseSheet.py +++ b/B09_Estimation/B09_Estimation_MachineExpenseSheet.py @@ -31,6 +31,9 @@ from B09_Estimation.B09_Estimation_MachineCost import ( ) from B09_Estimation.B09_Estimation_PriceBook import PriceKind +#: 조합 사용(굴착기+부착장비)일 때의 본체 잡재료비율 — 품셈 제8장 [주]⑤. +COMBINED_MISC_PERCENT = 16 + _CATALOG_SUBPATH = ("resources", "data_cost_input_value") _THOUSAND = Decimal(1000) _ZERO = Decimal(0) @@ -93,7 +96,7 @@ def machine_expense_sheets(build: Any) -> list[dict[str, Any]]: for code, title in sorted(build.book.titles.items()): if title.kind is not PriceKind.MACHINE_HOURLY: continue - machine_code = code[2:].split("#")[0] + machine_code, _, variant = code[2:].partition("#") machine = catalog.machines.get(machine_code) if machine is None: continue @@ -121,6 +124,10 @@ def machine_expense_sheets(build: Any) -> list[dict[str, Any]]: "machine_code": machine_code, "name": machine.name, "spec": machine.specification, + # ⚠ 같은 기종이 **두 장**일 수 있다 — 조합 사용이면 잡재료가 16% 로 줄어 + # 재료비가 달라지므로 층이 따로 선다(품셈 제8장 [주]⑤). 갈래를 안 적으면 + # 똑같은 장이 두 번 나온 것처럼 읽힌다. + "variant": variant, # ① 손료 "price_thousand_krw": _money(machine.price_thousand_krw), "economic_life_hours": raw.get("economic_life_hours"), @@ -138,7 +145,9 @@ def machine_expense_sheets(build: Any) -> list[dict[str, Any]]: "fuel_liters_per_hour": _money(fuel_liters), "fuel_price_per_liter": _money(fuel_price), "fuel_scope": fuel_meta.get("region_name") or "전국 공시가", - "misc_material_percent": _money(misc_percent), + "misc_material_percent": ( + str(COMBINED_MISC_PERCENT) if variant else _money(misc_percent) + ), "operator_code": occupation, "operator_daily_wage": _money(wage), "operator_krw_per_hour": _money( diff --git a/B09_Estimation/B09_Estimation_UI_BaseData.ts b/B09_Estimation/B09_Estimation_UI_BaseData.ts index 72cafae8..47dcad4d 100644 --- a/B09_Estimation/B09_Estimation_UI_BaseData.ts +++ b/B09_Estimation/B09_Estimation_UI_BaseData.ts @@ -272,6 +272,7 @@ export interface MachineExpenseDto { labor_krw: string | null; expense_krw: string | null; total_krw: string | null; + variant: string; attachment: boolean; attachment_note: string; gaps: string[]; @@ -293,7 +294,9 @@ function machineExpenseSheet(sheet: MachineExpenseDto["sheets"][number]): HTMLEl box.className = "b09-panel__group"; const title = document.createElement("p"); title.className = "b09-panel__legend"; - title.textContent = `${sheet.machine_code} ${sheet.name} ${sheet.spec}`.trim(); + title.textContent = + `${sheet.machine_code} ${sheet.name} ${sheet.spec}`.trim() + + (sheet.variant ? ` — ${sheet.variant}` : ""); box.append(title); const coefficient = (value: number | null) => (value === null ? "—" : String(value)); @@ -334,6 +337,14 @@ function machineExpenseSheet(sheet: MachineExpenseDto["sheets"][number]): HTMLEl [0, 1], ), ); + if (sheet.variant) { + box.append( + note( + "같은 기종이라도 조합 사용이면 잡재료가 16% 로 줄어 재료비가 달라집니다 —" + + " 그래서 층이 따로 섭니다(건설품셈 제8장 [주]⑤).", + ), + ); + } if (sheet.attachment_note) box.append(note(sheet.attachment_note)); for (const gap of sheet.gaps) box.append(note(`⚠ ${gap}`)); return box; diff --git a/resources/tester/test_b09_machine_expense.py b/resources/tester/test_b09_machine_expense.py index 106c69f0..5602b427 100644 --- a/resources/tester/test_b09_machine_expense.py +++ b/resources/tester/test_b09_machine_expense.py @@ -75,3 +75,16 @@ def test_수송비는_이_장에_안_붙는다() -> None: assert any("수송비" in line and "회당" in line for line in report["notes"]) for sheet in report["sheets"]: assert "transport" not in sheet + + +def test_같은_기종의_두_장은_갈래로_갈린다() -> None: + """⚠ 조합 사용이면 잡재료가 16% 로 줄어 재료비가 달라진다 — 갈래를 안 적으면 + 똑같은 장이 두 번 나온 것처럼 읽힌다(건설품셈 제8장 [주]⑤).""" + sheets = {sheet["code"]: sheet for sheet in _report()["sheets"]} + plain = sheets.get("X-0201-0070") + combined = sheets.get("X-0201-0070#조합") + assert plain is not None and combined is not None + assert plain["variant"] == "" and combined["variant"] == "조합" + assert combined["misc_material_percent"] == "16" + # 조합 쪽이 잡재료가 줄어 재료비가 더 싸야 한다. + assert Decimal(combined["material_krw"]) < Decimal(plain["material_krw"])