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 = """
@@ -91,6 +86,11 @@ class PaymentCommon(BaseCommon): (cls.currency_euro + cls.currency_usd + cls.env.company.currency_id).ids )], }) + # Activate pm + cls.env.ref('payment.payment_method_unknown').write({ + 'active': True, + 'support_tokenization': True, + }) cls.provider = cls.dummy_provider cls.payment_methods = cls.provider.payment_method_ids diff --git a/addons/payment/views/payment_method_views.xml b/addons/payment/views/payment_method_views.xml index fb76e125971..b71cee38836 100644 --- a/addons/payment/views/payment_method_views.xml +++ b/addons/payment/views/payment_method_views.xml @@ -89,7 +89,7 @@ payment.method.tree payment.method - + @@ -130,6 +130,10 @@ + @@ -138,12 +142,8 @@ Payment Methods payment.method tree,kanban,form - [ - ('is_primary', '=', True), - ('provider_ids.state', '!=', 'disabled') - ] - - {'active_test': False} + [('is_primary', '=', True)] + {'active_test': False, 'search_default_available_pms': 1}

No payment methods found for your payment providers. diff --git a/addons/payment_demo/const.py b/addons/payment_demo/const.py new file mode 100644 index 00000000000..28c46ba53cc --- /dev/null +++ b/addons/payment_demo/const.py @@ -0,0 +1,6 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +# The codes of the payment methods to activate when Demo is activated. +DEFAULT_PAYMENT_METHOD_CODES = [ + 'demo', +] diff --git a/addons/payment_demo/data/payment_method_data.xml b/addons/payment_demo/data/payment_method_data.xml index 5b713e30450..46b0d6f83a9 100644 --- a/addons/payment_demo/data/payment_method_data.xml +++ b/addons/payment_demo/data/payment_method_data.xml @@ -5,7 +5,6 @@ Demo demo 1 - True True False diff --git a/addons/payment_demo/models/payment_provider.py b/addons/payment_demo/models/payment_provider.py index 021a1164b07..1521f01c49e 100644 --- a/addons/payment_demo/models/payment_provider.py +++ b/addons/payment_demo/models/payment_provider.py @@ -3,6 +3,8 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError +from odoo.addons.payment_demo import const + class PaymentProvider(models.Model): _inherit = 'payment.provider' @@ -36,3 +38,10 @@ class PaymentProvider(models.Model): def _check_provider_state(self): if self.filtered(lambda p: p.code == 'demo' and p.state not in ('test', 'disabled')): raise UserError(_("Demo providers should never be enabled.")) + + def _get_default_payment_method_codes(self): + """ Override of `payment` to return the default payment method codes. """ + default_codes = super()._get_default_payment_method_codes() + if self.code != 'demo': + return default_codes + return const.DEFAULT_PAYMENT_METHOD_CODES diff --git a/addons/payment_stripe/__manifest__.py b/addons/payment_stripe/__manifest__.py index dd4d8f524d7..955ac84d34a 100644 --- a/addons/payment_stripe/__manifest__.py +++ b/addons/payment_stripe/__manifest__.py @@ -12,7 +12,6 @@ 'views/payment_stripe_templates.xml', 'views/payment_templates.xml', # Only load the SDK on pages with a payment form. - 'data/payment_method_data.xml', 'data/payment_provider_data.xml', # Depends on views/payment_stripe_templates.xml ], 'post_init_hook': 'post_init_hook', diff --git a/addons/payment_stripe/const.py b/addons/payment_stripe/const.py index efec33c1c85..f6391503d5f 100644 --- a/addons/payment_stripe/const.py +++ b/addons/payment_stripe/const.py @@ -5,6 +5,20 @@ API_VERSION = '2019-05-16' # The API version of Stripe implemented in this modu # Stripe proxy URL PROXY_URL = 'https://stripe.api.odoo.com/api/stripe/' +# The codes of the payment methods to activate when Stripe is activated. +DEFAULT_PAYMENT_METHODS_CODES = [ + # Primary payment methods. + 'card', + 'paypal', + 'bancontact', + 'ideal', + # Brand payment methods. + 'visa', + 'mastercard', + 'amex', + 'discover', +] + # Mapping of payment method codes to Stripe codes. PAYMENT_METHODS_MAPPING = { 'ach_direct_debit': 'us_bank_account', diff --git a/addons/payment_stripe/data/payment_method_data.xml b/addons/payment_stripe/data/payment_method_data.xml deleted file mode 100644 index b8298c5aa85..00000000000 --- a/addons/payment_stripe/data/payment_method_data.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - True - - - True - - - True - - - True - - - - - - True - - - True - - - True - - - True - - - diff --git a/addons/payment_stripe/models/payment_provider.py b/addons/payment_stripe/models/payment_provider.py index e3b448afc2c..8146b9b6628 100644 --- a/addons/payment_stripe/models/payment_provider.py +++ b/addons/payment_stripe/models/payment_provider.py @@ -503,3 +503,10 @@ class PaymentProvider(models.Model): 'payment_methods_mapping': const.PAYMENT_METHODS_MAPPING, } return json.dumps(inline_form_values) + + def _get_default_payment_method_codes(self): + """ Override of `payment` to return the default payment method codes. """ + default_codes = super()._get_default_payment_method_codes() + if self.code != 'stripe': + return default_codes + return const.DEFAULT_PAYMENT_METHODS_CODES diff --git a/addons/website_sale_picking/const.py b/addons/website_sale_picking/const.py new file mode 100644 index 00000000000..6c2e34cd2b2 --- /dev/null +++ b/addons/website_sale_picking/const.py @@ -0,0 +1,6 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +# The codes of the payment method to activate when Pay on site is activated. +DEFAULT_PAYMENT_METHOD_CODES = [ + 'pay_on_site', +] diff --git a/addons/website_sale_picking/models/payment_provider.py b/addons/website_sale_picking/models/payment_provider.py index 8458c12725e..cb6d799af98 100644 --- a/addons/website_sale_picking/models/payment_provider.py +++ b/addons/website_sale_picking/models/payment_provider.py @@ -1,7 +1,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models - +from odoo.addons.website_sale_picking import const class PaymentProvider(models.Model): _inherit = 'payment.provider' @@ -42,3 +42,10 @@ class PaymentProvider(models.Model): ) return compatible_providers + + def _get_default_payment_method_codes(self): + """ Override of `payment` to return the default payment method codes. """ + default_codes = super()._get_default_payment_method_codes() + if self.custom_mode != 'onsite': + return default_codes + return const.DEFAULT_PAYMENT_METHOD_CODES