diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index 09fa865a54ecb34cce53a569378827861958901d..3b172757d0967e70ea776dd0ed75d6feeded90b5 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -5,6 +5,7 @@ import requests import pprint from requests.exceptions import HTTPError from werkzeug import urls +from collections import namedtuple from odoo import api, fields, models, _ from odoo.tools.float_utils import float_round @@ -40,7 +41,6 @@ class PaymentAcquirerStripe(models.Model): base_url = self.get_base_url() stripe_session_data = { - 'payment_method_types[0]': 'card', 'line_items[][amount]': int(tx_values['amount'] if tx_values['currency'].name in INT_CURRENCIES else float_round(tx_values['amount'] * 100, 2)), 'line_items[][currency]': tx_values['currency'].name, 'line_items[][quantity]': 1, @@ -51,14 +51,43 @@ class PaymentAcquirerStripe(models.Model): 'payment_intent_data[description]': tx_values['reference'], 'customer_email': tx_values.get('partner_email') or tx_values.get('billing_partner_email'), } - if tx_values.get('billing_partner_country').code and tx_values.get('billing_partner_country').code.lower() == 'nl' and \ - tx_values.get('currency').name and tx_values.get('currency').name.lower() == 'eur': - # enable iDEAL for NL-based customers (€ payments only) - stripe_session_data['payment_method_types[1]'] = 'ideal' + + self._add_available_payment_method_types(stripe_session_data, tx_values) + tx_values['session_id'] = self._create_stripe_session(stripe_session_data) return tx_values + @api.model + def _add_available_payment_method_types(self, stripe_session_data, tx_values): + """ + Add payment methods available for the given transaction + + :param stripe_session_data: dictionary to add the payment method types to + :param tx_values: values of the transaction to consider the payment method types for + """ + PMT = namedtuple('PaymentMethodType', ['name', 'countries', 'currencies', 'recurrence']) + all_payment_method_types = [ + PMT('card', [], [], 'recurring'), + PMT('ideal', ['nl'], ['eur'], 'punctual'), + PMT('bancontact', ['be'], ['eur'], 'punctual'), + PMT('eps', ['at'], ['eur'], 'punctual'), + PMT('giropay', ['de'], ['eur'], 'punctual'), + PMT('p24', ['pl'], ['eur', 'pln'], 'punctual'), + ] + + country = (tx_values['billing_partner_country'].code or 'no_country').lower() + pmt_country_filtered = filter(lambda pmt: not pmt.countries or country in pmt.countries, all_payment_method_types) + currency = (tx_values.get('currency').name or 'no_currency').lower() + pmt_currency_filtered = filter(lambda pmt: not pmt.currencies or currency in pmt.currencies, pmt_country_filtered) + pmt_recurrence_filtered = filter(lambda pmt: tx_values.get('type') != 'form_save' or pmt.recurrence == 'recurring', + pmt_currency_filtered) + + available_payment_method_types = map(lambda pmt: pmt.name, pmt_recurrence_filtered) + + for idx, payment_method_type in enumerate(available_payment_method_types): + stripe_session_data[f'payment_method_types[{idx}]'] = payment_method_type + def _stripe_request(self, url, data=False, method='POST'): self.ensure_one() url = urls.url_join(self._get_stripe_api_url(), url) @@ -92,6 +121,8 @@ class PaymentAcquirerStripe(models.Model): if resp.get('payment_intent') and kwargs.get('client_reference_id'): tx = self.env['payment.transaction'].sudo().search([('reference', '=', kwargs['client_reference_id'])]) tx.stripe_payment_intent = resp['payment_intent'] + if 'id' not in resp and 'error' in resp: + _logger.error(resp['error']['message']) return resp['id'] def _create_setup_intent(self, kwargs): diff --git a/addons/payment_stripe/tests/test_stripe.py b/addons/payment_stripe/tests/test_stripe.py index 60b5fde6d9bdcf634fa19c945b64a3438d68c8ad..ed7fd19b462af39058343ae7b02830816ac76c22 100644 --- a/addons/payment_stripe/tests/test_stripe.py +++ b/addons/payment_stripe/tests/test_stripe.py @@ -28,6 +28,10 @@ class StripeCommon(PaymentAcquirerCommon): @odoo.tests.tagged('post_install', '-at_install', '-standard', 'external') class StripeTest(StripeCommon): + def run(self, result=None): + with mute_logger('odoo.addons.payment.models.payment_acquirer', 'odoo.addons.payment_stripe.models.payment'): + StripeCommon.run(self, result) + def test_10_stripe_s2s(self): self.assertEqual(self.stripe.state, 'test', 'test without test environment') # Create transaction @@ -76,3 +80,29 @@ class StripeTest(StripeCommon): tx.form_feedback(stripe_post_data, 'stripe') self.assertEqual(tx.state, 'done', 'Stripe: validation did not put tx into done state') self.assertEqual(tx.acquirer_reference, stripe_post_data.get('id'), 'Stripe: validation did not update tx id') + + def test_add_available_payment_method_types(self): + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card', 'bancontact'}, actual) + + def test_add_available_payment_method_types_recurrent(self): + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form_save' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card'}, actual)