From 428a2cda6737af69b77d6fd17d65aa0a1b28fc90 Mon Sep 17 00:00:00 2001 From: "Anita (anko)" Date: Fri, 9 Jun 2023 14:59:15 +0200 Subject: [PATCH] [IMP] payment_adyen: replace API URLs with an account-specific URL prefix Before this commit, users were required to compute the API URLs, which is specific to each Adyen account, themselves. After this commit, users will be able to copy their account prefix from Adyen to automatically generate the API URLs. task-3338126 closes odoo/odoo#126831 Related: odoo/upgrade#4876 Signed-off-by: Antoine Vandevenne (anv) --- addons/payment_adyen/controllers/main.py | 15 ++---- .../payment_adyen/models/payment_provider.py | 54 +++++++++---------- .../models/payment_transaction.py | 8 +-- addons/payment_adyen/tests/common.py | 3 +- .../views/payment_provider_views.xml | 3 +- 5 files changed, 32 insertions(+), 51 deletions(-) diff --git a/addons/payment_adyen/controllers/main.py b/addons/payment_adyen/controllers/main.py index 535b0b1e42a..ddc4f008474 100644 --- a/addons/payment_adyen/controllers/main.py +++ b/addons/payment_adyen/controllers/main.py @@ -59,10 +59,7 @@ class AdyenController(http.Controller): 'channel': 'Web', } response_content = provider_sudo._adyen_make_request( - url_field_name='adyen_checkout_api_url', - endpoint='/paymentMethods', - payload=data, - method='POST' + endpoint='/paymentMethods', payload=data, method='POST' ) _logger.info("paymentMethods request response:\n%s", pprint.pformat(response_content)) return response_content @@ -139,10 +136,7 @@ class AdyenController(http.Controller): # Make the payment request to Adyen response_content = provider_sudo._adyen_make_request( - url_field_name='adyen_checkout_api_url', - endpoint='/payments', - payload=data, - method='POST' + endpoint='/payments', payload=data, method='POST' ) # Handle the payment request response @@ -171,10 +165,7 @@ class AdyenController(http.Controller): # Make the payment details request to Adyen provider_sudo = request.env['payment.provider'].browse(provider_id).sudo() response_content = provider_sudo._adyen_make_request( - url_field_name='adyen_checkout_api_url', - endpoint='/payments/details', - payload=payment_details, - method='POST' + endpoint='/payments/details', payload=payment_details, method='POST' ) # Handle the payment details request response diff --git a/addons/payment_adyen/models/payment_provider.py b/addons/payment_adyen/models/payment_provider.py index 15f94ccbd3b..b788b8509d5 100644 --- a/addons/payment_adyen/models/payment_provider.py +++ b/addons/payment_adyen/models/payment_provider.py @@ -31,35 +31,35 @@ class PaymentProvider(models.Model): adyen_hmac_key = fields.Char( string="HMAC Key", help="The HMAC key of the webhook", required_if_provider='adyen', groups='base.group_system') - adyen_checkout_api_url = fields.Char( - string="Checkout API URL", help="The base URL for the Checkout API endpoints", - required_if_provider='adyen') - adyen_recurring_api_url = fields.Char( - string="Recurring API URL", help="The base URL for the Recurring API endpoints", - required_if_provider='adyen') + adyen_api_url_prefix = fields.Char( + string="API URL Prefix", + help="The base URL for the API endpoints", + required_if_provider='adyen', + ) #=== CRUD METHODS ===# @api.model_create_multi def create(self, values_list): for values in values_list: - self._adyen_trim_api_urls(values) + self._adyen_extract_prefix_from_api_url(values) return super().create(values_list) def write(self, values): - self._adyen_trim_api_urls(values) + self._adyen_extract_prefix_from_api_url(values) return super().write(values) @api.model - def _adyen_trim_api_urls(self, values): - """ Remove the version and the endpoint from the url of Adyen API fields. + def _adyen_extract_prefix_from_api_url(self, values): + """ Update the create or write values with the prefix extracted from the API URL. - :param dict values: The create or write values + :param dict values: The create or write values. :return: None """ - for field_name in ('adyen_checkout_api_url', 'adyen_recurring_api_url'): - if values.get(field_name): # Test the value in case we're duplicating a provider - values[field_name] = re.sub(r'[vV]\d+(/.*)?', '', values[field_name]) + if values.get('adyen_api_url_prefix'): # Test if we're duplicating a provider. + values['adyen_api_url_prefix'] = re.sub( + r'(?:https://)?(\w+-\w+).*', r'\1', values['adyen_api_url_prefix'] + ) #=== COMPUTE METHODS ===# @@ -74,14 +74,11 @@ class PaymentProvider(models.Model): #=== BUSINESS METHODS - PAYMENT FLOW ===# - def _adyen_make_request( - self, url_field_name, endpoint, endpoint_param=None, payload=None, method='POST' - ): + def _adyen_make_request(self, endpoint, endpoint_param=None, payload=None, method='POST'): """ Make a request to Adyen API at the specified endpoint. Note: self.ensure_one() - :param str url_field_name: The name of the field holding the base URL for the request :param str endpoint: The endpoint to be reached by the request :param str endpoint_param: A variable required by some endpoints which are interpolated with it if provided. For example, the provider reference of the source @@ -93,27 +90,28 @@ class PaymentProvider(models.Model): :raise: ValidationError if an HTTP error occurs """ - def _build_url(_base_url, _version, _endpoint): + def _build_url(prefix_, version_, endpoint_): """ Build an API URL by appending the version and endpoint to a base URL. The final URL follows this pattern: `<_base>/V<_version>/<_endpoint>`. - :param str _base_url: The base of the url prefixed with `https://` - :param int _version: The version of the endpoint - :param str _endpoint: The endpoint of the URL. - :return: The final URL + :param str prefix_: The API URL prefix of the account. + :param int version_: The version of the endpoint. + :param str endpoint_: The endpoint of the URL. + :return: The final URL. :rtype: str """ - _base = _base_url.rstrip('/') # Remove potential trailing slash - _endpoint = _endpoint.lstrip('/') # Remove potential leading slash - return f'{_base}/V{_version}/{_endpoint}' + prefix_ = prefix_.rstrip('/') # Remove potential trailing slash + endpoint_ = endpoint_.lstrip('/') # Remove potential leading slash + test_mode_ = self.state == 'test' + prefix_ = f'{prefix_}.adyen' if test_mode_ else f'{prefix_}-checkout-live.adyenpayments' + return f'https://{prefix_}.com/checkout/V{version_}/{endpoint_}' self.ensure_one() - base_url = self[url_field_name] # Restrict request URL to the stored API URL fields version = const.API_ENDPOINT_VERSIONS[endpoint] endpoint = endpoint if not endpoint_param else endpoint.format(endpoint_param) - url = _build_url(base_url, version, endpoint) + url = _build_url(self.adyen_api_url_prefix, version, endpoint) headers = {'X-API-Key': self.adyen_api_key} try: response = requests.request(method, url, json=payload, headers=headers, timeout=60) diff --git a/addons/payment_adyen/models/payment_transaction.py b/addons/payment_adyen/models/payment_transaction.py index 9cedd253d8e..15360240671 100644 --- a/addons/payment_adyen/models/payment_transaction.py +++ b/addons/payment_adyen/models/payment_transaction.py @@ -96,10 +96,7 @@ class PaymentTransaction(models.Model): # Make the payment request to Adyen try: response_content = self.provider_id._adyen_make_request( - url_field_name='adyen_checkout_api_url', - endpoint='/payments', - payload=data, - method='POST', + endpoint='/payments', payload=data, method='POST' ) except ValidationError as e: if self.operation == 'offline': @@ -143,7 +140,6 @@ class PaymentTransaction(models.Model): 'reference': refund_tx.reference, } response_content = refund_tx.provider_id._adyen_make_request( - url_field_name='adyen_checkout_api_url', endpoint='/payments/{}/refunds', endpoint_param=self.provider_reference, payload=data, @@ -183,7 +179,6 @@ class PaymentTransaction(models.Model): 'reference': self.reference, } response_content = self.provider_id._adyen_make_request( - url_field_name='adyen_checkout_api_url', endpoint='/payments/{}/captures', endpoint_param=self.provider_reference, payload=data, @@ -219,7 +214,6 @@ class PaymentTransaction(models.Model): 'reference': self.reference, } response_content = self.provider_id._adyen_make_request( - url_field_name='adyen_checkout_api_url', endpoint='/payments/{}/cancels', endpoint_param=self.provider_reference, payload=data, diff --git a/addons/payment_adyen/tests/common.py b/addons/payment_adyen/tests/common.py index 6704ba7cd08..4e671f8d3b8 100644 --- a/addons/payment_adyen/tests/common.py +++ b/addons/payment_adyen/tests/common.py @@ -14,8 +14,7 @@ class AdyenCommon(PaymentCommon): 'adyen_api_key': 'dummy', 'adyen_client_key': 'dummy', 'adyen_hmac_key': '12345678', - 'adyen_checkout_api_url': 'https://this.is.an.url', - 'adyen_recurring_api_url': 'https://this.is.an.url', + 'adyen_api_url_prefix': 'prefix', }) # Override default values diff --git a/addons/payment_adyen/views/payment_provider_views.xml b/addons/payment_adyen/views/payment_provider_views.xml index fb63dc8c613..decb1257c8d 100644 --- a/addons/payment_adyen/views/payment_provider_views.xml +++ b/addons/payment_adyen/views/payment_provider_views.xml @@ -12,8 +12,7 @@ - - +