diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index 590727e2ab8..dc84d709e17 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -5,7 +5,7 @@ import logging from psycopg2 import sql from odoo import _, api, fields, models, SUPERUSER_ID -from odoo.exceptions import ValidationError +from odoo.exceptions import UserError, ValidationError from odoo.osv import expression _logger = logging.getLogger(__name__) @@ -31,6 +31,11 @@ class PaymentAcquirer(models.Model): "This mode is advised when setting up the acquirer.", selection=[('disabled', "Disabled"), ('enabled', "Enabled"), ('test', "Test Mode")], default='disabled', required=True, copy=False) + is_published = fields.Boolean( + string="Published", + help="Whether the acquirer is visible on the website or not. Tokens remain functional but " + "are only visible on manage forms.", + ) company_id = fields.Many2one( # Indexed to speed-up ORM searches (from ir_rule or others) string="Company", comodel_name='res.company', default=lambda self: self.env.company.id, required=True, index=True) @@ -236,7 +241,15 @@ class PaymentAcquirer(models.Model): #=== ONCHANGE METHODS ===# @api.onchange('state') - def _onchange_state(self): + def _onchange_state_switch_is_published(self): + """ Automatically publish or unpublish the acquirer depending on its state. + + :return: None + """ + self.is_published = self.state == 'enabled' + + @api.onchange('state') + def _onchange_state_warn_before_disabling_tokens(self): """ Display a warning about the consequences of disabling an acquirer. Let the user know that tokens related to an acquirer get archived if it is disabled or if @@ -348,6 +361,17 @@ class PaymentAcquirer(models.Model): 'tag': 'reload', } + def action_toggle_is_published(self): + """ Toggle the acquirer's is_published state. + + :return: none + :raise UserError: If the acquirer is disabled. + """ + if self.state != 'disabled': + self.is_published = not self.is_published + else: + raise UserError(_("You cannot publish a disabled acquirer.")) + #=== BUSINESS METHODS ===# @api.model @@ -372,6 +396,10 @@ class PaymentAcquirer(models.Model): # Compute the base domain for compatible acquirers domain = ['&', ('state', 'in', ['enabled', 'test']), ('company_id', '=', company_id)] + # Handle the is_published state. + if not self.env.user._is_internal(): + domain = expression.AND([domain, [('is_published', '=', True)]]) + # Handle partner country partner = self.env['res.partner'].browse(partner_id) if partner.country_id: # The partner country must either not be set or be supported diff --git a/addons/payment/tests/__init__.py b/addons/payment/tests/__init__.py index d17e2d6a0f4..fb7389458f4 100644 --- a/addons/payment/tests/__init__.py +++ b/addons/payment/tests/__init__.py @@ -5,4 +5,5 @@ from . import http_common from . import test_account_payment from . import test_flows from . import test_multicompany_flows +from . import test_payment_acquirer from . import test_payment_transaction diff --git a/addons/payment/tests/common.py b/addons/payment/tests/common.py index 940847c25bd..bc7bf6681f1 100644 --- a/addons/payment/tests/common.py +++ b/addons/payment/tests/common.py @@ -92,6 +92,7 @@ class PaymentCommon(AccountTestInvoicingCommon): 'name': "Dummy Acquirer", 'provider': 'none', 'state': 'test', + 'is_published': True, 'allow_tokenization': True, 'redirect_form_view_id': redirect_form.id, 'journal_id': cls.company_data['default_journal_bank'].id, diff --git a/addons/payment/tests/test_payment_acquirer.py b/addons/payment/tests/test_payment_acquirer.py new file mode 100644 index 00000000000..b3351bef425 --- /dev/null +++ b/addons/payment/tests/test_payment_acquirer.py @@ -0,0 +1,36 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.tests import tagged + +from odoo.addons.payment.tests.common import PaymentCommon + + +@tagged('-at_install', 'post_install') +class TestPaymentAcquirer(PaymentCommon): + + def test_published_acquirer_compatible_with_all_users(self): + for user in (self.public_user, self.portal_user): + self.env = self.env(user=user) + + compatible_acquirers = self.env['payment.acquirer'].sudo()._get_compatible_acquirers( + self.company.id, self.partner.id + ) + self.assertIn(self.acquirer, compatible_acquirers) + + def test_unpublished_acquirer_compatible_with_internal_user(self): + self.acquirer.is_published = False + + compatible_acquirers = self.env['payment.acquirer']._get_compatible_acquirers( + self.company.id, self.partner.id + ) + self.assertIn(self.acquirer, compatible_acquirers) + + def test_unpublished_acquirer_not_compatible_with_non_internal_user(self): + self.acquirer.is_published = False + for user in (self.public_user, self.portal_user): + self.env = self.env(user=user) + + compatible_acquirers = self.env['payment.acquirer'].sudo()._get_compatible_acquirers( + self.company.id, self.partner.id + ) + self.assertNotIn(self.acquirer, compatible_acquirers) diff --git a/addons/payment/views/payment_acquirer_views.xml b/addons/payment/views/payment_acquirer_views.xml index 3158495c4ee..975ccbeeea6 100644 --- a/addons/payment/views/payment_acquirer_views.xml +++ b/addons/payment/views/payment_acquirer_views.xml @@ -6,6 +6,7 @@ payment.acquirer
+ @@ -21,6 +22,27 @@ + +
+ + +
@@ -117,6 +139,7 @@ + @@ -126,6 +149,7 @@ +
@@ -138,6 +162,8 @@ + Published + Unpublished diff --git a/addons/payment/views/payment_templates.xml b/addons/payment/views/payment_templates.xml index 25c8d379da8..3bcaf5e05e4 100644 --- a/addons/payment/views/payment_templates.xml +++ b/addons/payment/views/payment_templates.xml @@ -66,6 +66,11 @@ class="rounded-pill text-bg-warning ms-1"> Test Mode + + + Unpublished + @@ -118,6 +123,10 @@ + + + Unpublished +
@@ -195,7 +204,7 @@ data-payment-option-type="acquirer"/> - + Test Mode + + + Unpublished + @@ -244,6 +257,11 @@ + + + Unpublished +