From 64aea1a402e1e8f11cd04984d1b276cffc53d543 Mon Sep 17 00:00:00 2001 From: vava-odoo Date: Thu, 21 Dec 2023 16:17:02 +0100 Subject: [PATCH] [FIX] base_import_module: raise error if dependencies not in addons path If the addons path does not contain enterprise, the industry module cannot be installed since all of them rely on knowledge. The same applies if there is a theme in the industry and that the design-themes repository is not in the addons-path. This commit raises a UserError in case the installation would fail due to a missing repository in the addons-path. closes odoo/odoo#147138 Signed-off-by: Pierre Masereel (pim) --- .../i18n/base_import_module.pot | 21 +++++++++++- .../models/base_import_module.py | 2 +- addons/base_import_module/models/ir_module.py | 33 +++++++++++++++---- .../tests/test_import_module.py | 3 +- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/addons/base_import_module/i18n/base_import_module.pot b/addons/base_import_module/i18n/base_import_module.pot index 30880dfaf92..b0927451436 100644 --- a/addons/base_import_module/i18n/base_import_module.pot +++ b/addons/base_import_module/i18n/base_import_module.pot @@ -15,6 +15,16 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: base_import_module +#. odoo-python +#: code:addons/base_import_module/models/ir_module.py:0 +#, python-format +msgid "" +"\n" +"You may need the Enterprise version to install the data module. Please visit https://www.odoo.com/pricing-plan for more information.\n" +"If you need Website themes, it can be downloaded from https://github.com/odoo/design-themes.\n" +msgstr "" + #. module: base_import_module #: model_terms:ir.ui.view,arch_db:base_import_module.module_view_kanban_apps_inherit msgid "Activate" @@ -229,7 +239,16 @@ msgstr "" #. odoo-python #: code:addons/base_import_module/models/ir_module.py:0 #, python-format -msgid "The following modules will be also installed:\n" +msgid "The following modules will also be installed:\n" +msgstr "" + +#. module: base_import_module +#. odoo-python +#: code:addons/base_import_module/models/ir_module.py:0 +#, python-format +msgid "" +"The installation of the data module would fail as the following dependencies" +" can't be found in the addons-path:\n" msgstr "" #. module: base_import_module diff --git a/addons/base_import_module/models/base_import_module.py b/addons/base_import_module/models/base_import_module.py index 0035c9eb8fd..734ce94ccc4 100644 --- a/addons/base_import_module/models/base_import_module.py +++ b/addons/base_import_module/models/base_import_module.py @@ -30,7 +30,7 @@ class BaseImportModule(models.TransientModel): } def get_dependencies_to_install_names(self): - module_ids = self.env['ir.module.module']._get_missing_dependencies_modules(base64.decodebytes(self.module_file)) + module_ids, _not_found = self.env['ir.module.module']._get_missing_dependencies_modules(base64.decodebytes(self.module_file)) return module_ids.mapped('name') def action_module_open(self): diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 1c4610623e5..cef792ff631 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -381,10 +381,13 @@ class IrModule(models.Model): timeout=5.0, ) resp.raise_for_status() + missing_dependencies_description, unavailable_modules = self._get_missing_dependencies(resp.content) + if unavailable_modules: + raise UserError(missing_dependencies_description) import_module = self.env['base.import.module'].create({ 'module_file': base64.b64encode(resp.content), 'state': 'init', - 'modules_dependencies': self._get_missing_dependencies(resp.content) + 'modules_dependencies': missing_dependencies_description, }) return { 'name': 'Install an App', @@ -402,18 +405,31 @@ class IrModule(models.Model): @api.model def _get_missing_dependencies(self, zip_data): - modules = self._get_missing_dependencies_modules(zip_data) + modules, unavailable_modules = self._get_missing_dependencies_modules(zip_data) description = '' - if modules: - description = _('The following modules will be also installed:\n') + if unavailable_modules: + description = _( + "The installation of the data module would fail as the following dependencies can't" + " be found in the addons-path:\n" + ) + for module in unavailable_modules: + description += "- " + module + "\n" + description += _( + "\nYou may need the Enterprise version to install the data module. Please visit " + "https://www.odoo.com/pricing-plan for more information.\n" + "If you need Website themes, it can be downloaded from https://github.com/odoo/design-themes.\n" + ) + elif modules: + description = _("The following modules will also be installed:\n") for mod in modules: description += "- " + mod.shortdesc + "\n" - return description + return description, unavailable_modules def _get_missing_dependencies_modules(self, zip_data): dependencies_to_install = self.env['ir.module.module'] - known_mods = self.search([]) + known_mods = self.search([('to_buy', '=', False)]) installed_mods = [m.name for m in known_mods if m.state == 'installed'] + not_found_modules = set() with zipfile.ZipFile(BytesIO(zip_data), "r") as z: manifest_files = [ file @@ -431,7 +447,10 @@ class IrModule(models.Model): continue unmet_dependencies = set(terp.get('depends', [])).difference(installed_mods) dependencies_to_install |= known_mods.filtered(lambda m: m.name in unmet_dependencies) - return dependencies_to_install + not_found_modules |= set( + mod for mod in unmet_dependencies if mod not in dependencies_to_install.mapped('name') + ) + return dependencies_to_install, not_found_modules @api.model def search_panel_select_range(self, field_name, **kwargs): diff --git a/addons/base_import_module/tests/test_import_module.py b/addons/base_import_module/tests/test_import_module.py index 7f5d6c78b06..a52627d6991 100644 --- a/addons/base_import_module/tests/test_import_module.py +++ b/addons/base_import_module/tests/test_import_module.py @@ -351,10 +351,11 @@ class TestImportModuleHttp(TestImportModule, odoo.tests.HttpCase): with ZipFile(archive, 'w') as zipf: for path, data in files: zipf.writestr(path, data) + modules_dependencies, _not_found = self.env['ir.module.module']._get_missing_dependencies(archive.getvalue()) import_module = self.env['base.import.module'].create({ 'module_file': base64.b64encode(archive.getvalue()), 'state': 'init', - 'modules_dependencies': self.env['ir.module.module']._get_missing_dependencies(archive.getvalue()) + 'modules_dependencies': modules_dependencies, }) dependencies_names = import_module.get_dependencies_to_install_names() self.assertEqual(dependencies_names, [])