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, Sequence
from .math_round_div import round_div ← from math.round-div ^1.0.0 · built alongside by fune
from .money_amount import Money, money ← from money.amount ^1.0.0 · built alongside by fune
from .money_sum import sum_money ← from money.sum ^1.0.0 · built alongside by fune
from .payroll_overtime_types import OvertimeBand, OvertimeLine, OvertimePay
def overtime_pay(minutes_worked: int, hourly_rate: Money, bands: Sequence[OvertimeBand]) -> OvertimePay:
"""Price the minutes worked band by band, rounding once per payslip line."""
if isinstance(minutes_worked, bool) or not isinstance(minutes_worked, int) or minutes_worked < 0:
raise ValueError("minutesWorked must be a whole number of minutes, not negative, received %s" % (minutes_worked,))
if len(bands) == 0:
raise ValueError("overtime needs at least one band")
if bands[0].from_minutes != 0:
raise ValueError("the first band must start at 0 minutes")
for i in range(1, len(bands)):
if bands[i].from_minutes <= bands[i - 1].from_minutes:
raise ValueError("bands must be in strictly ascending order of fromMinutes")
lines: List[OvertimeLine] = []
for i, band in enumerate(bands):
start = band.from_minutes
end = min(bands[i + 1].from_minutes, minutes_worked) if i + 1 < len(bands) else minutes_worked
minutes = end - start
if minutes <= 0:
break
multiplier = band.multiplier_basis_points
if isinstance(multiplier, bool) or not isinstance(multiplier, int) or multiplier < 0:
raise ValueError("multiplierBasisPoints must be a whole number, not negative, received %s" % (multiplier,))
pay = money(round_div(hourly_rate.minor * minutes * multiplier, 60 * 10000, "half-up"), hourly_rate.currency)
lines.append(OvertimeLine(minutes=minutes, multiplier_basis_points=multiplier, pay=pay))
return OvertimePay(lines=lines, total=sum_money([l.pay for l in lines], hourly_rate.currency))