diff --git a/addons/base_install_request/__init__.py b/addons/base_install_request/__init__.py new file mode 100644 index 00000000000..3ffa90ff3d4 --- /dev/null +++ b/addons/base_install_request/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models +from . import wizard + +from odoo import api, tools, SUPERUSER_ID + + +def _auto_install_apps(cr, registry): + if not tools.config.get('default_productivity_apps', True): + return + env = api.Environment(cr, SUPERUSER_ID, {}) + env['ir.module.module'].sudo().search([ + ('name', 'in', [ + # Community + 'board', 'hr', 'mass_mailing', 'project', 'survey', + # Enterprise + 'appointment', 'knowledge', 'planning', 'sign', + ]), + ('state', '=', 'uninstalled') + ]).button_install() diff --git a/addons/base_install_request/__manifest__.py b/addons/base_install_request/__manifest__.py new file mode 100644 index 00000000000..89fa1dba16e --- /dev/null +++ b/addons/base_install_request/__manifest__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Base - Module Install Request', + 'category': 'Hidden', + 'depends': ['mail'], + 'description': """ +Allow internal users requesting a module installation +===================================================== + """, + 'auto_install': True, + 'data':[ + 'security/ir.model.access.csv', + 'wizard/base_module_install_request_views.xml', + 'data/mail_template_data.xml', + 'data/mail_templates_module_install.xml', + 'views/ir_module_module_views.xml', + ], + 'license': 'LGPL-3', + 'post_init_hook': '_auto_install_apps' +} diff --git a/addons/base_install_request/data/mail_template_data.xml b/addons/base_install_request/data/mail_template_data.xml new file mode 100644 index 00000000000..fa0d255baa2 --- /dev/null +++ b/addons/base_install_request/data/mail_template_data.xml @@ -0,0 +1,36 @@ + + + + + Mail: Install Request + + Module Activation Request for "{{ object.module_id.shortdesc }}" + {{ object.user_id.email_formatted or user.email_formatted }} + {{ ctx['partner'].id}} + +
+

+ Hello, +

+ has requested to activate the module. An administrator role is required to activate it. +

+

+ +
+

+ Review Request +

+ Thanks, + +

+ --
Mitchell Admin
+
+

+

+
+
+ {{ ctx['partner'].lang or user.lang }} + +
+
+
diff --git a/addons/base_install_request/data/mail_templates_module_install.xml b/addons/base_install_request/data/mail_templates_module_install.xml new file mode 100644 index 00000000000..e5b5d7f1cfb --- /dev/null +++ b/addons/base_install_request/data/mail_templates_module_install.xml @@ -0,0 +1,18 @@ + + + + diff --git a/addons/base_install_request/models/__init__.py b/addons/base_install_request/models/__init__.py new file mode 100644 index 00000000000..de58fda6e31 --- /dev/null +++ b/addons/base_install_request/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import ir_module_module diff --git a/addons/base_install_request/models/ir_module_module.py b/addons/base_install_request/models/ir_module_module.py new file mode 100644 index 00000000000..494b4c8c43a --- /dev/null +++ b/addons/base_install_request/models/ir_module_module.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, _ + + +class IrModuleModule(models.Model): + _inherit = 'ir.module.module' + + def action_open_install_request(self): + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'target': 'new', + 'name': _('Activation Request of "%s"', self.shortdesc), + 'view_mode': 'form', + 'res_model': 'base.module.install.request', + 'context': {'default_module_id': self.id}, + } diff --git a/addons/base_install_request/security/ir.model.access.csv b/addons/base_install_request/security/ir.model.access.csv new file mode 100644 index 00000000000..40b57b1c8a2 --- /dev/null +++ b/addons/base_install_request/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_base_module_install_request,access_base_module_install_request,model_base_module_install_request,base.group_user,1,1,1,0 +access_base_module_install_review,access_base_module_install_review,model_base_module_install_review,base.group_system,1,1,1,0 +base.access_ir_module_category_group_user,ir_module_category group_user,base.model_ir_module_category,base.group_user,1,0,0,0 +base.access_ir_module_module_group_user,ir_module_module group_user,base.model_ir_module_module,base.group_user,1,0,0,0 +access_ir_module_module_group_system,ir_module_module group_system,base.model_ir_module_module,base.group_system,1,1,1,1 diff --git a/addons/base_install_request/views/ir_module_module_views.xml b/addons/base_install_request/views/ir_module_module_views.xml new file mode 100644 index 00000000000..7dd872e06a1 --- /dev/null +++ b/addons/base_install_request/views/ir_module_module_views.xml @@ -0,0 +1,17 @@ + + + + ir.module.module.view.kanban.inherit.mail + ir.module.module + + + + + + + + + + + diff --git a/addons/base_install_request/wizard/__init__.py b/addons/base_install_request/wizard/__init__.py new file mode 100644 index 00000000000..7896df3d9f0 --- /dev/null +++ b/addons/base_install_request/wizard/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import base_module_install_request diff --git a/addons/base_install_request/wizard/base_module_install_request.py b/addons/base_install_request/wizard/base_module_install_request.py new file mode 100644 index 00000000000..54e206ddb98 --- /dev/null +++ b/addons/base_install_request/wizard/base_module_install_request.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError + + +class BaseModuleInstallRequest(models.TransientModel): + _name = "base.module.install.request" + _description = "Module Activation Request" + _rec_name = "module_id" + + module_id = fields.Many2one( + 'ir.module.module', string="Module", required=True, + domain=[('state', '=', "uninstalled")], + ondelete='cascade', readonly=True, + ) + user_id = fields.Many2one('res.users', default=lambda self: self.env.user, required=True) + user_ids = fields.Many2many('res.users', string="Send to:", compute='_compute_user_ids') + body_html = fields.Html('Body') + + @api.depends('module_id') + def _compute_user_ids(self): + users = self.env.ref('base.group_system').users + self.user_ids = [(6, 0, users.ids)] + + def action_send_request(self): + mail_template = self.env.ref('base_install_request.mail_template_base_install_request') + menu_id = self.env.ref('base.menu_apps').id + for user in self.user_ids: + render_ctx = dict(self.env.context, partner=user.partner_id, menu_id=menu_id) + mail_template.with_context(render_ctx).send_mail( + self.id, + force_send=True, + email_layout_xmlid='mail.mail_notification_light') + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': _('Your request has been successfully sent'), + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + +class BaseModuleInstallReview(models.TransientModel): + _name = "base.module.install.review" + _description = "Module Activation Review" + _rec_name = "module_id" + + module_id = fields.Many2one( + 'ir.module.module', string="Module", required=True, + domain=[('state', '=', "uninstalled")], + ondelete='cascade', readonly=True, + ) + module_ids = fields.Many2many( + 'ir.module.module', string="Depending Apps", compute='_compute_modules_description') + modules_description = fields.Html(compute='_compute_modules_description') + + @api.depends('module_id') + def _compute_modules_description(self): + for wizard in self: + apps = wizard._get_depending_apps(wizard.module_id) + wizard.module_ids = [(6, 0, apps.ids)] + wizard.modules_description = self.env["ir.qweb"]._render( + "base_install_request.base_module_install_review_description", {'apps': apps}) + + @api.model + def _get_depending_apps(self, module): + if not module: + raise UserError(_('No module selected.')) + if module.state == "installed": + raise UserError(_('The module is already installed.')) + deps = module.upstream_dependencies() + apps = module | deps.filtered(lambda d: d.application) + for dep in deps: + apps |= dep.upstream_dependencies() + return apps + + def action_install_module(self): + self.ensure_one() + self.module_id.button_immediate_install() + return { + 'type': 'ir.actions.client', + 'tag': 'home', + 'params': {'wait': True}, + } diff --git a/addons/base_install_request/wizard/base_module_install_request_views.xml b/addons/base_install_request/wizard/base_module_install_request_views.xml new file mode 100644 index 00000000000..5dd19b38063 --- /dev/null +++ b/addons/base_install_request/wizard/base_module_install_request_views.xml @@ -0,0 +1,58 @@ + + + + base.module.install.request.view.form + base.module.install.request + form + + +
+ + + + + + + +
+
+ +
+
+ + + base.module.install.review.view.form + base.module.install.review + form + + +
+ + + +
+
+ +
+
+ + + You are about to install an extra application + base.module.install.review + form + { 'default_module_id': active_id } + new + +
diff --git a/odoo/addons/base/views/ir_module_views.xml b/odoo/addons/base/views/ir_module_views.xml index 5aeaeda9add..fdaaa71fc55 100644 --- a/odoo/addons/base/views/ir_module_views.xml +++ b/odoo/addons/base/views/ir_module_views.xml @@ -73,14 +73,14 @@ - +
Installed
Learn More Module Info - Upgrade - - + Upgrade + +