Fix precision issue

This commit is contained in:
Raphael Michel
2026-09-17 10:53:38 +02:00
parent 4017851bcc
commit 91e58dcd1b
2 changed files with 21 additions and 0 deletions
+13
View File
@@ -49,6 +49,13 @@ def money_filter(value: Optional[Decimal | float | int | str], arg='', hide_curr
raise ValueError("No currency passed.")
arg = arg.upper()
if value.normalize().as_tuple().exponent < -9:
# Heuristic: It's unlikely we'll ever see values of less than 0.000000001 in any currency. Therefore, if we
# do see them, we very likely deal with a floating point error. This happens mostly in dev mode when computations
# are made in SQLite, which uses REAL precision, but it can also happen when we naively pass a float from Python
# land to this filter (even though it should not happen).
value = value.quantize(Decimal('1e-9'), ROUND_HALF_UP).normalize()
currency_places = settings.CURRENCY_PLACES.get(arg, 2)
required_places = -value.normalize().as_tuple().exponent
render_places = max(currency_places, required_places)
@@ -108,6 +115,12 @@ def tax_rate_format(number: Optional[Decimal | float | int | str]):
number = Decimal('0.00')
if not isinstance(number, Decimal):
raise TypeError("Invalid data type passed to tax rate format filter: %r" % type(number))
if number.normalize().as_tuple().exponent < -9:
# Heuristic: It's unlikely we'll ever see values of less than 0.000000001 in any currency. Therefore, if we
# do see them, we very likely deal with a floating point error. This happens mostly in dev mode when computations
# are made in SQLite, which uses REAL precision, but it can also happen when we naively pass a float from Python
# land to this filter (even though it should not happen).
number = number.quantize(Decimal('1e-9'), ROUND_HALF_UP).normalize()
return mark_safe(
formats.number_format(
number,
+8
View File
@@ -60,7 +60,9 @@ def test_urlreplace_replace_parameter():
"locale,amount,currency,expected",
[
("en", None, "USD", "$0.00"),
("en", "", "USD", ""),
("en", 1000000, "USD", "$1,000,000.00"),
("en", 2.23, "USD", "$2.23"),
("en", Decimal("1000.00"), "USD", "$1,000.00"),
("de", Decimal("1.23"), "EUR", "1,23" + NBSP + "€"),
("de", Decimal("1000.00"), "EUR", "1.000,00" + NBSP + "€"),
@@ -74,6 +76,7 @@ def test_urlreplace_replace_parameter():
# deal with precision that is higher than the currency
("de", Decimal("1.234"), "EUR", "1,234" + NBSP + "€"),
("de", 1.234, "EUR", "1,234" + NBSP + "€"),
("de", Decimal("1.2340"), "EUR", "1,234" + NBSP + "€"),
("de", Decimal("1.2300"), "EUR", "1,23" + NBSP + "€"),
("de", Decimal("1023.1"), "JPY", "1.023,10" + NBSP + "¥"),
@@ -118,6 +121,11 @@ def test_money_filter_hidecurrency(locale, amount, currency, expected):
("en", Decimal("2.50"), "2.5"),
("en", Decimal("4.3e7"), "43000000"),
("en", Decimal("2.2340"), "2.234"),
("en", "2.23", "2.23"),
("en", 2.23, "2.23"),
("en", 2, "2"),
("en", "", ""),
("en", None, "0"),
]
)
def test_tax_rate_format(locale, rate, expected):