def test_sub_units() -> None: assert str(Money(471100, from_sub_units=True)) == "4711.00" assert Money(471100, from_sub_units=False) == 471100 assert Money(471100, from_sub_units=True).to_sub_units() == 471100 assert str(Money(471100, currency=Currency.SEK, from_sub_units=True)) == "4711.00 SEK" assert str(Money(471100, currency=Currency.SEK, from_sub_units=False)) == "471100.00 SEK" assert Money(471100, currency=Currency.SEK, from_sub_units=True).to_sub_units() == 471100 assert str(Money(471100, Currency.JPY, from_sub_units=True)) == "471100 JPY" assert Money(471100, Currency.JPY, from_sub_units=False) == 471100 assert Money(471100, Currency.JPY, from_sub_units=True).to_sub_units() == 471100 assert str( Money(471100, Currency.JPY, from_sub_units=True).to_sub_units()) == "471100 JPY" assert str(Money(471100, Currency.IQD, from_sub_units=True)) == "471.100 IQD" assert Money(471100, Currency.IQD, from_sub_units=False) == 471100 assert round( Money(471100, Currency.IQD, from_sub_units=True).to_sub_units()) == 471100
def test_string_formatting() -> None: m = Money("123456.50", currency="GBP") assert f"{m}" == "123456.50 GBP" assert f"{m:}" == "123456.50 GBP" assert f"{m:f}" == "123456.50" assert f"{m:.2f}" == "123456.50" assert f"{m:.0f}" == "123457" assert f"{m:.5f}" == "123456.50000" assert f"{m:m}" == "123456.50 GBP" assert f"{m:.2m}" == "123456.50 GBP" assert f"{m:.0m}" == "123457 GBP" assert f"{m:.5m}" == "123456.50000 GBP" assert f"{m:-.5m}" == "123456.50000 GBP" assert f"{m:+.5m}" == "+123456.50000 GBP" assert f"{m: .5m}" == " 123456.50000 GBP" assert f"{m:M}" == "GBP 123456.50" assert f"{m:.2M}" == "GBP 123456.50" assert f"{m:.0M}" == "GBP 123457" assert f"{m:.5M}" == "GBP 123456.50000" assert f"{m:-.5M}" == "GBP 123456.50000" assert f"{m:+.5M}" == "GBP +123456.50000" assert f"{m: .5M}" == "GBP 123456.50000" assert f"{m:d}" == "123457" assert f"{m:+d}" == "+123457" assert f"{m: d}" == " 123457" assert f"{m:s}" == "123456.50 GBP" assert f"{m:c}" == "GBP" m = Money(123456, currency="GBP") assert f"{m}" == "123456.00 GBP" assert f"{m:f}" == "123456.00" assert f"{m:.0f}" == "123456" assert f"{m:.1f}" == "123456.0" assert f"{m:.2f}" == "123456.00" m = Money("123457.50", currency="GBP") assert f"{m}" == "123457.50 GBP" assert f"{m:.2f}" == "123457.50" assert f"{m:.0f}" == "123458" assert f"{m:.5f}" == "123457.50000" assert f"{m:d}" == "123458" m = Money(123457, currency="GBP") assert f"{m:.2f}" == "123457.00" m = Money("-0.01", currency="SEK") assert f"{m:.4m}" == "-0.0100 SEK" assert f"{m:m}" == "-0.01 SEK" assert f"{m:.1m}" == "0.0 SEK" assert f"{m:.0m}" == "0 SEK" assert f"{m:+m}" == "-0.01 SEK" assert f"{m:+.1m}" == "+0.0 SEK" assert f"{m:+.0m}" == "+0 SEK" m = Money("0.005", currency="SEK") assert f"{m:.4m}" == "0.0050 SEK" assert f"{m:m}" == "0.005 SEK" assert f"{m:.2m}" == "0.01 SEK" assert f"{m:.1m}" == "0.0 SEK" assert f"{m:.0m}" == "0 SEK" assert f"{m:+.4m}" == "+0.0050 SEK" m = Money("0.0050", currency="ETH") assert f"{m:5.4m}" == "0.0050 ETH" assert f"{m:+5.4m}" == "+0.0050 ETH" assert f"{m:05.2m}" == "00.01 ETH" assert f"{m:+05.2m}" == "+0.01 ETH" assert f"{m:05.3m}" == "0.005 ETH" assert f"{m:+05.3m}" == "+0.005 ETH" assert f"{m:10.4m}" == " 0.0050 ETH" assert f"{-m:10.4m}" == " -0.0050 ETH" assert f"{m:+10.4m}" == " +0.0050 ETH" assert f"{m:10.4M}" == "ETH 0.0050" assert f"{-m:10.4M}" == "ETH -0.0050" assert f"{m:+10.4M}" == "ETH +0.0050" assert f"{m:10.0m}" == " 0 ETH" assert f"{-m:10.0m}" == " 0 ETH" assert f"{m:+10.0m}" == " +0 ETH" assert f"{-m:+10.0m}" == " +0 ETH" assert f"{m:010.4m}" == "00000.0050 ETH" assert f"{-m:010.4m}" == "-0000.0050 ETH" assert f"{m:+010.4m}" == "+0000.0050 ETH" assert f"{m: 010.4m}" == " 0000.0050 ETH" assert f"{m:+10.4m}" == " +0.0050 ETH" assert f"{-m:010.4M}" == "ETH -0000.0050" assert f"{m:+010.4M}" == "ETH +0000.0050" assert f"{m:010.0m}" == "0000000000 ETH" assert f"{-m:010.0m}" == "0000000000 ETH" assert f"{-m:+010.0m}" == "+000000000 ETH" assert f"{-m:010.0f}" == "0000000000" m = Money("22.12345", currency="ETH") assert f"{m:010.5m}" == "0022.12345 ETH" assert f"{-m:010.5m}" == "-022.12345 ETH" assert f"{-m:10.5m}" == " -22.12345 ETH" assert f"{m:010.4m}" == "00022.1235 ETH" assert f"{-m:010.4m}" == "-0022.1235 ETH" assert f"{-m:10.4m}" == " -22.1235 ETH" assert f"{m:010.3m}" == "000022.123 ETH" assert f"{m:+010.3m}" == "+00022.123 ETH" assert f"{-m:010.3m}" == "-00022.123 ETH" assert f"{-m:10.3m}" == " -22.123 ETH" assert f"{m:+10.3m}" == " +22.123 ETH" assert f"{m:+10.3f}" == " +22.123" assert f"{m:x<15}" == "22.12345 ETHxxx" assert f"{m:<15}" == "22.12345 ETH " assert f"{m: <15}" == "22.12345 ETH " assert f"{m: >15}" == " 22.12345 ETH" assert f"{m:x<15.3f}" == "22.123xxxxxxxxx" assert f"{m:<15}" == "22.12345 ETH " assert f"{-m:=10m}" == "- 22.12345 ETH" assert f"{m:=+10m}" == "+ 22.12345 ETH" assert f"{-m:x=10m}" == "-x22.12345 ETH" assert f"{m:x=+10m}" == "+x22.12345 ETH" m = Money("-100030055.05555", currency="SEK") assert f"{m:,m}" == "-100,030,055.05555 SEK" assert f"{m:,f}" == "-100,030,055.05555" assert f"{m:,.2m}" == "-100,030,055.06 SEK" assert f"{m:,.2M}" == "SEK -100,030,055.06" assert f"{m:,.2f}" == "-100,030,055.06" assert f"{m:,.0m}" == "-100,030,055 SEK" assert f"{m:,.0f}" == "-100,030,055" m = Money("5100030055.05555", currency="SEK") assert f"{m:,m}" == "5,100,030,055.05555 SEK" assert f"{m:,f}" == "5,100,030,055.05555" m = Money("0.5", currency="SEK") assert f"{m:,m}" == "0.50 SEK" assert f"{m:,f}" == "0.50" assert f"{m:,.0m}" == "1 SEK" assert f"{m:,.0f}" == "1" m = Money("-999.5", currency="SEK") assert f"{m:,m}" == "-999.50 SEK" assert f"{m:,f}" == "-999.50" assert f"{m:,.0m}" == "-1,000 SEK" assert f"{m:,.0f}" == "-1,000" m = Money(1000) assert f"{m}" == "1000.00" assert f"{m:}" == "1000.00" assert f"{m:s}" == "1000.00" assert f"{m:f}" == "1000.00" assert f"{m:m}" == "1000.00" assert f"{m:.5m}" == "1000.00000" assert f"{m:.5f}" == "1000.00000" with pytest.raises(ValueError): f"{m:x<015.3f}" with pytest.raises(ValueError): f"{m:<015.3f}" with pytest.raises(ValueError): f"{m:=15}" with pytest.raises(ValueError): f"{m:X}" with pytest.raises(ValueError): f"{m:+s}" with pytest.raises(ValueError): f"{m:,s}"
def test_sorted_with_strings() -> None: lst = [ Money("1"), Money("-1"), Money("0"), Money("4711"), 77.95, Money("4711.55"), Money("4711", currency="SEK"), Money("4711"), Money("0 SEK"), "1338", 3.14, Money("1e-2", currency="SEK", is_cents=True), "0.3351 SEK", Money("-0.5 SEK"), -55, Money(0.4), ] expected = [ -55, Money("-1"), Money("-0.5 SEK"), Money("0"), Money("0 SEK"), Money("1e-2", currency="SEK", is_cents=True), "0.3351 SEK", Money(0.4), Money("1"), 3.14, 77.95, "1338", Money("4711"), Money("4711", currency="SEK"), Money("4711"), Money("4711.55"), ] assert sorted(lst, key=lambda x: Money(x)) == expected assert Money.sort(lst) == expected assert Money.sort(lst, reverse=True) == list(reversed(expected))
def test_sort_numbers() -> None: lst = [ Money("1"), Money("-1"), Money("0"), Money("4711"), 77.95, Money("4711.55"), Money("4711", currency="SEK"), Money("4711"), Money("0 SEK"), 3.14, Money("1e-2", currency="SEK", is_cents=True), Money("-0.5 SEK"), -55, Money(0.4), ] expected = [ -55, Money("-1"), Money("-0.5 SEK"), Money("0"), Money("0 SEK"), Money("1e-2", currency="SEK", is_cents=True), Money(0.4), Money("1"), 3.14, 77.95, Money("4711"), Money("4711", currency="SEK"), Money("4711"), Money("4711.55"), ] assert lst != expected lst.sort() assert lst == expected
def test_sort_with_strings() -> None: lst = [ Money("1"), Money("-1"), Money("0"), Money("4711"), 77.95, Money("4711.55"), Money("4711", currency="SEK"), Money("4711"), Money("0 SEK"), "1338", 3.14, Money("1e-2", currency="SEK", is_cents=True), "0.3351 SEK", Money("-0.5 SEK"), -55, Money(0.4), ] expected = [ -55, Money("-1"), Money("-0.5 SEK"), Money("0"), Money("0 SEK"), Money("1e-2", currency="SEK", is_cents=True), "0.3351 SEK", Money(0.4), Money("1"), 3.14, 77.95, "1338", Money("4711"), Money("4711", currency="SEK"), Money("4711"), Money("4711.55"), ] assert lst != expected with pytest.raises(TypeError): lst.sort() assert lst != expected lst.sort(key=lambda x: Money(x)) assert lst == expected
from typing import Any, Optional import pytest from stockholm import ConversionError, CurrencyMismatchError, Money @pytest.mark.parametrize( "values, expected, exception_expected", [ ([1, 2, 3, 4], 10, None), ([1, -1, 2, -2, 10, 4711, 1338, -10000], -3941, None), (["23.50 SEK", "50.00 SEK", "91.21 SEK", "9053 SEK", 20], Money("9237.71", currency="SEK"), None), ([Money(100, currency="EUR"), 20, "1.5000", "-0.008 EUR", 1.10], Money("122.592", currency="EUR"), None), (["1 EUR", "1 SEK"], None, CurrencyMismatchError), (["0 EUR", "0 SEK"], None, CurrencyMismatchError), (["0 EUR", "0 EUR"], "0 EUR", None), (["1 EUR", "1 EUR"], "2.00 EUR", None), (["3.14", "3.14", "3.14", "ABC"], None, ConversionError), ], ) def test_sum_list(values: Any, expected: Any, exception_expected: Optional[Exception]) -> None: try: m = Money.sum(values) if exception_expected: assert False, "Exception expected" assert isinstance(m, Money) assert m == expected except Exception as ex: if not exception_expected: raise
def get_transaction_amounts(content: str) -> List[Money]: amounts: List[Money] = [] total_amount: Money = Money(0) transaction_count: int = 0 transaction_count_validation: int = 0 for line_num, line in enumerate(content.split("\n"), 1): if not line.strip(): continue try: if line.startswith("00"): transaction_count = int(line[64:(64 + 6)]) elif line.startswith("99"): total_amount = Money(line[25:(25 + 11)], from_sub_units=True, currency=get_currency(line[36:(36 + 3)])) transaction_count_validation = int(line[16:(16 + 6)]) break elif line.startswith("4"): amount = Money(line[27:(27 + 9)], from_sub_units=True, currency=get_currency(line[50:(50 + 3)])) amounts.append((amount)) except Exception as exc: raise Exception( f"Invalid content format – [line number = {line_num}, line length = {len(line)}, exception = ({type(exc)} – '{exc}')]" ) if transaction_count != transaction_count_validation: raise Exception( f"Transaction count does not match – ['00': count = {transaction_count} | '99': count = {transaction_count_validation}]" ) if transaction_count != len(amounts): raise Exception( f"Transaction count does not match – ['00': count = {transaction_count} | '4X': count = {len(amounts)}]" ) if not transaction_count: return amounts total_amount_sum: Money = Money(0) try: total_amount_sum = Money.sum(amounts) except CurrencyMismatchError: currency_codes_string = "', '".join( {str(a.currency_code) for a in amounts}) raise Exception( f"Multiple currency codes within the same content block – ['00': currency = '{total_amount.currency}' | '4X': currencies = ('{currency_codes_string}')]" ) if total_amount.currency != total_amount_sum.currency: raise Exception( f"Currency codes does not match – ['00': currency = '{total_amount.currency}' | '4X': currency = '{total_amount_sum.currency}']" ) if not total_amount.currency: raise Exception( f"Currency codes missing – ['00': currency = '{total_amount.currency}' | '4X': currency = '{total_amount_sum.currency}']" ) if total_amount != total_amount_sum: diff = abs(total_amount - total_amount_sum) raise Exception( f"Sums of amounts differ with {diff} – ['00': amount = {total_amount} | '4X': amount = {total_amount_sum}]" ) return amounts