From d4a0bcaa5a24842b99ad61e1e41a31152662e89c Mon Sep 17 00:00:00 2001 From: Thibault Libioulle Date: Thu, 29 Apr 2021 10:43:35 +0200 Subject: [PATCH] [IMP] sale_project: link project analytic account to invoice Previously when a user added products to a task, when invoicing the customer, in default case, no analytic account was defined on the invoice line generated for the sale order line. With this commit, we define a default analytic account based on the information of the sale order line. If the sale order line has a generated task or project associated to it, we set the project analytic account. If the sale order line is used on tasks or projects which all use the same analytic account, then the invoice line created will take this unique analytic account as default value. If a sale order line is used in distinct project or tasks from distinct project, then no default analytic account is defined. PR : #70527 task-2458135 --- addons/sale_project/models/project.py | 4 ++-- addons/sale_project/models/sale_order.py | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/addons/sale_project/models/project.py b/addons/sale_project/models/project.py index 10bb47f2a5d..204ed64dd5f 100644 --- a/addons/sale_project/models/project.py +++ b/addons/sale_project/models/project.py @@ -12,7 +12,7 @@ class Project(models.Model): sale_line_id = fields.Many2one( 'sale.order.line', 'Sales Order Item', copy=False, - compute="_compute_sale_line_id", store=True, readonly=False, + compute="_compute_sale_line_id", store=True, readonly=False, index=True, domain="[('is_service', '=', True), ('is_expense', '=', False), ('state', 'in', ['sale', 'done']), ('order_partner_id', '=?', partner_id), '|', ('company_id', '=', False), ('company_id', '=', company_id)]", 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.") @@ -61,7 +61,7 @@ class ProjectTask(models.Model): sale_order_id = fields.Many2one('sale.order', 'Sales Order', compute='_compute_sale_order_id', store=True, help="Sales order to which the task is linked.") sale_line_id = fields.Many2one( 'sale.order.line', 'Sales Order Item', domain="[('company_id', '=', company_id), ('is_service', '=', True), ('order_partner_id', 'child_of', commercial_partner_id), ('is_expense', '=', False), ('state', 'in', ['sale', 'done'])]", - compute='_compute_sale_line', recursive=True, store=True, readonly=False, copy=False, tracking=True, + compute='_compute_sale_line', recursive=True, store=True, readonly=False, copy=False, tracking=True, index=True, help="Sales Order Item to which the time spent on this task will be added, in order to be invoiced to your customer.") project_sale_order_id = fields.Many2one('sale.order', string="Project's sale order", related='project_id.sale_order_id') invoice_count = fields.Integer("Number of invoices", related='sale_order_id.invoice_count') diff --git a/addons/sale_project/models/sale_order.py b/addons/sale_project/models/sale_order.py index b91be8db811..10795b84a15 100644 --- a/addons/sale_project/models/sale_order.py +++ b/addons/sale_project/models/sale_order.py @@ -353,3 +353,24 @@ class SaleOrderLine(models.Model): project = map_so_project[so_line.order_id.id] if not so_line.task_id: so_line._timesheet_create_task(project=project) + + def _prepare_invoice_line(self, **optional_values): + """ + If the sale order line isn't linked to a sale order which already have a default analytic account, + this method allows to retrieve the analytic account which is linked to project or task directly linked + to this sale order line, or the analytic account of the project which uses this sale order line, if it exists. + """ + values = super(SaleOrderLine, self)._prepare_invoice_line(**optional_values) + if not values['analytic_account_id']: + if self.project_id.analytic_account_id: + values['analytic_account_id'] = self.project_id.analytic_account_id + elif self.task_id.project_id.analytic_account_id: + values['analytic_account_id'] = self.task_id.project_id.analytic_account_id + elif self.is_service and not self.is_expense: + project_analytic_account_id = self.env['project.project'].read_group([ + '|', ('sale_line_id', '=', self.id), ('task_ids.sale_line_id', '=', self.id) + ], ['analytic_account_id'], ['analytic_account_id']) + analytic_account_ids = {rec['analytic_account_id'][0] for rec in project_analytic_account_id} + if len(analytic_account_ids) == 1: + values['analytic_account_id'] = analytic_account_ids.pop() + return values