61 lines
1.5 KiB
Python
61 lines
1.5 KiB
Python
"""Cost calculation for meter rate components."""
|
|
|
|
import logging
|
|
from dataclasses import dataclass
|
|
|
|
from hameter.config import RateComponent
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass
|
|
class CostResult:
|
|
"""Result of a cost calculation for a single reading delta."""
|
|
|
|
delta: float
|
|
per_unit_cost: float
|
|
component_costs: list[dict]
|
|
total_incremental_cost: float
|
|
|
|
|
|
def calculate_incremental_cost(
|
|
delta: float,
|
|
cost_factors: list[RateComponent],
|
|
) -> CostResult:
|
|
"""Calculate the incremental cost for a usage delta.
|
|
|
|
Only per_unit rate components contribute to incremental cost.
|
|
Fixed charges are NOT included — they are handled separately
|
|
via the billing period reset / manual add workflow.
|
|
|
|
Args:
|
|
delta: Usage delta in calibrated units (e.g., kWh).
|
|
cost_factors: List of rate components from meter config.
|
|
|
|
Returns:
|
|
CostResult with per-component breakdown and total.
|
|
"""
|
|
component_costs = []
|
|
per_unit_total = 0.0
|
|
|
|
for cf in cost_factors:
|
|
if cf.type == "per_unit":
|
|
cost = round(delta * cf.rate, 4)
|
|
per_unit_total += cost
|
|
else:
|
|
cost = 0.0
|
|
|
|
component_costs.append({
|
|
"name": cf.name,
|
|
"rate": cf.rate,
|
|
"type": cf.type,
|
|
"cost": cost,
|
|
})
|
|
|
|
return CostResult(
|
|
delta=delta,
|
|
per_unit_cost=round(per_unit_total, 4),
|
|
component_costs=component_costs,
|
|
total_incremental_cost=round(per_unit_total, 4),
|
|
)
|