[IMP] odoo.tools: add rounding_mode and amount_rounding to formatLang

Adds the possibility to give formatLang() a 'rounding_mode' (any Decimal rounding mode)
and an amount_rounding ('decimals', 'units', 'thousands', 'millions' and 'lakhs').

'amount_rounding' will display the amount in the given unit. For example, 10456 in 'thousands' will be 10.

task-3626894

closes odoo/odoo#151314

Related: odoo/enterprise#55218
Signed-off-by: John Laterre (jol) <jol@odoo.com>
This commit is contained in:
Ruben Gomes (rugo)
2024-02-16 12:12:41 +00:00
parent a454456148
commit b54df52774
2 changed files with 68 additions and 12 deletions
+22
View File
@@ -583,6 +583,28 @@ class TestFormatLang(TransactionCase):
# If we have a 'dp' and 'currency_obj', we use the decimal precision of 'dp' and the format of 'currency_obj'.
self.assertEqual(misc.formatLang(self.env, 100, dp=decimal_precision.name, currency_obj=currency_object), '100.000%sfL' % u'\N{NO-BREAK SPACE}')
def test_rounding_method(self):
self.assertEqual(misc.formatLang(self.env, 100.205), '100.20') # Default is 'HALF-EVEN'
self.assertEqual(misc.formatLang(self.env, 100.215), '100.22') # Default is 'HALF-EVEN'
self.assertEqual(misc.formatLang(self.env, 100.205, rounding_method='HALF-UP'), '100.21')
self.assertEqual(misc.formatLang(self.env, 100.215, rounding_method='HALF-UP'), '100.22')
self.assertEqual(misc.formatLang(self.env, 100.205, rounding_method='HALF-DOWN'), '100.20')
self.assertEqual(misc.formatLang(self.env, 100.215, rounding_method='HALF-DOWN'), '100.21')
def test_rounding_unit(self):
self.assertEqual(misc.formatLang(self.env, 1000000.00), '1,000,000.00')
self.assertEqual(misc.formatLang(self.env, 1000000.00, rounding_unit='units'), '1,000,000')
self.assertEqual(misc.formatLang(self.env, 1000000.00, rounding_unit='thousands'), '1,000')
self.assertEqual(misc.formatLang(self.env, 1000000.00, rounding_unit='lakhs'), '10')
self.assertEqual(misc.formatLang(self.env, 1000000.00, rounding_unit="millions"), '1')
def test_rounding_method_and_rounding_unit(self):
self.assertEqual(misc.formatLang(self.env, 1822060000, rounding_method='HALF-UP', rounding_unit='lakhs'), '18,221')
self.assertEqual(misc.formatLang(self.env, 1822050000, rounding_method='HALF-UP', rounding_unit='lakhs'), '18,221')
self.assertEqual(misc.formatLang(self.env, 1822049900, rounding_method='HALF-UP', rounding_unit='lakhs'), '18,220')
class TestUrlValidate(BaseCase):
def test_url_validate(self):
+46 -12
View File
@@ -1373,24 +1373,58 @@ def babel_locale_parse(lang_code):
except:
return babel.Locale.parse("en_US")
def formatLang(env, value, digits=2, grouping=True, monetary=False, dp=None, currency_obj=None):
def formatLang(env, value, digits=2, grouping=True, monetary=False, dp=None, currency_obj=None, rounding_method='HALF-EVEN', rounding_unit='decimals'):
"""
Assuming 'Account' decimal.precision=3:
formatLang(value) -> digits=2 (default)
formatLang(value, digits=4) -> digits=4
formatLang(value, dp='Account') -> digits=3
formatLang(value, digits=5, dp='Account') -> digits=5
This function will format a number `value` to the appropriate format of the language used.
:param Object env: The environment.
:param float value: The value to be formatted.
:param int digits: The number of decimals digits.
:param bool grouping: Usage of language grouping or not.
:param bool monetary: Usage of thousands separator or not.
.. deprecated:: 13.0
:param str dp: Name of the decimals precision to be used. This will override ``digits``
and ``currency_obj`` precision.
:param Object currency_obj: Currency to be used. This will override ``digits`` precision.
:param str rounding_method: The rounding method to be used:
**'HALF-UP'** will round to the closest number with ties going away from zero,
**'HALF-DOWN'** will round to the closest number with ties going towards zero,
**'HALF_EVEN'** will round to the closest number with ties going to the closest
even number,
**'UP'** will always round away from 0,
**'DOWN'** will always round towards 0.
:param str rounding_unit: The rounding unit to be used:
**decimals** will round to decimals with ``digits`` or ``dp`` precision,
**units** will round to units without any decimals,
**thousands** will round to thousands without any decimals,
**lakhs** will round to lakhs without any decimals,
**millions** will round to millions without any decimals.
:returns: The value formatted.
:rtype: str
"""
# We don't want to return 0
if isinstance(value, str) and not value:
if value == '':
return ''
if dp:
digits = env['decimal.precision'].precision_get(dp)
elif currency_obj:
digits = currency_obj.decimal_places
if rounding_unit == 'decimals':
if dp:
digits = env['decimal.precision'].precision_get(dp)
elif currency_obj:
digits = currency_obj.decimal_places
else:
digits = 0
rounded_value = float_round(value, precision_digits=digits, rounding_method='HALF-EVEN')
rounding_unit_mapping = {
'decimals': 1,
'thousands': 10**3,
'lakhs': 10**5,
'millions': 10**6,
}
value /= rounding_unit_mapping.get(rounding_unit, 1)
rounded_value = float_round(value, precision_digits=digits, rounding_method=rounding_method)
formatted_value = get_lang(env).format(f'%.{digits}f', rounded_value, grouping=grouping, monetary=monetary)
if currency_obj and currency_obj.symbol: