From eb51bdb5adff24bffb7743bd8b8a1b9e569c910c Mon Sep 17 00:00:00 2001 From: Kevin Baptiste Date: Tue, 15 Sep 2020 06:19:00 +0000 Subject: [PATCH] [IMP] sale,sale_project: show Project Overview The project overview statbutton will only be shown when there's a proper Project Overview to display (when there are timesheets, etc.) closes odoo/odoo#57698 Taskid: 2257764 Signed-off-by: Yannick Tivisse (yti) --- addons/sale/views/sale_views.xml | 15 ++++++++++++ addons/sale_project/models/project.py | 8 +++++++ addons/sale_project/models/sale_order.py | 17 ++++++++++++- .../sale_project/views/sale_order_views.xml | 5 +++- addons/sale_timesheet/models/project.py | 6 +++++ .../sale_timesheet/models/project_overview.py | 24 +++++++++++++++---- addons/sale_timesheet/models/sale_order.py | 7 +++--- .../sale_timesheet/views/sale_order_views.xml | 3 --- 8 files changed, 71 insertions(+), 14 deletions(-) diff --git a/addons/sale/views/sale_views.xml b/addons/sale/views/sale_views.xml index d9cd1aa68e3..0c069240fd3 100644 --- a/addons/sale/views/sale_views.xml +++ b/addons/sale/views/sale_views.xml @@ -810,6 +810,21 @@ + + Sales Order + ir.actions.act_window + sale.order + form,tree,kanban,calendar,pivot,graph,activity + + +

+ Create a new quotation, the first step of a new sale! +

+ Once the quotation is confirmed, it becomes a sales order.
You will be able to create an invoice and collect the payment. +

+
+
+ tree diff --git a/addons/sale_project/models/project.py b/addons/sale_project/models/project.py index a1695c461d5..0e3806ff538 100644 --- a/addons/sale_project/models/project.py +++ b/addons/sale_project/models/project.py @@ -16,6 +16,7 @@ class Project(models.Model): help="Sales order item to which the project is linked. Link the timesheet entry to the sales order item defined on the project. " "Only applies on tasks without sale order item defined, and if the employee is not in the 'Employee/Sales Order Item Mapping' of the project.") sale_order_id = fields.Many2one('sale.order', 'Sales Order', domain="[('partner_id', '=', partner_id)]", copy=False, help="Sales order to which the project is linked.") + project_overview = fields.Boolean('Show Project Overview', compute='_compute_project_overview') _sql_constraints = [ ('sale_order_required_if_sale_line', "CHECK((sale_line_id IS NOT NULL AND sale_order_id IS NOT NULL) OR (sale_line_id IS NULL))", 'The project should be linked to a sale order to select a sale order item.'), @@ -27,6 +28,13 @@ class Project(models.Model): defaults['sale_line_id'] = False return defaults + @api.depends('analytic_account_id') + def _compute_project_overview(self): + overview = self.env['project.project'] + if self.user_has_groups('analytic.group_analytic_accounting'): + overview = self.filtered(lambda p: p.analytic_account_id) + overview.project_overview = True + (self - overview).project_overview = False class ProjectTask(models.Model): _inherit = "project.task" diff --git a/addons/sale_project/models/sale_order.py b/addons/sale_project/models/sale_order.py index e779902dcc4..065105b9e8c 100644 --- a/addons/sale_project/models/sale_order.py +++ b/addons/sale_project/models/sale_order.py @@ -17,6 +17,8 @@ class SaleOrder(models.Model): 'project.project', 'Project', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help='Select a non billable project on which tasks can be created.') project_ids = fields.Many2many('project.project', compute="_compute_project_ids", string='Projects', copy=False, groups="project.group_project_user", help="Projects used in this sales order.") + project_overview = fields.Boolean('Show Project Overview', compute='_compute_project_overview') + project_count = fields.Integer(string='Number of Projects', compute='_compute_project_ids', groups='project.group_project_user') @api.depends('order_line.product_id.project_id') def _compute_tasks_ids(self): @@ -33,6 +35,12 @@ class SaleOrder(models.Model): service_tracking == 'task_in_project' for service_tracking in order.order_line.mapped('product_id.service_tracking') ) + @api.depends('project_ids') + def _compute_project_overview(self): + for order in self: + billable_projects = order.project_ids.filtered('sale_line_id') + order.project_overview = len(order.project_ids) == 1 and len(billable_projects) == 1 and billable_projects.project_overview + @api.depends('order_line.product_id', 'order_line.project_id') def _compute_project_ids(self): for order in self: @@ -40,6 +48,7 @@ class SaleOrder(models.Model): projects |= order.order_line.mapped('project_id') projects |= order.project_id order.project_ids = projects + order.project_count = len(projects) @api.onchange('project_id') def _onchange_project_id(self): @@ -92,16 +101,22 @@ class SaleOrder(models.Model): def action_view_project_ids(self): self.ensure_one() + if len(self.project_ids) == 1 and self.project_overview: + return self.project_id.action_view_account_analytic_line() + view_form_id = self.env.ref('project.edit_project').id view_kanban_id = self.env.ref('project.view_project_kanban').id action = { 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.project_ids.ids)], - 'views': [(view_kanban_id, 'kanban'), (view_form_id, 'form')], 'view_mode': 'kanban,form', 'name': _('Projects'), 'res_model': 'project.project', } + if len(self.project_ids) == 1: + action.update({'views': [(view_form_id, 'form')], 'res_id': self.project_ids.id}) + else: + action['views'] = [(view_kanban_id, 'kanban'), (view_form_id, 'form')] return action def write(self, values): diff --git a/addons/sale_project/views/sale_order_views.xml b/addons/sale_project/views/sale_order_views.xml index 49c4e7cf519..6d2fcf9afd8 100644 --- a/addons/sale_project/views/sale_order_views.xml +++ b/addons/sale_project/views/sale_order_views.xml @@ -10,9 +10,12 @@ - +