from .fleet_cost_per_mile_types import CostPerMile, WholeLifeCosts from .math_round_div import round_div from .money_amount import Money from .money_sum import sum_money def _tenths(amount: Money, miles: int) -> int: return round_div(amount.minor * 10, miles, "half-up") def _display(value: int) -> str: sign = "-" if value < 0 else "" magnitude = abs(value) return "%s%d.%d" % (sign, magnitude // 10, magnitude % 10) def cost_per_mile(costs: WholeLifeCosts, miles: int) -> CostPerMile: """Whole-life cost per mile, in tenths of a penny, the unit fleet reports use. Each part is rounded on its own for the breakdown, and the total is rounded from the total cost: adding up the rounded parts drifts by a tenth or two, which is why the total is not their sum. """ if isinstance(miles, bool) or not isinstance(miles, int) or miles <= 0: raise ValueError("miles must be a whole number above zero, received %r" % (miles,)) total_cost = sum_money( [costs.depreciation, costs.fuel, costs.maintenance, costs.insurance, costs.tax], costs.depreciation.currency, ) total_tenths = _tenths(total_cost, miles) return CostPerMile( total_cost=total_cost, depreciation_tenths=_tenths(costs.depreciation, miles), fuel_tenths=_tenths(costs.fuel, miles), maintenance_tenths=_tenths(costs.maintenance, miles), insurance_tenths=_tenths(costs.insurance, miles), tax_tenths=_tenths(costs.tax, miles), total_tenths=total_tenths, per_mile=_display(total_tenths), )