Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions mass_module_updater/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
===================
Mass Module Updater
===================

This module provides a wizard to update multiple Odoo modules at once by their technical names.

**Table of contents**

.. contents::
:local:

Usage
=====

To use this module, you need to:

1. Go to Apps > Mass Module Updater.
2. Enter the technical names of the modules you want to update, separated by commas.
3. Click on "Update Modules".

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.

Credits
=======

Authors
-------

* Pol Reig

Maintainers
-----------

This module is maintained by QubiQ.
4 changes: 4 additions & 0 deletions mass_module_updater/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 Pol Reig
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import wizards
18 changes: 18 additions & 0 deletions mass_module_updater/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2026 Pol Reig
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Mass Module Updater",
"summary": "Update multiple Odoo modules at once from a single wizard",
"version": "18.0.1.0.0",
"category": "Extra Tools",
"license": "AGPL-3",
"author": "Pol Reig, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/server-tools",
"depends": ["base"],
"data": [
"security/ir.model.access.csv",
"views/mass_module_updater_wizard_views.xml",
],
"installable": True,
}
3 changes: 3 additions & 0 deletions mass_module_updater/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
2 changes: 2 additions & 0 deletions mass_module_updater/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_mass_module_updater_wizard,mass.module.updater.wizard,model_mass_module_updater_wizard,base.group_system,1,1,1,1
44 changes: 44 additions & 0 deletions mass_module_updater/views/mass_module_updater_wizard_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="mass_module_updater_wizard_view_form" model="ir.ui.view">
<field name="name">mass.module.updater.wizard.view.form</field>
<field name="model">mass.module.updater.wizard</field>
<field name="arch" type="xml">
<form string="Mass Module Updater">
<group>
<field name="module_names" placeholder="e.g. sale, hr, account" />
</group>
<footer>
<button
name="action_install_modules"
string="Install Modules"
type="object"
class="btn-primary"
/>
<button
name="action_update_modules"
string="Update Modules"
type="object"
class="btn-primary"
/>
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>

<record id="mass_module_updater_wizard_action" model="ir.actions.act_window">
<field name="name">Mass Module Updater</field>
<field name="res_model">mass.module.updater.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>

<menuitem
id="mass_module_updater_wizard_menu"
name="Mass Module Updater"
parent="base.menu_management"
action="mass_module_updater_wizard_action"
sequence="100"
/>
</odoo>
4 changes: 4 additions & 0 deletions mass_module_updater/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 Pol Reig
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import mass_module_updater_wizard
60 changes: 60 additions & 0 deletions mass_module_updater/wizards/mass_module_updater_wizard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2026 Pol Reig
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import _, fields, models
from odoo.exceptions import UserError


class MassModuleUpdaterWizard(models.TransientModel):
_name = "mass.module.updater.wizard"
_description = "Mass Module Updater Wizard"

module_names = fields.Char(
required=True, help="Comma-separated list of module names."
)

def _get_modules(self):
raw_names = self.module_names.split(",")
module_names = [name.strip() for name in raw_names if name.strip()]

if not module_names:
raise UserError(_("Please provide at least one valid module name."))

modules = self.env["ir.module.module"].search([("name", "in", module_names)])

found_names = set(modules.mapped("name"))
missing_names = set(module_names) - found_names
if missing_names:
raise UserError(
_(
"The following modules were not found: %s",
", ".join(sorted(missing_names)),
)
)
return modules

def action_install_modules(self):
self.ensure_one()
modules = self._get_modules()
already_installed = modules.filtered(lambda m: m.state == "installed")
if already_installed:
raise UserError(
_(
"The following modules are already installed: %s",
", ".join(sorted(already_installed.mapped("name"))),
)
)
return modules.button_immediate_install()

def action_update_modules(self):
self.ensure_one()
modules = self._get_modules()
uninstalled = modules.filtered(lambda m: m.state != "installed")
if uninstalled:
raise UserError(
_(
"The following modules are not installed: %s",
", ".join(sorted(uninstalled.mapped("name"))),
)
)
return modules.button_immediate_upgrade()
Loading