# Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.exceptions import UserError from odoo.models import Command from odoo.tests import tagged from odoo.addons.payment import utils as payment_utils from odoo.addons.payment.const import REPORT_REASONS_MAPPING from odoo.addons.payment.tests.common import PaymentCommon @tagged('-at_install', 'post_install') class TestPaymentMethod(PaymentCommon): def test_unlinking_payment_method_from_provider_state_archives_tokens(self): """ Test that the active tokens of a payment method created through a provider are archived when the method is unlinked from the provider. """ token = self._create_token() self.payment_method.provider_ids = [Command.unlink(self.payment_method.provider_ids[:1].id)] self.assertFalse(token.active) def test_payment_method_requires_provider_to_be_activated(self): """ Test that activating a payment method that is not linked to an enabled provider is forbidden. """ self.provider.state = 'disabled' with self.assertRaises(UserError): self.payment_methods.active = True def test_payment_method_compatible_when_provider_is_enabled(self): """ Test that a payment method is available when it is supported by an enabled provider. """ compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_not_compatible_when_provider_is_disabled(self): """ Test that a payment method is not available when there is no enabled provider that supports it. """ self.provider.state = 'disabled' compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id ) self.assertNotIn(self.payment_method, compatible_payment_methods) def test_non_primary_payment_method_not_compatible(self): """ Test that a "brand" (i.e., non-primary) payment method is never available. """ brand_payment_method = self.payment_method.copy() brand_payment_method.primary_payment_method_id = self.payment_method_id # Make it a brand. compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id ) self.assertNotIn(brand_payment_method, compatible_payment_methods) def test_payment_method_compatible_with_supported_countries(self): """ Test that the payment method is compatible with its supported countries. """ belgium = self.env.ref('base.be') self.payment_method.supported_country_ids = [Command.set([belgium.id])] self.partner.country_id = belgium compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_not_compatible_with_unsupported_countries(self): """ Test that the payment method is not compatible with a country that is not supported. """ belgium = self.env.ref('base.be') self.payment_method.supported_country_ids = [Command.set([belgium.id])] france = self.env.ref('base.fr') self.partner.country_id = france compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id ) self.assertNotIn(self.payment_method, compatible_payment_methods) def test_payment_method_compatible_when_no_supported_countries_set(self): """ Test that the payment method is always compatible when no supported countries are set. """ self.payment_method.supported_country_ids = [Command.clear()] belgium = self.env.ref('base.be') self.partner.country_id = belgium compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_compatible_with_supported_currencies(self): """ Test that the payment method is compatible with its supported currencies. """ self.payment_method.supported_currency_ids = [Command.set([self.currency_euro.id])] compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, currency_id=self.currency_euro.id ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_not_compatible_with_unsupported_currencies(self): """ Test that the payment method is not compatible with a currency that is not supported. """ self.payment_method.supported_currency_ids = [Command.set([self.currency_euro.id])] compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, currency_id=self.currency_usd.id ) self.assertNotIn(self.payment_method, compatible_payment_methods) def test_payment_method_compatible_when_no_supported_currencies_set(self): """ Test that the payment method is always compatible when no supported currencies are set. """ self.payment_method.supported_currency_ids = [Command.clear()] compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, currency_id=self.currency_euro.id ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_compatible_when_tokenization_forced(self): """ Test that the payment method is compatible when it supports tokenization while it is forced by the calling module. """ self.payment_method.support_tokenization = True compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, force_tokenization=True ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_not_compatible_when_tokenization_forced(self): """ Test that the payment method is not compatible when it does not support tokenization while it is forced by the calling module. """ self.payment_method.support_tokenization = False compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, force_tokenization=True ) self.assertNotIn(self.payment_method, compatible_payment_methods) def test_payment_method_compatible_with_express_checkout(self): """ Test that the payment method is compatible when it supports express checkout while it is an express checkout flow. """ self.payment_method.support_express_checkout = True compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, is_express_checkout=True ) self.assertIn(self.payment_method, compatible_payment_methods) def test_payment_method_not_compatible_with_express_checkout(self): """ Test that the payment method is not compatible when it does not support express checkout while it is an express checkout flow. """ self.payment_method.support_express_checkout = False compatible_payment_methods = self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, is_express_checkout=True ) self.assertNotIn(self.payment_method, compatible_payment_methods) def test_availability_report_covers_all_reasons(self): """ Test that every possible unavailability reason is correctly reported. """ # Disable all payment methods. pms = self.env['payment.method'].search([('is_primary', '=', True)]) pms.active = False # Prepare a base payment method. self.payment_method.write({ 'active': True, 'support_express_checkout': True, 'support_tokenization': True, }) # Prepare the report with a provider to allow checking provider availability. report = {} payment_utils.add_to_report(report, self.provider) # Prepare a payment method with an unavailable provider. unavailable_provider = self.provider.copy() payment_utils.add_to_report(report, unavailable_provider, available=False, reason="test") no_provider_pm = self.payment_method.copy() no_provider_pm.provider_ids = [Command.set([unavailable_provider.id])] unavailable_provider.payment_method_ids = [Command.set([no_provider_pm.id])] # Prepare a payment method with an incompatible country. invalid_country_pm = self.payment_method.copy() belgium = self.env.ref('base.be') invalid_country_pm.supported_country_ids = [Command.set([belgium.id])] france = self.env.ref('base.fr') self.partner.country_id = france # Prepare a payment method with an incompatible currency. invalid_currency_pm = self.payment_method.copy() invalid_currency_pm.supported_currency_ids = [Command.set([self.currency_euro.id])] # Prepare a payment method without support for tokenization. no_tokenization_pm = self.payment_method.copy() no_tokenization_pm.support_tokenization = False # Prepare a payment method without support for express checkout. no_express_checkout_pm = self.payment_method.copy() no_express_checkout_pm.support_express_checkout = False # Get compatible payment methods to generate their availability report. self.env['payment.method']._get_compatible_payment_methods( self.provider.ids, self.partner.id, currency_id=self.currency_usd.id, force_tokenization=True, is_express_checkout=True, report=report, ) # Compare the generated payment methods report with the expected one. expected_pms_report = { self.payment_method: { 'available': True, 'reason': '', 'supported_providers': [(self.provider, True)], }, no_provider_pm: { 'available': False, 'reason': REPORT_REASONS_MAPPING['provider_not_available'], 'supported_providers': [(unavailable_provider, False)], }, invalid_country_pm: { 'available': False, 'reason': REPORT_REASONS_MAPPING['incompatible_country'], 'supported_providers': [(self.provider, True)], }, invalid_currency_pm: { 'available': False, 'reason': REPORT_REASONS_MAPPING['incompatible_currency'], 'supported_providers': [(self.provider, True)], }, no_tokenization_pm: { 'available': False, 'reason': REPORT_REASONS_MAPPING['tokenization_not_supported'], 'supported_providers': [(self.provider, True)], }, no_express_checkout_pm: { 'available': False, 'reason': REPORT_REASONS_MAPPING['express_checkout_not_supported'], 'supported_providers': [(self.provider, True)], }, } self.maxDiff = None self.assertDictEqual(report['payment_methods'], expected_pms_report)