78 lines
3.1 KiB
Python
78 lines
3.1 KiB
Python
from odoo import api, conf, fields, models
|
|
|
|
|
|
class IrModuleModule(models.Model):
|
|
_inherit = "ir.module.module"
|
|
|
|
is_bundle = fields.Boolean(
|
|
help="A bundle purges dependencies on uninstallation of this module",
|
|
compute="_compute_is_bundle",
|
|
) # Can't be stored
|
|
module_type = fields.Selection(
|
|
selection_add=[("bundles", "Bundles")], ondelete={"bundles": "set default"}
|
|
)
|
|
|
|
def _compute_is_bundle(self):
|
|
for module in self:
|
|
module_info = self.get_module_info(module.name)
|
|
module.is_bundle = module_info.get("bundle", False)
|
|
|
|
def _get_modules_to_uninstall_for_bundle(self):
|
|
self.ensure_one()
|
|
downstream_dependencies = self.downstream_dependencies(self)
|
|
other_installed_bundle_modules = self.search(
|
|
[("state", "=", "installed"), ("id", "not in", downstream_dependencies.ids)]
|
|
).filtered(lambda m: m.is_bundle)
|
|
modules_to_keep = self.search([("name", "in", conf.server_wide_modules)])
|
|
modules_to_keep += other_installed_bundle_modules.upstream_dependencies(
|
|
exclude_states=("uninstalled",)
|
|
)
|
|
modules_to_keep = set(modules_to_keep)
|
|
modules_to_remove = self.upstream_dependencies(exclude_states=("uninstalled",))
|
|
modules_to_remove = modules_to_remove.filtered(
|
|
lambda d: d not in modules_to_keep
|
|
)
|
|
modules_to_remove += downstream_dependencies.upstream_dependencies(
|
|
exclude_states=("uninstalled",)
|
|
).filtered(lambda d: d not in modules_to_keep and not d.is_bundle)
|
|
modules_to_remove += modules_to_remove.downstream_dependencies(
|
|
modules_to_remove
|
|
).filtered(lambda m: m not in downstream_dependencies)
|
|
return modules_to_remove
|
|
|
|
def button_uninstall(self):
|
|
"""
|
|
Uninstall upstream modules but only if they're not in another bundle modules dependency.
|
|
This will not be invoked if a dependency of a bundle is uninstalled, only when a bundle is directly uninstalled
|
|
"""
|
|
modules = self.search(
|
|
[("state", "=", "installed"), ("auto_install", "=", False)]
|
|
)
|
|
bundle_modules = modules.filtered(lambda m: m.is_bundle)
|
|
for to_uninstall in self.filtered(lambda m: m in bundle_modules):
|
|
modules_to_remove = to_uninstall._get_modules_to_uninstall_for_bundle()
|
|
modules_to_remove.write({"state": "to remove"})
|
|
|
|
return super().button_uninstall()
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
modules = super().create(vals_list)
|
|
bundle_modules = self
|
|
for module in modules:
|
|
if module.get_module_info(module.name).get("bundle", False):
|
|
bundle_modules += module
|
|
bundle_modules.write({"module_type": "bundles"})
|
|
return modules
|
|
|
|
def _update_from_terp(self, terp):
|
|
res = super()._update_from_terp(terp)
|
|
self._update_module_type(terp)
|
|
return res
|
|
|
|
def _update_module_type(self, terp):
|
|
if terp.get("bundle", False):
|
|
self.module_type = "bundles"
|
|
elif self.module_type == "bundles":
|
|
self.module_type = "official"
|