Odoo amount_to_text not working correctly with 4 decimal places

61 Views Asked by At

We are trying to implement OpenERP's function "amount_to_text" for total amount in our reports, but have a problem when the odoo interprets an amount like 20.38 as TWENTY DOLLARS AND THREE THOUSAND EIGHT HUNDRED CENTS, since the prices are with 4 decimal places, like 0.0640.

How can we have the function "amount_to_text" to return the correct text for the amount, or How can we round up only the total sum to 2 decimal places in order for the "amount_to_text" to run correctly?

Thx in advance!

I've tried to setting the rounding precision to 0.01, but it rounds up all prices in the DB.

1

There are 1 best solutions below

0
aekis.dev On

The method amount_to_text of the res.currency model reformat your value according to the currency decimal_places field value, which it's a computed field that depends on the rounding field to calculate the number of decimal places that will be taken into account to return the text representation of the amount.

So you have this 3 options(could be more):

  1. Change the stored value of the currency decimal_places field
    currency.write({'decimal_places': 2})
    text = currency.amount_to_text(20.38)

But this will affect all of the next conversion operations if the value it's not restored back to what it was

  1. Change the amount_to_text definition to check if there is a context value for decimal_places
class Currency(models.Model):
    _inherit = "res.currency"

    def amount_to_text(self, amount):
        self.ensure_one()
        def _num2words(number, lang):
            try:
                return num2words(number, lang=lang).title()
            except NotImplementedError:
                return num2words(number, lang='en').title()

        if num2words is None:
            logging.getLogger(__name__).warning("The library 'num2words' is missing, cannot render textual amounts.")
            return ""

        # Here are the changes
        decimal_places = self.decimal_places
        if self.env.context.get('decimal_places', False):
            decimal_places = self.env.context['decimal_places']
        # End of the changes

        formatted = "%.{0}f".format(decimal_places) % amount
        parts = formatted.partition('.')
        integer_value = int(parts[0])
        fractional_value = int(parts[2] or 0)

        lang = tools.get_lang(self.env)
        amount_words = tools.ustr('{amt_value} {amt_word}').format(
                        amt_value=_num2words(integer_value, lang=lang.iso_code),
                        amt_word=self.currency_unit_label,
                        )
        if not self.is_zero(amount - integer_value):
            amount_words += ' ' + _('and') + tools.ustr(' {amt_value} {amt_word}').format(
                        amt_value=_num2words(fractional_value, lang=lang.iso_code),
                        amt_word=self.currency_subunit_label,
                        )
        return amount_words

And use it like: text = currency.with_context(decimal_places=2).amount_to_text(20.38)

  1. Build your own function based on the option 2 suggested above