From 8b89f63d2c14d7df15e2618a2847702930037118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre?= Date: Wed, 20 Nov 2019 15:47:25 +0100 Subject: [PATCH 1/5] [FIX] sale_timsheet: Consider employees in current companies In the project overview, "Time by people" shows data from other companies. One user can be linked to several employees (in different companies). Because searching the employees is performed in a sudo'ed env, the multicompany ir.rule is not applied and *all* employees of each assigned users are retrieved. The employees from other companies should be filtered. Task 2119567 --- addons/sale_timesheet/models/project_overview.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/sale_timesheet/models/project_overview.py b/addons/sale_timesheet/models/project_overview.py index 946990be91e..41c7a26c506 100644 --- a/addons/sale_timesheet/models/project_overview.py +++ b/addons/sale_timesheet/models/project_overview.py @@ -5,6 +5,7 @@ import itertools import json from odoo import fields, _, models +from odoo.osv import expression from odoo.tools import float_round from odoo.tools.misc import get_lang @@ -103,7 +104,8 @@ class Project(models.Model): employee_ids.extend(list(map(lambda x: x['employee_id'][0], aal_employee_ids))) # Retrieve the employees for which the current user can see theirs timesheets - employees = self.env['hr.employee'].sudo().browse(employee_ids).filtered_domain(self.env['account.analytic.line']._domain_employee_id()) + employee_domain = expression.AND([[('company_id', 'in', self.env.companies.ids)], self.env['account.analytic.line']._domain_employee_id()]) + employees = self.env['hr.employee'].sudo().browse(employee_ids).filtered_domain(employee_domain) repartition_domain = [('project_id', 'in', self.ids), ('employee_id', '!=', False), ('timesheet_invoice_type', '!=', False)] # force billable type # repartition data, without timesheet on cancelled so repartition_data = self.env['account.analytic.line'].read_group(repartition_domain + ['|', ('so_line', '=', False), ('so_line.state', '!=', 'cancel')], ['employee_id', 'timesheet_invoice_type', 'unit_amount'], ['employee_id', 'timesheet_invoice_type'], lazy=False) From 3519b9872ece1337ca0d008fbfa032a8005c35af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre?= Date: Fri, 15 Nov 2019 13:38:06 +0100 Subject: [PATCH 2/5] [IMP] web: Add support of js_class attribute for qweb views Task 2119567 --- addons/web/models/models.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/web/models/models.py b/addons/web/models/models.py index 0d03d950b9f..3a70ab4f0c8 100644 --- a/addons/web/models/models.py +++ b/addons/web/models/models.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import babel.dates import pytz +from lxml import etree from odoo import _, api, fields, models from odoo.osv.expression import AND @@ -202,9 +203,11 @@ class Base(models.AbstractModel): def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): r = super().fields_view_get(view_id, view_type, toolbar, submenu) # avoid leaking the raw (un-rendered) template, also avoids bloating - # the response payload for no reason + # the response payload for no reason. Only send the root node, + # to send attributes such as `js_class`. if r['type'] == 'qweb': - r['arch'] = '' + root = etree.fromstring(r['arch']) + r['arch'] = etree.tostring(etree.Element('qweb', root.attrib)) return r @api.model From 9acb61c5da6ab20fc344e5124dd5eab56b99b259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre?= Date: Mon, 25 Nov 2019 13:22:30 +0100 Subject: [PATCH 3/5] [IMP] sale_timesheet: Allow to fold/unfold project overview Allow to fold/unfold the details by SO. It should be folded by default. Note: Although qweb views have a generic mechanism to manage fold and unfold, this standard behavior is not used here. It would imply refactoring the entire code preparing the template data (700+ lines of code which are hard to read). The quick and dirty js way is used for now. Task 2119567 --- .../static/src/js/project_overview.js | 56 +++++++++++++++++++ .../views/hr_timesheet_templates.xml | 24 +++++++- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 addons/sale_timesheet/static/src/js/project_overview.js diff --git a/addons/sale_timesheet/static/src/js/project_overview.js b/addons/sale_timesheet/static/src/js/project_overview.js new file mode 100644 index 00000000000..876a79633ca --- /dev/null +++ b/addons/sale_timesheet/static/src/js/project_overview.js @@ -0,0 +1,56 @@ +odoo.define('sale_timesheet.project_overview', function (require) { + "use strict"; + + var qweb = require('web.qweb'); + var viewRegistry = require('web.view_registry'); + + const Controller = qweb.Controller.extend({ + events: _.extend({}, qweb.Controller.prototype.events, { + 'click .project_overview_foldable': '_onFoldToggle', + }), + + _onFoldToggle(ev) { + const {model, resId} = ev.target.dataset; + const shouldOpen = ev.target.classList.contains('fa-caret-right'); + if (model === 'sale.order' && shouldOpen) { + this._openSaleOrder(resId); + } + else if (model === 'sale.order.line' && shouldOpen) { + this._openSaleOrderLine(resId); + } + else { + const targetClass = `.${model.replace(/\./g, '_')}_${resId || 'None'}`; + this.$(targetClass).hide(); + } + $(ev.target).toggleClass('fa-caret-right'); + $(ev.target).toggleClass('fa-caret-down'); + }, + + _openSaleOrder(id) { + id = id || 'None'; + const targetClass = `.sale_order_${id}`; + this.$(`.o_timesheet_forecast_sale_order_line${targetClass}`).show(); + this.$(`.o_timesheet_forecast_hr_employee${targetClass}`).hide(); + this.$(`.o_timesheet_forecast_sale_order_line${targetClass} .fa`).removeClass('fa-caret-down'); + this.$(`.o_timesheet_forecast_sale_order_line${targetClass} .fa`).addClass('fa-caret-right'); + + }, + + _openSaleOrderLine(id) { + id = id || 'None'; + const targetClass = `.sale_order_line_${id}`; + this.$(`.o_timesheet_forecast_hr_employee${targetClass}`).show(); + }, + }); + + var ProjectOverview = qweb.View.extend({ + withSearchBar: true, + searchMenuTypes: [], + + config: _.extend({}, qweb.View.prototype.config, { + Controller: Controller, + }), + }); + + viewRegistry.add('project_overview', ProjectOverview); +}); diff --git a/addons/sale_timesheet/views/hr_timesheet_templates.xml b/addons/sale_timesheet/views/hr_timesheet_templates.xml index 1c65ecfbc07..e3692eb3345 100644 --- a/addons/sale_timesheet/views/hr_timesheet_templates.xml +++ b/addons/sale_timesheet/views/hr_timesheet_templates.xml @@ -4,6 +4,7 @@ @@ -12,6 +13,7 @@ qweb project.project +