summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/mail/wizard/__init__.py1
-rw-r--r--addons/mail/wizard/base_module_uninstall.py13
-rw-r--r--odoo/addons/base/__manifest__.py1
-rw-r--r--odoo/addons/base/ir/ir_model.py11
-rw-r--r--odoo/addons/base/module/module.py12
-rw-r--r--odoo/addons/base/module/module_view.xml2
-rw-r--r--odoo/addons/base/module/wizard/__init__.py1
-rw-r--r--odoo/addons/base/module/wizard/base_module_uninstall.py55
-rw-r--r--odoo/addons/base/module/wizard/base_module_uninstall_view.xml52
9 files changed, 147 insertions, 1 deletions
diff --git a/addons/mail/wizard/__init__.py b/addons/mail/wizard/__init__.py
index 2181ffa8266..2523a3593b0 100644
--- a/addons/mail/wizard/__init__.py
+++ b/addons/mail/wizard/__init__.py
@@ -4,3 +4,4 @@
from . import invite
from . import mail_compose_message
from . import email_template_preview
+from . import base_module_uninstall
diff --git a/addons/mail/wizard/base_module_uninstall.py b/addons/mail/wizard/base_module_uninstall.py
new file mode 100644
index 00000000000..43e029ba851
--- /dev/null
+++ b/addons/mail/wizard/base_module_uninstall.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+
+
+class BaseModuleUninstall(models.TransientModel):
+ _inherit = "base.module.uninstall"
+
+ def _get_models(self):
+ # consider mail-thread models only
+ models = super(BaseModuleUninstall, self)._get_models()
+ return models.filtered('is_mail_thread')
diff --git a/odoo/addons/base/__manifest__.py b/odoo/addons/base/__manifest__.py
index 8f8f585473c..be3a4b6af25 100644
--- a/odoo/addons/base/__manifest__.py
+++ b/odoo/addons/base/__manifest__.py
@@ -46,6 +46,7 @@ The kernel of Odoo, needed for all installation.
'module/wizard/base_language_install_view.xml',
'module/wizard/base_import_language_view.xml',
'module/wizard/base_module_upgrade_view.xml',
+ 'module/wizard/base_module_uninstall_view.xml',
'module/wizard/base_export_language_view.xml',
'module/wizard/base_update_translations_view.xml',
'module/wizard/base_module_immediate_install.xml',
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index 4ce65a210c2..31828750dfe 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -97,6 +97,8 @@ class IrModel(models.Model):
transient = fields.Boolean(string="Transient Model")
modules = fields.Char(compute='_in_modules', string='In Apps', help='List of modules in which the object is defined or inherited')
view_ids = fields.One2many('ir.ui.view', compute='_view_ids', string='Views')
+ count = fields.Integer(compute='_compute_count', string="Count (incl. archived)",
+ help="Total number of records in this model")
@api.depends()
def _inherited_models(self):
@@ -119,6 +121,15 @@ class IrModel(models.Model):
for model in self:
model.view_ids = self.env['ir.ui.view'].search([('model', '=', model.model)])
+ @api.depends()
+ def _compute_count(self):
+ cr = self.env.cr
+ for model in self:
+ records = self.env[model.model]
+ if not records._abstract:
+ cr.execute('SELECT COUNT(*) FROM "%s"' % records._table)
+ model.count = cr.fetchone()[0]
+
@api.constrains('model')
def _check_model_name(self):
for model in self:
diff --git a/odoo/addons/base/module/module.py b/odoo/addons/base/module/module.py
index bfc018f247f..3ded39fb128 100644
--- a/odoo/addons/base/module/module.py
+++ b/odoo/addons/base/module/module.py
@@ -535,6 +535,18 @@ class Module(models.Model):
return dict(ACTION_DICT, name=_('Uninstall'))
@api.multi
+ def button_uninstall_wizard(self):
+ """ Launch the wizard to uninstall the given module. """
+ return {
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'name': _('Uninstall module'),
+ 'view_mode': 'form',
+ 'res_model': 'base.module.uninstall',
+ 'context': {'default_module_id': self.id},
+ }
+
+ @api.multi
def button_uninstall_cancel(self):
self.write({'state': 'installed'})
return True
diff --git a/odoo/addons/base/module/module_view.xml b/odoo/addons/base/module/module_view.xml
index 338cb723980..d0e842b5e3e 100644
--- a/odoo/addons/base/module/module_view.xml
+++ b/odoo/addons/base/module/module_view.xml
@@ -82,7 +82,7 @@
<div>
<button name="button_immediate_install" states="uninstalled" string="Install" type="object" class="btn btn-primary"/>
<button name="button_immediate_upgrade" states="installed" string="Upgrade" type="object" class="btn btn-primary"/>
- <button name="button_uninstall" states="installed" string="Uninstall" type="object" class="btn btn-default"/>
+ <button name="button_uninstall_wizard" states="installed" string="Uninstall" type="object" class="btn btn-default"/>
<button name="button_uninstall_cancel" states="to remove" string="Cancel Uninstall" type="object" class="btn btn-default"/>
<button name="button_upgrade_cancel" states="to upgrade" string="Cancel Upgrade" type="object" class="btn btn-default"/>
<button name="button_install_cancel" states="to install" string="Cancel Install" type="object" class="btn btn-default"/>
diff --git a/odoo/addons/base/module/wizard/__init__.py b/odoo/addons/base/module/wizard/__init__.py
index 72162359952..ece1521da87 100644
--- a/odoo/addons/base/module/wizard/__init__.py
+++ b/odoo/addons/base/module/wizard/__init__.py
@@ -5,5 +5,6 @@ from . import base_module_update
from . import base_language_install
from . import base_import_language
from . import base_module_upgrade
+from . import base_module_uninstall
from . import base_export_language
from . import base_update_translations
diff --git a/odoo/addons/base/module/wizard/base_module_uninstall.py b/odoo/addons/base/module/wizard/base_module_uninstall.py
new file mode 100644
index 00000000000..1168e57341c
--- /dev/null
+++ b/odoo/addons/base/module/wizard/base_module_uninstall.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class BaseModuleUninstall(models.TransientModel):
+ _name = "base.module.uninstall"
+ _description = "Module Uninstallation"
+
+ show_all = fields.Boolean()
+ module_id = fields.Many2one('ir.module.module', string="Module", required=True,
+ domain=[('state', 'in', ['installed', 'to upgrade', 'to install'])])
+ module_ids = fields.Many2many('ir.module.module', string="Impacted modules",
+ compute='_compute_module_ids')
+ model_ids = fields.Many2many('ir.model', string="Impacted data models",
+ compute='_compute_model_ids')
+
+ def _get_modules(self):
+ """ Return all the modules impacted by self. """
+ return self.module_id.downstream_dependencies(self.module_id)
+
+ @api.depends('module_id', 'show_all')
+ def _compute_module_ids(self):
+ for wizard in self:
+ modules = wizard._get_modules()
+ wizard.module_ids = modules if wizard.show_all else modules.filtered('application')
+
+ def _get_models(self):
+ """ Return the models (ir.model) to consider for the impact. """
+ return self.env['ir.model'].search([('transient', '=', False)])
+
+ @api.depends('module_ids')
+ def _compute_model_ids(self):
+ ir_models = self._get_models()
+ ir_models_xids = ir_models._get_external_ids()
+ for wizard in self:
+ if wizard.module_id:
+ module_names = set(wizard._get_modules().mapped('name'))
+ # find the models that have all their XIDs in the given modules
+ def lost(model):
+ return all(xid.split('.')[0] in module_names
+ for xid in ir_models_xids.get(model.id, ()))
+ self.model_ids = ir_models.filtered(lost).sorted('name')
+
+ @api.onchange('module_id')
+ def _onchange_module_id(self):
+ # if we select a technical module, show technical modules by default
+ if not self.module_id.application:
+ self.show_all = True
+
+ @api.multi
+ def action_uninstall(self):
+ modules = self.mapped('module_id')
+ return modules.button_immediate_uninstall()
diff --git a/odoo/addons/base/module/wizard/base_module_uninstall_view.xml b/odoo/addons/base/module/wizard/base_module_uninstall_view.xml
new file mode 100644
index 00000000000..43da6a2bcde
--- /dev/null
+++ b/odoo/addons/base/module/wizard/base_module_uninstall_view.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+
+ <record id="view_base_module_uninstall" model="ir.ui.view">
+ <field name="name">Uninstall module</field>
+ <field name="model">base.module.uninstall</field>
+ <field name="arch" type="xml">
+ <form string="Uninstall module">
+ <field name="module_id" groups="base.group_no_one"/>
+ <h3>The following apps will be uninstalled</h3>
+ <field name="show_all"/> Show technical modules
+ <field name="module_ids" mode="kanban">
+ <kanban create="false">
+ <field name="icon"/>
+ <field name="name"/>
+ <field name="shortdesc"/>
+ <field name="summary"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div class="oe_module_vignette">
+ <img t-attf-src="#{record.icon.value}"
+ class="oe_module_icon" style="width: 60px; height: 60px"/>
+ <div class="oe_module_desc" style="padding-left: 70px">
+ <h4><field name="shortdesc"/></h4>
+ <p class="oe_module_name">
+ <t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
+ <i><field name="name" groups="base.group_no_one"/></i>
+ </p>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ <h3>The following documents will be permanently lost</h3>
+ <field name="model_ids">
+ <tree string="Models">
+ <field name="name" string="Document"/>
+ <field name="count"/>
+ </tree>
+ </field>
+ <footer>
+ <button string="Confirm" class="btn-primary" type="object" name="action_uninstall"/>
+ <button string="Cancel" class="btn-default" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ </data>
+</odoo>