Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
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 .retail_price_rounding_types import PriceDirection
def _whole(value: object) -> bool:
return isinstance(value, int) and not isinstance(value, bool)
def round_price(price: Money, step: int, ending: int, direction: PriceDirection) -> Money:
"""Snap a price to the points k x step - ending.
Shifting by ``ending`` turns every point into a multiple of ``step``, so
the whole policy is one integer division with the right rounding mode.
"""
if not _whole(step) or step < 1:
raise ValueError("step must be 1 or more, received %r" % (step,))
if not _whole(ending) or ending < 0 or ending >= step:
raise ValueError("ending must be from 0 to step - 1, received %r" % (ending,))
if price.minor < 0:
raise ValueError("price must not be negative, received %d" % price.minor)
shifted = price.minor + ending
if direction == "up":
point = round_div(shifted, step, "up") * step - ending
elif direction == "down":
point = round_div(shifted, step, "down") * step - ending
if point < 0:
raise ValueError("no price point at or below %d" % price.minor)
elif direction == "nearest":
point = round_div(shifted, step, "half-up") * step - ending
# Below the first point the only candidate is above.
if point < 0:
point = step - ending
else:
raise ValueError('unknown direction "%s"' % (direction,))
return money(point, price.currency)