Functional Weave
Code in Rust

money.convert@1.0.0

impl/python.py

1,303 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 .math_rational import multiply_rational, rational, rational_to_integer  ← from math.rational ^1.0.0 · built alongside by fune
from .math_round_div import RoundingMode  ← 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_convert_types import ExchangeRate
from .money_currency_digits import currency_digits  ← from money.currency-digits ^1.0.0 · built alongside by fune


def convert_money(amount: Money, rate: ExchangeRate, mode: RoundingMode) -> Money:
    """Convert ``amount`` into the rate's quote currency.

    Exact up to one final rounding into the quote currency's minor unit; the
    rate is a fraction in major units and each currency's decimal places are
    looked up rather than assumed to be two.
    """
    if amount.currency != rate.base:
        raise ValueError("exchange rate converts %s to %s, not %s" % (rate.base, rate.quote, amount.currency))
    r = rational(rate.rate.numerator, rate.rate.denominator)
    if r.numerator <= 0:
        raise ValueError("exchange rate must be positive")
    from_digits = currency_digits(rate.base)
    to_digits = currency_digits(rate.quote)

    # minor units of quote per minor unit of base: rate x 10^to_digits / 10^from_digits
    scale = rational(10**to_digits, 10**from_digits)
    per_minor = multiply_rational(r, scale)
    exact = multiply_rational(rational(amount.minor, 1), per_minor)
    return money(rational_to_integer(exact, mode), rate.quote)