finance.depreciation-straight-line@1.0.0
impl/python.py
2,677 bytes · the Python implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import List
from .finance_depreciation_straight_line_types import DepreciationPeriod
from .money_add import subtract_money ← from money.add ^1.0.0 · built alongside by fune
from .money_allocate import allocate ← from money.allocate ^1.0.0 · built alongside by fune
from .money_amount import Money ← from money.amount ^1.0.0 · built alongside by fune
def straight_line_depreciation(cost: Money, residual_value: Money, years: int) -> List[DepreciationPeriod]:
"""A straight-line depreciation schedule, year by year.
The depreciable amount is split with ``money.allocate`` instead of being
divided by the number of years. Dividing leaves 1000.00 over three years as
333.33 three times - a penny short - and an asset that never quite finishes
writing down to its residual value. ``allocate`` hands out every minor unit,
so the last closing value equals the residual value exactly, by construction
rather than by a fudge at the end.
The odd units go to the earliest years, following ``allocate``'s largest-
remainder rule rather than a second rule invented here.
"""
if isinstance(years, bool) or not isinstance(years, int) or years < 1:
raise ValueError("years must be at least 1, received %r" % (years,))
if cost.minor < 0:
raise ValueError("cost must not be negative")
if residual_value.minor < 0:
raise ValueError("residual value must not be negative")
# subtract_money also rejects a cost and a residual value in different
# currencies, which would otherwise produce a plausible-looking schedule.
depreciable = subtract_money(cost, residual_value)
if depreciable.minor < 0:
raise ValueError("residual value must not exceed cost")
charges = allocate(depreciable, [1] * years)
schedule: List[DepreciationPeriod] = []
opening_value = cost
for index in range(years):
charge = charges[index]
closing_value = subtract_money(opening_value, charge)
schedule.append(
DepreciationPeriod(
year=index + 1,
opening_value=opening_value,
charge=charge,
closing_value=closing_value,
)
)
opening_value = closing_value
return schedule
def written_down_value(cost: Money, residual_value: Money, years: int, elapsed_years: int) -> Money:
"""The written-down value after ``elapsed_years`` complete years."""
schedule = straight_line_depreciation(cost, residual_value, years)
if isinstance(elapsed_years, bool) or not isinstance(elapsed_years, int) or not 0 <= elapsed_years <= years:
raise ValueError("elapsed_years must be between 0 and %d, received %r" % (years, elapsed_years))
return cost if elapsed_years == 0 else schedule[elapsed_years - 1].closing_value