diff --git a/addons/hr_org_chart/controllers/hr_org_chart.py b/addons/hr_org_chart/controllers/hr_org_chart.py index 4a8fb029dda..d9aeb0ce5fa 100644 --- a/addons/hr_org_chart/controllers/hr_org_chart.py +++ b/addons/hr_org_chart/controllers/hr_org_chart.py @@ -19,7 +19,7 @@ class HrOrgChartController(http.Controller): else: cids = [request.env.company.id] - Employee = request.env['hr.employee'].with_context(allowed_company_ids=cids) + Employee = request.env['hr.employee.public'].with_context(allowed_company_ids=cids) # check and raise if not Employee.check_access_rights('read', raise_exception=False): return None @@ -35,13 +35,19 @@ class HrOrgChartController(http.Controller): return dict( id=employee.id, name=employee.name, - link='/mail/view?model=hr.employee&res_id=%s' % employee.id, + link='/mail/view?model=%s&res_id=%s' % ('hr.employee.public', employee.id,), job_id=job.id, job_name=job.name or '', direct_sub_count=len(employee.child_ids), indirect_sub_count=employee.child_all_count, ) + @http.route('/hr/get_redirect_model', type='json', auth='user') + def get_redirect_model(self): + if request.env['hr.employee'].check_access_rights('read', raise_exception=False): + return 'hr.employee' + return 'hr.employee.public' + @http.route('/hr/get_org_chart', type='json', auth='user') def get_org_chart(self, employee_id, **kw): @@ -50,7 +56,7 @@ class HrOrgChartController(http.Controller): return {} # compute employee data for org chart - ancestors, current = request.env['hr.employee'], employee + ancestors, current = request.env['hr.employee.public'], employee while current.parent_id and len(ancestors) < self._managers_level+1: ancestors += current.parent_id current = current.parent_id @@ -81,8 +87,10 @@ class HrOrgChartController(http.Controller): return {} if subordinates_type == 'direct': - return employee.child_ids.ids + res = employee.child_ids.ids elif subordinates_type == 'indirect': - return (employee.subordinate_ids - employee.child_ids).ids + res = (employee.subordinate_ids - employee.child_ids).ids else: - return employee.subordinate_ids.ids + res = employee.subordinate_ids.ids + + return res diff --git a/addons/hr_org_chart/models/__init__.py b/addons/hr_org_chart/models/__init__.py index 71d1e5c7c23..27f11d1b306 100644 --- a/addons/hr_org_chart/models/__init__.py +++ b/addons/hr_org_chart/models/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import hr_org_chart_mixin from . import hr_employee diff --git a/addons/hr_org_chart/models/hr_employee.py b/addons/hr_org_chart/models/hr_employee.py index 15fc50645d2..8d04dd989ec 100644 --- a/addons/hr_org_chart/models/hr_employee.py +++ b/addons/hr_org_chart/models/hr_employee.py @@ -1,43 +1,16 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import fields, models + class Employee(models.Model): - _name = "hr.employee" - _inherit = "hr.employee" + _inherit = ["hr.employee"] - child_all_count = fields.Integer( - 'Indirect Surbordinates Count', - compute='_compute_subordinates', store=False) - - subordinate_ids = fields.One2many('hr.employee', string='Subordinates', compute='_compute_subordinates', help="Direct and indirect subordinates", groups='base.group_user') + subordinate_ids = fields.One2many('hr.employee', string='Subordinates', compute='_compute_subordinates', help="Direct and indirect subordinates") - def _get_subordinates(self, parents=None): - """ - Helper function to compute subordinates_ids. - Get all subordinates (direct and indirect) of an employee. - An employee can be a manager of his own manager (recursive hierarchy; e.g. the CEO is manager of everyone but is also - member of the RD department, managed by the CTO itself managed by the CEO). - In that case, the manager in not counted as a subordinate if it's in the 'parents' set. - """ +class HrEmployeePublic(models.Model): + _inherit = ["hr.employee.public"] - if not parents: - parents = self.env['hr.employee'] - - indirect_subordinates = self.env['hr.employee'] - parents |= self - direct_subordinates = self.child_ids - parents - for child in direct_subordinates: - child_subordinate = child._get_subordinates(parents=parents) - child.subordinate_ids = child_subordinate - indirect_subordinates |= child_subordinate - return indirect_subordinates | direct_subordinates - - - @api.depends('child_ids', 'child_ids.child_all_count') - def _compute_subordinates(self): - for employee in self: - employee.subordinate_ids = employee._get_subordinates() - employee.child_all_count = len(employee.subordinate_ids) + subordinate_ids = fields.One2many('hr.employee.public', string='Subordinates', compute='_compute_subordinates', help="Direct and indirect subordinates") diff --git a/addons/hr_org_chart/models/hr_org_chart_mixin.py b/addons/hr_org_chart/models/hr_org_chart_mixin.py new file mode 100644 index 00000000000..7633f2325ab --- /dev/null +++ b/addons/hr_org_chart/models/hr_org_chart_mixin.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class HrEmployeeBase(models.AbstractModel): + _inherit = "hr.employee.base" + + child_all_count = fields.Integer( + 'Indirect Surbordinates Count', + compute='_compute_subordinates', store=False) + + def _get_subordinates(self, parents=None): + """ + Helper function to compute subordinates_ids. + Get all subordinates (direct and indirect) of an employee. + An employee can be a manager of his own manager (recursive hierarchy; e.g. the CEO is manager of everyone but is also + member of the RD department, managed by the CTO itself managed by the CEO). + In that case, the manager in not counted as a subordinate if it's in the 'parents' set. + """ + if not parents: + parents = self.env[self._name] + + indirect_subordinates = self.env[self._name] + parents |= self + direct_subordinates = self.child_ids - parents + for child in direct_subordinates: + child_subordinate = child._get_subordinates(parents=parents) + child.subordinate_ids = child_subordinate + indirect_subordinates |= child_subordinate + return indirect_subordinates | direct_subordinates + + + @api.depends('child_ids', 'child_ids.child_all_count') + def _compute_subordinates(self): + for employee in self: + employee.subordinate_ids = employee._get_subordinates() + employee.child_all_count = len(employee.subordinate_ids) diff --git a/addons/hr_org_chart/static/src/js/hr_org_chart.js b/addons/hr_org_chart/static/src/js/hr_org_chart.js index 5e2ba861058..d1831b53c8b 100644 --- a/addons/hr_org_chart/static/src/js/hr_org_chart.js +++ b/addons/hr_org_chart/static/src/js/hr_org_chart.js @@ -24,7 +24,7 @@ var FieldOrgChart = AbstractField.extend({ init: function (parent, options) { this._super.apply(this, arguments); this.dm = new concurrency.DropMisordered(); - this.employee; + this.employee = null; }, //-------------------------------------------------------------------------- @@ -37,16 +37,16 @@ var FieldOrgChart = AbstractField.extend({ * @param {integer} employee_id * @returns {Promise} */ - _getOrgData: function (employee_id) { + _getOrgData: function () { var self = this; return this.dm.add(this._rpc({ route: '/hr/get_org_chart', params: { - employee_id: employee_id, + employee_id: this.employee, context: session.user_context, }, })).then(function (data) { - self.orgData = data; + return data; }); }, /** @@ -83,10 +83,9 @@ var FieldOrgChart = AbstractField.extend({ } var self = this; - return this._getOrgData(this.employee).then(function () { - - self.orgData['view_employee_id'] = self.recordData.id; - self.$el.html(QWeb.render("hr_org_chart", self.orgData)); + return this._getOrgData().then(function (orgData) { + orgData.view_employee_id = self.recordData.id; + self.$el.html(QWeb.render("hr_org_chart", orgData)); self.$('[data-toggle="popover"]').each(function () { $(this).popover({ html: true, @@ -130,7 +129,7 @@ var FieldOrgChart = AbstractField.extend({ _onEmployeeMoreManager: function(event) { event.preventDefault(); this.employee = parseInt($(event.currentTarget).data('employee-id')); - this._render() + this._render(); }, /** * Redirect to the employee form view. @@ -140,16 +139,15 @@ var FieldOrgChart = AbstractField.extend({ * @returns {Promise} action loaded */ _onEmployeeRedirect: function (event) { + var self = this; event.preventDefault(); var employee_id = parseInt($(event.currentTarget).data('employee-id')); - return this.do_action({ - type: 'ir.actions.act_window', - view_type: 'form', - view_mode: 'form', - views: [[false, 'form']], - target: 'current', - res_model: 'hr.employee', - res_id: employee_id, + return this._rpc({ + model: 'hr.employee', + method: 'get_formview_action', + args: [employee_id], + }).then(function(action) { + return self.do_action(action); }); }, /** @@ -164,22 +162,23 @@ var FieldOrgChart = AbstractField.extend({ var employee_id = parseInt($(event.currentTarget).data('employee-id')); var employee_name = $(event.currentTarget).data('employee-name'); var type = $(event.currentTarget).data('type') || 'direct'; - var self = this + var self = this; if (employee_id) { this._getSubordinatesData(employee_id, type).then(function(data) { var domain = [['id', 'in', data]]; - - return self.do_action({ - name: employee_name, - type: 'ir.actions.act_window', - view_mode: 'kanban,list,form', - views: [[false, 'kanban'], [false, 'list'], [false, 'form']], - target: 'current', - res_model: 'hr.employee', - domain: domain, + return self._rpc({ + model: 'hr.employee', + method: 'get_formview_action', + args: [employee_id], + }).then(function(action) { + action = _.extend(action, { + 'view_mode': 'kanban,list,form', + 'views': [[false, 'kanban'], [false, 'list'], [false, 'form']], + 'domain': domain, + }); + return self.do_action(action); }); - }) - + }); } }, }); diff --git a/addons/hr_org_chart/static/src/xml/hr_org_chart.xml b/addons/hr_org_chart/static/src/xml/hr_org_chart.xml index 893e0394f90..2bb9db5d4ca 100644 --- a/addons/hr_org_chart/static/src/xml/hr_org_chart.xml +++ b/addons/hr_org_chart/static/src/xml/hr_org_chart.xml @@ -10,13 +10,13 @@ use bg-images to get a clean and centred images -->
+ t-att-style="'background-image:url(\'/web/image/hr.employee.public/' + employee.id + '/image/\')'"/>
@@ -151,7 +151,7 @@
- +
diff --git a/addons/hr_org_chart/static/tests/hr_org_chart_tests.js b/addons/hr_org_chart/static/tests/hr_org_chart_tests.js index e536f0b587b..98104311f55 100644 --- a/addons/hr_org_chart/static/tests/hr_org_chart_tests.js +++ b/addons/hr_org_chart/static/tests/hr_org_chart_tests.js @@ -41,6 +41,8 @@ QUnit.module('hr_org_chart', { managers: [], managers_more: false, }); + } else if (route === '/hr/get_redirect_model') { + return Promise.resolve('hr.employee'); } return this._super(route, args); } @@ -92,6 +94,8 @@ QUnit.module('hr_org_chart', { name: 'Antoine Langlais', } }); + } else if (route === '/hr/get_redirect_model') { + return Promise.resolve('hr.employee'); } return this._super(route, args); } @@ -153,6 +157,8 @@ QUnit.module('hr_org_chart', { name: 'John Smith', } }); + } else if (route === '/hr/get_redirect_model') { + return Promise.resolve('hr.employee'); } return this._super(route, args); } @@ -164,4 +170,4 @@ QUnit.module('hr_org_chart', { }); }); -}); \ No newline at end of file +}); diff --git a/addons/hr_org_chart/views/hr_views.xml b/addons/hr_org_chart/views/hr_views.xml index 2e9e090887b..a8e7a6c70bd 100644 --- a/addons/hr_org_chart/views/hr_views.xml +++ b/addons/hr_org_chart/views/hr_views.xml @@ -14,6 +14,22 @@ + + hr.employee.public.view.form.inherit.org_chart + hr.employee.public + + + + +
+

Organization Chart

+ +
+
+
+
+
+ res.users.preferences.view.form.inherit.org_chart res.users