From 458f6b0327d08b9599976408bd2471eb4bcce9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Sun, 25 Dec 2022 18:54:30 +0100 Subject: [PATCH] Allow rounding with opposite method --- modules/currency/CHANGELOG | 2 ++ modules/currency/currency.py | 18 ++++++++++++++++-- modules/currency/tests/test_module.py | 25 ++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/modules/currency/CHANGELOG b/modules/currency/CHANGELOG index 3ee21564b6..54e039452f 100644 --- a/modules/currency/CHANGELOG +++ b/modules/currency/CHANGELOG @@ -1,3 +1,5 @@ +* Allow rounding with opposite method + Version 6.6.0 - 2022-10-31 -------------------------- * Bug fixes (see mercurial logs for details) diff --git a/modules/currency/currency.py b/modules/currency/currency.py index 97239871ec..dd0429a8ed 100644 --- a/modules/currency/currency.py +++ b/modules/currency/currency.py @@ -1,8 +1,9 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime +import decimal import logging -from decimal import ROUND_HALF_EVEN, Decimal, localcontext +from decimal import Decimal, localcontext from dateutil.relativedelta import relativedelta from sql import Window @@ -24,6 +25,17 @@ from .ir import rate_decimal logger = logging.getLogger(__name__) +ROUNDING_OPPOSITES = { + decimal.ROUND_HALF_EVEN: decimal.ROUND_HALF_EVEN, + decimal.ROUND_HALF_UP: decimal.ROUND_HALF_DOWN, + decimal.ROUND_HALF_DOWN: decimal.ROUND_HALF_UP, + decimal.ROUND_UP: decimal.ROUND_DOWN, + decimal.ROUND_DOWN: decimal.ROUND_UP, + decimal.ROUND_CEILING: decimal.ROUND_FLOOR, + decimal.ROUND_FLOOR: decimal.ROUND_CEILING, + } + + class Currency( SymbolMixin, DigitsMixin, DeactivableMixin, ModelSQL, ModelView): 'Currency' @@ -148,8 +160,10 @@ class Currency( res[currency_id] = id2rate[res[currency_id]].rate return res - def round(self, amount, rounding=ROUND_HALF_EVEN): + def round(self, amount, rounding=decimal.ROUND_HALF_EVEN, opposite=False): 'Round the amount depending of the currency' + if opposite: + rounding = ROUNDING_OPPOSITES[rounding] return self._round(amount, self.rounding, rounding) @classmethod diff --git a/modules/currency/tests/test_module.py b/modules/currency/tests/test_module.py index ce53d0a32f..bdbefced3c 100644 --- a/modules/currency/tests/test_module.py +++ b/modules/currency/tests/test_module.py @@ -3,7 +3,7 @@ import datetime import unittest -from decimal import Decimal +from decimal import ROUND_HALF_DOWN, Decimal from trytond import backend from trytond.modules.currency.ecb import ( @@ -143,6 +143,29 @@ class CurrencyTestCase(ModuleTestCase): self.assertEqual(rounded, Decimal('1.2345')) + @with_transaction() + def test_round_opposite(self): + "Test the opposite rounding" + cu = create_currency('cu') + cu.save() + + rounded = cu.round(Decimal('1.235')) + self.assertEqual(rounded, Decimal('1.24')) + opposite_rounded = cu.round(Decimal('1.235'), opposite=True) + self.assertEqual(opposite_rounded, Decimal('1.24')) + + @with_transaction() + def test_round_opposite_HALF_DOWN(self): + "Test the oposite rounding of ROUND_HALF_DOWN" + cu = create_currency('cu') + cu.save() + + rounded = cu.round(Decimal('1.235'), rounding=ROUND_HALF_DOWN) + self.assertEqual(rounded, Decimal('1.23')) + opposite_rounded = cu.round( + Decimal('1.235'), rounding=ROUND_HALF_DOWN, opposite=True) + self.assertEqual(opposite_rounded, Decimal('1.24')) + @with_transaction() def test_is_zero(self): "Test is zero"