refactor(B09): 불도저를 딴 파일로 분리, 장비 붙이는 자리를 한 켤레로 맞춤
- B09_Estimation_MachineProductivity_Dozer.py 신설 (8-2-1 전용). 굴착기(8-1-4)와 한 파일에 두면 700줄을 넘고, 두 식이 섞여 읽힘. - 굴착기 쪽 장비 붙이기를 attach_machine_share 로 올려 불도저 쪽 attach_dozer_share 와 같은 모양으로 맞춤 — 자리를 나눠 쓰는 것이 눈에 보이게. - 줄수: UnitPrice 652 · MachineProductivity 360 · Dozer 398. - 224건 통과 (동작 변화 없음). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,12 +27,14 @@ from B09_Estimation.B09_Estimation_MachineCost import load_machine_catalog
|
||||
from B09_Estimation.B09_Estimation_MachineProductivity import (
|
||||
CycleFactors,
|
||||
FactorGap,
|
||||
attach_machine_share,
|
||||
extract_cycle_factors,
|
||||
)
|
||||
from B09_Estimation.B09_Estimation_MachineProductivity_Dozer import (
|
||||
attach_dozer_share,
|
||||
dozer_variants,
|
||||
formula_machine_codes,
|
||||
extract_cycle_factors,
|
||||
extract_dozer_factors,
|
||||
machine_hours_per_unit,
|
||||
formula_machine_codes,
|
||||
)
|
||||
from B09_Estimation.B09_Estimation_MachineOperating import (
|
||||
load_fuel_price,
|
||||
@@ -429,7 +431,14 @@ def build_unit_prices(axis: AxisResult | None = None) -> UnitPriceBuild:
|
||||
build.book, build.factor_gaps, master, work_item_code, title_code, variant
|
||||
)
|
||||
if not machine_share and not variant:
|
||||
machine_share = _attach_machine_share(build, master, work_item_code, title_code)
|
||||
machine_share = attach_machine_share(
|
||||
build.book,
|
||||
build.factor_gaps,
|
||||
build.cycle_factors,
|
||||
master,
|
||||
work_item_code,
|
||||
title_code,
|
||||
)
|
||||
|
||||
# ⚠ **배분율이 있는 표는 「몇 %가 실제로 붙었나」를 세어 둔다.**
|
||||
# 「인력(10%)·장비(90%)」 표에서 인력만 붙으면 단가가 10 % 몫만인데, 그 값이
|
||||
@@ -477,58 +486,6 @@ def _share_of(row) -> Decimal:
|
||||
return Decimal(1) if ratio is None else Decimal(str(ratio)) / Decimal(100)
|
||||
|
||||
|
||||
def _attach_machine_share(
|
||||
build: UnitPriceBuild,
|
||||
master: dict,
|
||||
work_item_code: str,
|
||||
title_code: str,
|
||||
) -> Decimal:
|
||||
"""시공능력 공식으로 **장비 몫**을 붙인다. 붙인 비율(%)을 돌려준다.
|
||||
|
||||
계수가 다 안 서면 **아무것도 안 붙이고 0 을 돌려준다** — 그러면 그 공종은
|
||||
`partial_ratio` 에 남아 내역서에서 금액이 안 붙는다(지어낸 값이 서는 것보다 낫다).
|
||||
"""
|
||||
node = next(
|
||||
(w for w in master.get("work_items", []) if w.get("work_item_code") == work_item_code),
|
||||
None,
|
||||
)
|
||||
if node is None:
|
||||
return _ZERO
|
||||
|
||||
for table in node.get("tables", []):
|
||||
factors = extract_cycle_factors(work_item_code, table)
|
||||
if not isinstance(factors, CycleFactors):
|
||||
if isinstance(factors, FactorGap):
|
||||
build.factor_gaps[work_item_code] = factors
|
||||
continue
|
||||
hourly_code = f"X-{factors.machine_code}"
|
||||
if hourly_code not in build.book.titles:
|
||||
# 기계 층이 안 섰다 — 지어내지 않고 못 붙인 채로 둔다.
|
||||
build.factor_gaps[work_item_code] = FactorGap(
|
||||
work_item_code=work_item_code,
|
||||
pum_table_id=factors.pum_table_id,
|
||||
missing=("시간당 사용료",),
|
||||
note=f"{factors.machine_name} 의 시간당 사용료가 아직 안 섰습니다.",
|
||||
)
|
||||
continue
|
||||
share = (
|
||||
Decimal(1)
|
||||
if factors.machine_ratio_pct is None
|
||||
else Decimal(str(factors.machine_ratio_pct)) / Decimal(100)
|
||||
)
|
||||
build.book.add_detail(
|
||||
PriceDetail(
|
||||
title_code,
|
||||
hourly_code,
|
||||
machine_hours_per_unit(factors) * share,
|
||||
note=factors.formula_text,
|
||||
)
|
||||
)
|
||||
build.cycle_factors[work_item_code] = factors
|
||||
return share * Decimal(100)
|
||||
return _ZERO
|
||||
|
||||
|
||||
def _covered_ratio_pct(
|
||||
rows: list, attached_refs: set[str], build: UnitPriceBuild
|
||||
) -> Decimal | None:
|
||||
|
||||
Reference in New Issue
Block a user