19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:27 +01:00
parent d1963a3c3a
commit 2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions

View file

@ -1,12 +1,11 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from uuid import uuid4
from contextlib import contextmanager
from lxml import etree, objectify
from werkzeug import urls
from odoo.tests import HttpCase
from odoo.tests import HttpCase, JsonRpcException
from odoo.tools import urls
from odoo.addons.payment.tests.common import PaymentCommon
@ -22,7 +21,7 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
###########
def _build_url(self, route):
return urls.url_join(self.base_url(), route)
return urls.urljoin(self.base_url(), route)
def _make_http_get_request(self, url, params=None):
""" Make an HTTP GET request to the provided URL.
@ -33,7 +32,7 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
:rtype: :class:`requests.models.Response`
"""
formatted_params = self._format_http_request_payload(payload=params)
return self.opener.get(url, params=formatted_params)
return self.url_open(url, params=formatted_params)
def _make_http_post_request(self, url, data=None):
""" Make an HTTP POST request to the provided URL.
@ -44,7 +43,7 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
:rtype: :class:`requests.models.Response`
"""
formatted_data = self._format_http_request_payload(payload=data)
return self.opener.post(url, data=formatted_data)
return self.url_open(url, data=formatted_data, method='POST')
def _format_http_request_payload(self, payload=None):
""" Format a request payload to replace float values by their string representation.
@ -67,29 +66,19 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
:return: The response of the request
:rtype: :class:`requests.models.Response`
"""
return self.opener.post(url, json=data)
return self.url_open(url, json=data)
def _make_json_rpc_request(self, url, data=None):
""" Make a JSON-RPC request to the provided URL.
@contextmanager
def _assertNotFound(self):
with self.assertRaises(JsonRpcException) as cm:
yield
self.assertEqual(cm.exception.code, 404)
:param str url: The URL to make the request to
:param dict data: The data to be send in the request body in JSON-RPC 2.0 format
:return: The response of the request
:rtype: :class:`requests.models.Response`
"""
return self.opener.post(url, json={
'jsonrpc': '2.0',
'method': 'call',
'id': str(uuid4()),
'params': data,
})
def _get_tx_context(self, response, form_name):
"""Extracts txContext & other form info (provider & token ids)
from a payment response (with manage/checkout html form)
def _get_payment_context(self, response):
"""Extracts the payment context & other form info (provider & token ids)
from a payment response
:param response: http Response, with a payment form as text
:param str form_name: o_payment_manage / o_payment_checkout
:return: Transaction context (+ provider_ids & token_ids)
:rtype: dict
"""
@ -100,9 +89,9 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
response.text,
parser=etree.HTMLParser(),
)
checkout_form = html_tree.xpath(f"//form[@name='{form_name}']")[0]
payment_form = html_tree.xpath('//form[@id="o_payment_form"]')[0]
values = {}
for key, val in checkout_form.items():
for key, val in payment_form.items():
if key.startswith("data-"):
formatted_key = key[5:].replace('-', '_')
if formatted_key.endswith('_id'):
@ -114,21 +103,21 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
values[formatted_key] = formatted_val
payment_options_inputs = html_tree.xpath("//input[@name='o_payment_radio']")
provider_ids = []
token_ids = []
payment_method_ids = []
for p_o_input in payment_options_inputs:
data = dict()
for key, val in p_o_input.items():
if key.startswith('data-'):
data[key[5:]] = val
if data['payment-option-type'] == 'provider':
provider_ids.append(int(data['payment-option-id']))
else:
if data['payment-option-type'] == 'token':
token_ids.append(int(data['payment-option-id']))
else: # 'payment_method'
payment_method_ids.append(int(data['payment-option-id']))
values.update({
'provider_ids': provider_ids,
'token_ids': token_ids,
'payment_method_ids': payment_method_ids,
})
return values
@ -156,7 +145,7 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
}
def _portal_pay(self, **route_kwargs):
"""/payment/pay txContext feedback
"""/payment/pay payment context feedback
NOTE: must be authenticated before calling method.
Or an access_token should be specified in route_kwargs
@ -165,18 +154,18 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
url = self._build_url(uri)
return self._make_http_get_request(url, route_kwargs)
def _get_tx_checkout_context(self, **route_kwargs):
def _get_portal_pay_context(self, **route_kwargs):
response = self._portal_pay(**route_kwargs)
self.assertEqual(response.status_code, 200)
return self._get_tx_context(response, 'o_payment_checkout')
return self._get_payment_context(response)
# /my/payment_method #
######################
def _portal_payment_method(self):
"""/my/payment_method txContext feedback
"""/my/payment_method payment context feedback
NOTE: must be authenticated before calling method
validation flow is restricted to logged users
@ -185,56 +174,49 @@ class PaymentHttpCommon(PaymentCommon, HttpCase):
url = self._build_url(uri)
return self._make_http_get_request(url, {})
def _get_tx_manage_context(self):
def _get_portal_payment_method_context(self):
response = self._portal_payment_method()
self.assertEqual(response.status_code, 200)
return self._get_tx_context(response, 'o_payment_manage')
return self._get_payment_context(response)
# payment/transaction #
#######################
def _prepare_transaction_values(self, payment_option_id, flow):
def _prepare_transaction_values(self, payment_method_id, token_id, flow):
""" Prepare the basic payment/transaction route values.
:param int payment_option_id: The payment option handling the transaction, as a
`payment.provider` id or a `payment.token` id
`payment.method` id or a `payment.token` id
:param str flow: The payment flow
:return: The route values
:rtype: dict
"""
return {
'provider_id': self.provider.id,
'payment_method_id': payment_method_id,
'token_id': token_id,
'amount': self.amount,
'currency_id': self.currency.id,
'partner_id': self.partner.id,
'access_token': self._generate_test_access_token(
self.partner.id, self.amount, self.currency.id
),
'payment_option_id': payment_option_id,
'reference_prefix': 'test',
'tokenization_requested': True,
'landing_route': 'Test',
'reference_prefix': 'test',
'is_validation': False,
'flow': flow,
}
def _portal_transaction(self, **route_kwargs):
def _portal_transaction(self, tx_route='/payment/transaction', **route_kwargs):
"""/payment/transaction feedback
:return: The response to the json request
"""
uri = '/payment/transaction'
url = self._build_url(uri)
response = self._make_json_rpc_request(url, route_kwargs)
self.assertEqual(response.status_code, 200) # Check the request went through.
return response
url = self._build_url(tx_route)
return self.make_jsonrpc_request(url, route_kwargs)
def _get_processing_values(self, **route_kwargs):
response = self._portal_transaction(**route_kwargs)
self.assertEqual(response.status_code, 200)
resp_content = json.loads(response.content)
return resp_content['result']
return self._portal_transaction(**route_kwargs)