[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) <vfe@odoo.com>
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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.)
|
||||
|
||||
@@ -94,11 +94,19 @@
|
||||
</page>
|
||||
<page string="Fees" name="fees" attrs="{'invisible': [('support_fees', '=', False)]}">
|
||||
<group name="payment_fees">
|
||||
<field name="fees_active"/>
|
||||
<field name="fees_dom_fixed" attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<field name="fees_dom_var" attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<field name="fees_int_fixed" attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<field name="fees_int_var" attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<group class="oe_inline">
|
||||
<field name="fees_active"/>
|
||||
<field name="fees_dom_fixed"
|
||||
attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<field name="fees_dom_var"
|
||||
widget="percentage"
|
||||
attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<field name="fees_int_fixed"
|
||||
attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
<field name="fees_int_var"
|
||||
widget="percentage"
|
||||
attrs="{'invisible': [('fees_active', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Messages"
|
||||
|
||||
@@ -96,9 +96,9 @@ class AlipayTest(AlipayCommon, PaymentHttpCommon):
|
||||
self.alipay.write({
|
||||
'fees_active': True,
|
||||
'fees_dom_fixed': 1.0,
|
||||
'fees_dom_var': 0.35,
|
||||
'fees_dom_var': 0.0035,
|
||||
'fees_int_fixed': 1.5,
|
||||
'fees_int_var': 0.50,
|
||||
'fees_int_var': 0.005,
|
||||
})
|
||||
|
||||
transaction_fees = self.currency.round(
|
||||
@@ -108,12 +108,12 @@ class AlipayTest(AlipayCommon, PaymentHttpCommon):
|
||||
self.partner.country_id,
|
||||
)
|
||||
)
|
||||
self.assertEqual(transaction_fees, 7.09)
|
||||
self.assertEqual(transaction_fees, 18.78)
|
||||
total_fee = self.currency.round(self.amount + transaction_fees)
|
||||
self.assertEqual(total_fee, 1118.2)
|
||||
self.assertEqual(total_fee, 1129.89)
|
||||
|
||||
tx = self._create_transaction(flow='redirect')
|
||||
self.assertEqual(tx.fees, 7.09)
|
||||
self.assertEqual(tx.fees, 18.78)
|
||||
with mute_logger('odoo.addons.payment.models.payment_transaction'):
|
||||
processing_values = tx._get_processing_values()
|
||||
redirect_form_data = self._extract_values_from_html_form(processing_values['redirect_form_html'])
|
||||
|
||||
@@ -4,7 +4,7 @@ from unittest.mock import patch
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import tagged
|
||||
from odoo.tools import mute_logger
|
||||
from odoo.tools import float_repr, mute_logger
|
||||
|
||||
from odoo.addons.payment.tests.http_common import PaymentHttpCommon
|
||||
from odoo.addons.payment_paypal.controllers.main import PaypalController
|
||||
@@ -41,7 +41,7 @@ class PaypalTest(PaypalCommon, PaymentHttpCommon):
|
||||
fees = self.currency.round(self.paypal._compute_fees(self.amount, self.currency, self.partner.country_id))
|
||||
if fees:
|
||||
# handling input is only specified if truthy
|
||||
values['handling'] = str(fees)
|
||||
values['handling'] = float_repr(fees, self.currency.decimal_places)
|
||||
|
||||
return values
|
||||
|
||||
@@ -111,9 +111,9 @@ class PaypalTest(PaypalCommon, PaymentHttpCommon):
|
||||
self.paypal.write({
|
||||
'fees_active': True,
|
||||
'fees_int_fixed': 0.30,
|
||||
'fees_int_var': 2.90,
|
||||
'fees_int_var': 0.029,
|
||||
})
|
||||
total_fee = self.paypal._compute_fees(100, False, False)
|
||||
total_fee = self.paypal._compute_fees(100, self.paypal.main_currency_id, False)
|
||||
self.assertEqual(round(total_fee, 2), 3.3, 'Wrong computation of the Paypal fees')
|
||||
|
||||
def test_parsing_pdt_validation_response_returns_notification_data(self):
|
||||
|
||||
Reference in New Issue
Block a user