Add support for 'leading' digits in render_currency
This commit is contained in:
parent
75a7db6015
commit
2153a4e231
|
|
@ -556,9 +556,28 @@ The locale is resolved in the following priority order:
|
|||
1. **Explicit `locale=` argument** — highest priority, always wins
|
||||
2. **Server `LANGUAGE_CODE`** — fallback
|
||||
|
||||
#### Leading Digits
|
||||
|
||||
The `leading` argument specifies the minimum number of digits to render before the decimal point (zero-padded). This works identically to `leading` in [`format_number`](#format_number):
|
||||
|
||||
```html
|
||||
{% raw %}
|
||||
{% load report %}
|
||||
|
||||
<!-- default: no padding -->
|
||||
{% render_currency order.total_price currency='USD' %}
|
||||
<!-- output: $1.23 -->
|
||||
|
||||
<!-- force at least 4 integer digits -->
|
||||
{% render_currency order.total_price currency='USD' leading=4 %}
|
||||
<!-- output: $0,001.23 -->
|
||||
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
#### Custom Format Strings
|
||||
|
||||
The `fmt` argument accepts a [Unicode number pattern](https://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns) string (same syntax as [`format_number`](#custom-format-strings)). **When `fmt` is provided, it takes complete priority over `decimal_places` and `max_decimal_places`** — those arguments are ignored.
|
||||
The `fmt` argument accepts a [Unicode number pattern](https://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns) string (same syntax as [`format_number`](#custom-format-strings)). **When `fmt` is provided, it takes complete priority over `decimal_places`, `max_decimal_places`, and `leading`** — those arguments are ignored.
|
||||
|
||||
The `locale`, `currency`, `multiplier`, and `include_symbol` arguments are still applied when `fmt` is set.
|
||||
|
||||
|
|
|
|||
|
|
@ -797,12 +797,13 @@ def modulo(x: Any, y: Any, cast: Optional[type] = None) -> Any:
|
|||
|
||||
@register.simple_tag
|
||||
def render_currency(
|
||||
money,
|
||||
money: Money | str | int | float | Decimal,
|
||||
decimal_places: Optional[int] = None,
|
||||
currency: Optional[str] = None,
|
||||
multiplier: Optional[Decimal] = None,
|
||||
max_decimal_places: Optional[int] = None,
|
||||
include_symbol: bool = True,
|
||||
leading: Optional[int] = None,
|
||||
fmt: Optional[str] = None,
|
||||
locale: Optional[str] = None,
|
||||
**kwargs,
|
||||
|
|
@ -816,12 +817,14 @@ def render_currency(
|
|||
decimal_places: Minimum (forced) decimal places, e.g. decimal_places=2 gives '.00'. Defaults to the locale/currency standard.
|
||||
max_decimal_places: Maximum decimal places (optional digits beyond decimal_places), e.g. max_decimal_places=4 allows up to 4.
|
||||
include_symbol: If True, include the currency symbol in the output
|
||||
fmt: Optional Babel number pattern string. When provided, takes priority over all decimal_places options.
|
||||
leading: Minimum number of leading digits to render before the decimal point (default = 1)
|
||||
fmt: Optional Babel number pattern string. When provided, takes priority over all other formatting options.
|
||||
locale: Optional locale override (e.g. 'en-us', 'de-de'). Defaults to server LANGUAGE_CODE.
|
||||
"""
|
||||
if money in [None, '']:
|
||||
return '-'
|
||||
|
||||
# If the supplied value is *not* a Money instance, attempt to convert it into one
|
||||
if not isinstance(money, Money):
|
||||
try:
|
||||
money = Money(
|
||||
|
|
@ -829,9 +832,7 @@ def render_currency(
|
|||
currency or get_global_setting('INVENTREE_DEFAULT_CURRENCY'),
|
||||
)
|
||||
except Exception:
|
||||
raise ValidationError(
|
||||
'render_currency: invalid money value: ' + repr(money)
|
||||
)
|
||||
raise ValidationError(f'render_currency: invalid money value - {money!r}')
|
||||
|
||||
if currency is not None:
|
||||
try:
|
||||
|
|
@ -844,7 +845,7 @@ def render_currency(
|
|||
money *= Decimal(str(multiplier).strip())
|
||||
except Exception:
|
||||
raise ValidationError(
|
||||
'render_currency: invalid multiplier value: ' + repr(multiplier)
|
||||
f'render_currency: invalid multiplier value - {multiplier!r}'
|
||||
)
|
||||
|
||||
locale = get_locale(locale)
|
||||
|
|
@ -870,6 +871,15 @@ def render_currency(
|
|||
|
||||
pattern.frac_prec = (decimal_places, max(decimal_places, max_decimal_places))
|
||||
|
||||
if leading is not None:
|
||||
try:
|
||||
leading = int(leading) or 0
|
||||
except (ValueError, TypeError):
|
||||
leading = 0
|
||||
if leading > 0:
|
||||
min_int, max_int = pattern.int_prec
|
||||
pattern.int_prec = (max(leading, min_int), max(leading, max_int))
|
||||
|
||||
return pattern.apply(
|
||||
money.amount,
|
||||
locale,
|
||||
|
|
|
|||
|
|
@ -609,6 +609,24 @@ class ReportTagTest(PartImageTestMixin, InvenTreeTestCase):
|
|||
report_tags.render_currency(m, fmt='0.0000', decimal_places=2), '1234.5600'
|
||||
)
|
||||
|
||||
# Test leading digits
|
||||
m_small = Money(1.23, 'USD')
|
||||
self.assertEqual(
|
||||
report_tags.render_currency(m_small, leading=4, locale='en-us'), '$0,001.23'
|
||||
)
|
||||
# leading=1 is the default — no change
|
||||
self.assertEqual(
|
||||
report_tags.render_currency(m_small, leading=1, locale='en-us'), '$1.23'
|
||||
)
|
||||
# invalid leading falls back gracefully
|
||||
self.assertEqual(
|
||||
report_tags.render_currency(m_small, leading='x', locale='en-us'), '$1.23'
|
||||
)
|
||||
# fmt takes priority over leading
|
||||
self.assertEqual(
|
||||
report_tags.render_currency(m_small, leading=6, fmt='#,##0.00'), '1.23'
|
||||
)
|
||||
|
||||
def test_render_currency_locale_override(self):
|
||||
"""Explicit locale= kwarg takes priority over global setting and system locale."""
|
||||
m = Money(1234.56, 'USD')
|
||||
|
|
|
|||
Loading…
Reference in New Issue