Includes: - Odoo 19 framework (odoo/) - 27 custom EnCoach addons (new_project/custom_addons/) - encoach_core, encoach_api, encoach_lms_api, encoach_adaptive_api - encoach_exam, encoach_taxonomy, encoach_adaptive, encoach_assignment - encoach_ai, encoach_ai_grading, encoach_ai_generation, encoach_ai_media - encoach_courseware, encoach_communication, encoach_subscription - encoach_notification, encoach_approval, encoach_branding - encoach_classroom, encoach_registration, encoach_stats - encoach_faq, encoach_ticket, encoach_training, encoach_resources - encoach_adaptive_ai, encoach_sis - 21 OpenEduCat Enterprise modules (new_project/enterprise-19/) - 14 OpenEduCat Community modules (new_project/openeducat_erp-19.0/) - Configuration: odoo.conf, requirements.txt, scripts - 200+ REST API endpoints with JWT authentication - SRS and test documentation Made-with: Cursor
195 lines
7.1 KiB
Python
195 lines
7.1 KiB
Python
import requests
|
|
|
|
from contextlib import contextmanager
|
|
from unittest.mock import Mock, patch
|
|
from urllib.parse import parse_qs, quote_plus
|
|
|
|
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
|
|
|
ID_CLIENT = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
|
|
|
|
|
|
class PeppolConnectorCommon(AccountTestInvoicingCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.env['ir.config_parameter'].sudo().set_param('account_peppol.edi.mode', 'test')
|
|
|
|
@staticmethod
|
|
def forge_id_client(company_id):
|
|
id_str = str(company_id).rjust(len(ID_CLIENT.split('x')) - 1, '0')
|
|
new_id_client_blocks = []
|
|
index = 0
|
|
for block in ID_CLIENT.split('-'):
|
|
new_id_client_blocks.append(id_str[index:index + len(block)])
|
|
index += len(block)
|
|
return '-'.join(new_id_client_blocks)
|
|
|
|
def _default_error_code(self):
|
|
return {'error': {'code': "spoutch", 'message': "failure"}}
|
|
|
|
def _empty_result_or_error(self, success=True):
|
|
if success:
|
|
return {'result': {}}
|
|
else:
|
|
return self._default_error_code()
|
|
|
|
def _mock_can_connect(self, with_auth=False):
|
|
def replacement_method(url, **kwargs):
|
|
auth_vals = {
|
|
'available_auths': {
|
|
'itsme': {'authorization_url': 'test_authorization_url'},
|
|
},
|
|
} if with_auth else {}
|
|
return {
|
|
'auth_required': with_auth,
|
|
**auth_vals,
|
|
}
|
|
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/2/can_connect',
|
|
replacement_method,
|
|
)
|
|
|
|
def _mock_connect(self, success=True, peppol_state='smp_registration', id_client='test_id_client'):
|
|
def replacement_method(url, **kwargs):
|
|
if peppol_state == 'rejected':
|
|
return {
|
|
'status_code': 403,
|
|
'code': 201,
|
|
'message': 'Unable to register, please contact our support team at peppol.support@odoo.com.'
|
|
}
|
|
if success:
|
|
return {'id_client': id_client, 'refresh_token': 'test_refresh_token', 'peppol_state': peppol_state}
|
|
else:
|
|
return {
|
|
'status_code': 401,
|
|
'code': 208,
|
|
'message': 'The Authentication failed',
|
|
}
|
|
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/2/connect',
|
|
replacement_method,
|
|
)
|
|
|
|
def _mock_register_sender(self, success=True):
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/1/register_sender',
|
|
lambda url, **kwargs: self._empty_result_or_error(success=success),
|
|
)
|
|
|
|
def _mock_register_sender_as_receiver(self, success=True):
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/1/register_sender_as_receiver',
|
|
lambda url, **kwargs: self._empty_result_or_error(success=success),
|
|
)
|
|
|
|
def _mock_lookup_participant(self, already_exists=False):
|
|
|
|
def replacement_method(url, **kwargs):
|
|
if not already_exists:
|
|
return {
|
|
'status_code': 404,
|
|
'error': {
|
|
'code': "NOT_FOUND",
|
|
'message': "no naptr record",
|
|
'retryable': False,
|
|
},
|
|
}
|
|
else:
|
|
peppol_identifier = parse_qs(url.rsplit('?')[1])['peppol_identifier'][0]
|
|
return {
|
|
'ok': True,
|
|
'result': {
|
|
"identifier": peppol_identifier,
|
|
"smp_base_url": "http://example.com/smp",
|
|
"ttl": 60,
|
|
"service_group_url": "http://example.com/smp/iso6523-actorid-upis%3A%3A" + quote_plus(peppol_identifier),
|
|
"services": [],
|
|
},
|
|
}
|
|
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/1/lookup',
|
|
replacement_method,
|
|
)
|
|
|
|
def _mock_participant_status(self, peppol_state, exists=True):
|
|
|
|
def replacement_method(url, **kwargs):
|
|
assert peppol_state
|
|
if exists:
|
|
return {
|
|
'result': {
|
|
'peppol_state': peppol_state,
|
|
},
|
|
}
|
|
else:
|
|
return {
|
|
'result': {
|
|
'error': {
|
|
'code': "client_gone",
|
|
'message': "Your registration for this service is no longer valid. "
|
|
"If you see this message, please update the related Odoo app. "
|
|
"You will then be able to re-register if needed.",
|
|
}
|
|
},
|
|
}
|
|
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/2/participant_status',
|
|
replacement_method,
|
|
)
|
|
|
|
def _mock_cancel_peppol_registration(self, success=True):
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/1/cancel_peppol_registration',
|
|
lambda url, **kwargs: self._empty_result_or_error(success=success),
|
|
)
|
|
|
|
def _mock_get_all_documents(self, success=True):
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/1/get_all_documents',
|
|
lambda url, **kwargs: self._empty_result_or_error(success=success),
|
|
)
|
|
|
|
def _mock_update_user(self, success=True):
|
|
return (
|
|
'https://peppol.test.odoo.com/api/peppol/1/update_user',
|
|
lambda url, **kwargs: self._empty_result_or_error(success=success),
|
|
)
|
|
|
|
@contextmanager
|
|
def _mock_requests(self, mocks_methods):
|
|
mocks = dict(mocks_methods)
|
|
called_urls = set()
|
|
mock_results = {'called': {}}
|
|
|
|
def mock_request(url, **kwargs):
|
|
for mocked_url, replacement_method in mocks.items():
|
|
if url.startswith(mocked_url):
|
|
called_urls.add(mocked_url)
|
|
mock_results['called'][mocked_url] = {
|
|
'url': url,
|
|
'kwargs': kwargs,
|
|
}
|
|
results = replacement_method(url, **kwargs)
|
|
mocked_request = Mock()
|
|
mocked_request.status_code = results.get('status_code', 200)
|
|
results.pop('status_code', None)
|
|
if not (200 <= mocked_request.status_code < 300):
|
|
mocked_request.raise_for_status.side_effect = requests.exceptions.HTTPError()
|
|
mocked_request.json.return_value = results
|
|
return mocked_request
|
|
self.assertFalse(url, "Missing mock!")
|
|
|
|
def mock_request_2(method, url, **kwargs):
|
|
return mock_request(url, **kwargs)
|
|
|
|
with patch('requests.get', mock_request), patch('requests.post', mock_request), patch('requests.request', mock_request_2):
|
|
yield mock_results
|
|
|
|
self.assertFalse([url for url in mocks if url not in called_urls], "URLs mocked but not called")
|