from .finance_markup_price_types import PricingBasis from .math_round_div import RoundingMode, round_div from .money_amount import Money, money MAX_SAFE = 9007199254740991 def markup_price(cost: Money, basis_points: int, basis: PricingBasis, mode: RoundingMode) -> Money: """The selling price that hits a target margin or markup on ``cost``. Margin divides by the price and markup by the cost, so the same 5000 basis points means 200.00 or 150.00 on a cost of 100.00; the basis is explicit. """ if isinstance(basis_points, bool) or not isinstance(basis_points, int): raise TypeError("basis_points must be an integer, received %r" % (basis_points,)) if cost.minor < 0: raise ValueError("cost must not be negative, received %d" % (cost.minor,)) if basis == "markup": if basis_points < -10000: raise ValueError("a markup of %d basis points gives a negative price" % (basis_points,)) numerator = cost.minor * (10000 + basis_points) denominator = 10000 elif basis == "margin": if basis_points >= 10000: raise ValueError("a margin of %d basis points has no finite price" % (basis_points,)) numerator = cost.minor * 10000 denominator = 10000 - basis_points else: raise ValueError('unknown pricing basis "%s"' % (basis,)) # Python would carry on, but TypeScript cannot, and all three must agree. if numerator > MAX_SAFE: raise ValueError("the price calculation exceeds 2^53 - 1") return money(round_div(numerator, denominator, mode), cost.currency)