diff --git a/addons/payment/models/payment_method.py b/addons/payment/models/payment_method.py index 6d7368653c8..c737531ebab 100644 --- a/addons/payment/models/payment_method.py +++ b/addons/payment/models/payment_method.py @@ -1,6 +1,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import _, api, fields, models, Command +from odoo import Command, _, api, fields, models +from odoo.exceptions import UserError from odoo.osv import expression @@ -164,6 +165,20 @@ class PaymentMethod(models.Model): ('payment_method_id', 'in', (self + self.brand_ids).ids), ]) # Fix `active_test` in the context forwarded by the view. linked_tokens.active = False + + # Prevent enabling a payment method if it is not linked to an enabled provider. + if values.get('active'): + for pm in self: + primary_pm = pm if pm.is_primary else pm.primary_payment_method_id + if ( + not primary_pm.active # Don't bother for already enabled payment methods. + and all(p.state == 'disabled' for p in primary_pm.provider_ids) + ): + raise UserError(_( + "This payment method needs a partner in crime; you should enable a payment" + " provider supporting this method first." + )) + return super().write(values) # === BUSINESS METHODS === # diff --git a/addons/payment/models/payment_provider.py b/addons/payment/models/payment_provider.py index 09ea73c7931..e70ef44ccd4 100644 --- a/addons/payment/models/payment_provider.py +++ b/addons/payment/models/payment_provider.py @@ -331,16 +331,25 @@ class PaymentProvider(models.Model): return providers def write(self, values): - # Handle provider disabling. + # Handle provider state changes. + deactivated_providers = self.env['payment.provider'] + activated_providers = self.env['payment.provider'] if 'state' in values: state_changed_providers = self.filtered( lambda p: p.state not in ('disabled', values['state']) ) # Don't handle providers being enabled or whose state is not updated. - state_changed_providers._handle_state_change() + state_changed_providers._archive_linked_tokens() + if values['state'] == 'disabled': + deactivated_providers = state_changed_providers + else: # 'enabled' or 'test' + activated_providers = self.filtered(lambda p: p.state == 'disabled') result = super().write(values) self._check_required_if_provider() + deactivated_providers._deactivate_unsupported_payment_methods() + activated_providers._activate_default_pms() + return result def _check_required_if_provider(self): @@ -370,13 +379,33 @@ class PaymentProvider(models.Model): _("The following fields must be filled: %s", ", ".join(field_names)) ) - def _handle_state_change(self): + def _archive_linked_tokens(self): """ Archive all the payment tokens linked to the providers. :return: None """ self.env['payment.token'].search([('provider_id', 'in', self.ids)]).write({'active': False}) + def _deactivate_unsupported_payment_methods(self): + """ Deactivate payment methods linked to only disabled providers. + + :return: None + """ + unsupported_pms = self.payment_method_ids.filtered( + lambda pm: all(p.state == 'disabled' for p in pm.provider_ids) + ) + (unsupported_pms + unsupported_pms.brand_ids).active = False + + def _activate_default_pms(self): + """ Activate the default payment methods of the provider. + + :return: None + """ + for provider in self: + pm_codes = provider._get_default_payment_method_codes() + pms = provider.with_context(active_test=False).payment_method_ids + (pms + pms.brand_ids).filtered(lambda pm: pm.code in pm_codes).active = True + @api.ondelete(at_uninstall=False) def _unlink_except_master_data(self): """ Prevent the deletion of the payment provider if it has an xmlid. """ @@ -656,3 +685,14 @@ class PaymentProvider(models.Model): """ self.ensure_one() return self.code + + def _get_default_payment_method_codes(self): + """ Return the default payment methods for this provider. + + Note: self.ensure_one() + + :return: The default payment method codes. + :rtype: list + """ + self.ensure_one() + return [] diff --git a/addons/payment/tests/common.py b/addons/payment/tests/common.py index 84b4792ff60..222c4c9cb43 100644 --- a/addons/payment/tests/common.py +++ b/addons/payment/tests/common.py @@ -61,11 +61,6 @@ class PaymentCommon(BaseCommon): 'country_id': cls.country_belgium.id, }) - # Activate pm - cls.env.ref('payment.payment_method_unknown').write({ - 'active': True, - 'support_tokenization': True, - }) # Create a dummy provider to allow basic tests without any specific provider implementation arch = """