From 7ebfced928b4588ccbfea5f4034c2d20f121b965 Mon Sep 17 00:00:00 2001 From: "Valentin Vallaeys (vava)" Date: Wed, 14 Sep 2022 12:17:44 +0000 Subject: [PATCH] [FIX] payment(_*): convert fixed fees into payment currency Payment fees appeared as float (and not monetary) in the Payment provider form and were not converted into the chosen payment currency. Some tests check the `_compute_fees` function. task-2854143 closes odoo/odoo#100156 Related: odoo/upgrade#4106 Signed-off-by: Victor Feyens (vfe) --- addons/payment/models/payment_provider.py | 25 +++++---- addons/payment/tests/common.py | 4 +- addons/payment/tests/test_payment_provider.py | 53 ++++++++++++++++++- .../payment/views/payment_provider_views.xml | 18 +++++-- addons/payment_alipay/tests/test_alipay.py | 10 ++-- addons/payment_paypal/tests/test_paypal.py | 8 +-- 6 files changed, 92 insertions(+), 26 deletions(-) diff --git a/addons/payment/models/payment_provider.py b/addons/payment/models/payment_provider.py index abec35a96a8..1b6aa7595a3 100644 --- a/addons/payment/models/payment_provider.py +++ b/addons/payment/models/payment_provider.py @@ -111,10 +111,14 @@ class PaymentProvider(models.Model): # Fees fields fees_active = fields.Boolean(string="Add Extra Fees") - fees_dom_fixed = fields.Float(string="Fixed domestic fees") - fees_dom_var = fields.Float(string="Variable domestic fees (in percents)") - fees_int_fixed = fields.Float(string="Fixed international fees") - fees_int_var = fields.Float(string="Variable international fees (in percents)") + fees_dom_fixed = fields.Monetary( + string="Fixed domestic fees", currency_field='main_currency_id' + ) + fees_dom_var = fields.Float(string="Variable domestic fees") + fees_int_fixed = fields.Monetary( + string="Fixed international fees", currency_field='main_currency_id' + ) + fees_int_var = fields.Float(string="Variable international fees") # Message fields display_as = fields.Char( @@ -315,7 +319,7 @@ class PaymentProvider(models.Model): :return None """ for provider in self: - if any(not 0 <= fee < 100 for fee in (provider.fees_dom_var, provider.fees_int_var)): + if any(not 0 <= fee < 1 for fee in (provider.fees_dom_var, provider.fees_int_var)): raise ValidationError(_("Variable fees must always be positive and below 100%.")) #=== CRUD METHODS ===# @@ -499,9 +503,9 @@ class PaymentProvider(models.Model): The computation is based on the fields `fees_dom_fixed`, `fees_dom_var`, `fees_int_fixed` and `fees_int_var`, and is performed with the formula - :code:`fees = (amount * variable / 100.0 + fixed) / (1 - variable / 100.0)` where the values - of `fixed` and `variable` are taken from either the domestic (`dom`) or international - (`int`) fields, depending on whether the country matches the company's country. + :code:`fees = (amount * variable + fixed) / (1 - variable)` where the values of `fixed` and + `variable` are taken from either the domestic (`dom`) or international (`int`) fields, + depending on whether the country matches the company's country. For a provider to base the computation on different variables, or to use a different formula, it must override this method and return the resulting fees. @@ -522,7 +526,10 @@ class PaymentProvider(models.Model): else: fixed = self.fees_int_fixed variable = self.fees_int_var - fees = (amount * variable / 100.0 + fixed) / (1 - variable / 100.0) + fixed_converted = self.main_currency_id._convert( + fixed, currency, self.company_id, fields.Date.context_today(self) + ) + fees = (amount * variable + fixed_converted) / (1 - variable) return fees def _get_validation_amount(self): diff --git a/addons/payment/tests/common.py b/addons/payment/tests/common.py index e298dca688b..44e3deaa405 100644 --- a/addons/payment/tests/common.py +++ b/addons/payment/tests/common.py @@ -6,13 +6,13 @@ from unittest.mock import patch from lxml import objectify from odoo.fields import Command -from odoo.tests.common import TransactionCase +from odoo.addons.base.tests.common import BaseCommon from odoo.tools.misc import hmac as hmac_tool _logger = logging.getLogger(__name__) -class PaymentCommon(TransactionCase): +class PaymentCommon(BaseCommon): @classmethod def setUpClass(cls): diff --git a/addons/payment/tests/test_payment_provider.py b/addons/payment/tests/test_payment_provider.py index aa4ebb9561b..ccce69d3dcd 100644 --- a/addons/payment/tests/test_payment_provider.py +++ b/addons/payment/tests/test_payment_provider.py @@ -1,12 +1,14 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from unittest.mock import patch + from odoo.tests import tagged from odoo.addons.payment.tests.common import PaymentCommon @tagged('-at_install', 'post_install') -class TestPaymentprovider(PaymentCommon): +class TestPaymentProvider(PaymentCommon): def test_published_provider_compatible_with_all_users(self): """ Test that a published provider is always available to all users. """ @@ -67,3 +69,52 @@ class TestPaymentprovider(PaymentCommon): self.company.id, self.partner.id, self.amount, currency_id=self.env.company.currency_id.id, ) self.assertNotIn(self.provider, compatible_providers) + + def test_fees_null_when_deactivated(self): + """ Test that extra fees of a provider are null if these fees are deactivated. """ + self.provider.write({ + 'fees_active': False, + 'fees_dom_fixed': 1.0, + 'fees_dom_var': 0.35, + 'fees_int_fixed': 0.1, + 'fees_int_var': 0.2, + }) + transaction_fees = self.provider._compute_fees( + self.amount, self.currency, self.partner.country_id + ) + self.assertEqual(transaction_fees, 0) + + def test_fees_formula(self): + """ Test that the extra fees of a provider are correctly computed in a domestic case. """ + self.provider.write({ + 'fees_active': True, + 'fees_dom_fixed': 1.0, + 'fees_dom_var': 0.0035, + 'fees_int_fixed': 0., + 'fees_int_var': 0., + }) + transaction_fees = self.currency.round( + self.provider._compute_fees( + self.amount, self.currency_usd, self.provider.company_id.country_id + ) + ) + self.assertEqual(transaction_fees, 4.91) + + def test_fees_with_currency_conversion(self): + """ Test that the conversion of the fees is correctly computed. """ + self.provider.write({ + 'fees_active': True, + 'fees_dom_fixed': 0., + 'fees_dom_var': 0., + 'fees_int_fixed': 1., + 'fees_int_var': 0., + }) + + with patch( + 'odoo.addons.base.models.res_currency.Currency._get_rates', + return_value={self.currency_euro.id: 2., self.currency_usd.id: 1.}, + ): + transaction_fees = self.currency.round( + self.provider._compute_fees(self.amount, self.currency_euro, self.country_france) + ) + self.assertEqual(transaction_fees, 2.) diff --git a/addons/payment/views/payment_provider_views.xml b/addons/payment/views/payment_provider_views.xml index 7896f9f1dd1..25a1668d094 100644 --- a/addons/payment/views/payment_provider_views.xml +++ b/addons/payment/views/payment_provider_views.xml @@ -94,11 +94,19 @@ - - - - - + + + + + + +