[IMP] hr_timesheet, sale_timesheet: Set task analytic account

Purpose
=======

Currently, it is only possible to set an Analytic Account for a whole Project, there
is no distinction by task. However, if the user has 1 task per customer, he cannot
track the costs and revenues for that specific customer easily. He has to manually
change the AA of the timesheets' analytic lines. An option would be to set a
different AA on the SO generating the task, but the AA of the project takes over
anyway.

Specifications
==============

If the user sets an AA on the SO, it should bypass the one set on the project
Add an AA field below the Email cc one on tasks in debug mode
- should be related to the AA field from the SO
- it should also bypass the AA set on the project
All the timesheets from this task should be related to the AA field set on the SO/Task

closes odoo/odoo#40844

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
Lucas Lefèvre
2020-01-31 11:02:14 +00:00
parent eafa9f4abc
commit ac8c30beec
4 changed files with 22 additions and 1 deletions
+7 -1
View File
@@ -84,7 +84,7 @@ class Task(models.Model):
_name = "project.task"
_inherit = ["project.task", "timer.mixin"]
analytic_account_active = fields.Boolean("Analytic Account", related='project_id.analytic_account_id.active', readonly=True)
analytic_account_active = fields.Boolean("Active Analytic Account", compute='_compute_analytic_account_active')
allow_timesheets = fields.Boolean("Allow timesheets", related='project_id.allow_timesheets', help="Timesheets can be logged on this task.", readonly=True)
remaining_hours = fields.Float("Remaining Hours", compute='_compute_remaining_hours', store=True, readonly=True, help="Total remaining time, can be re-estimated periodically by the assignee of the task.")
effective_hours = fields.Float("Hours Spent", compute='_compute_effective_hours', compute_sudo=True, store=True, help="Computed using the sum of the task work done.")
@@ -133,6 +133,12 @@ class Task(models.Model):
'display_timer_resume': resume,
})
@api.depends('project_id.analytic_account_id.active')
def _compute_analytic_account_active(self):
""" Overridden in sale_timesheet """
for task in self:
task.analytic_account_active = task.project_id.analytic_account_id.active
@api.depends('timesheet_ids.unit_amount')
def _compute_effective_hours(self):
for task in self:
+5
View File
@@ -68,6 +68,11 @@ class AccountAnalyticLine(models.Model):
@api.model
def _timesheet_preprocess(self, values):
if values.get('task_id') and not values.get('account_id'):
task = self.env['project.task'].browse(values.get('task_id'))
if task.analytic_account_id:
values['account_id'] = task.analytic_account_id.id
values['company_id'] = task.analytic_account_id.company_id.id
values = super(AccountAnalyticLine, self)._timesheet_preprocess(values)
# task implies so line (at create)
if 'task_id' in values and not values.get('so_line') and values.get('employee_id'):
+7
View File
@@ -127,6 +127,7 @@ class ProjectTask(models.Model):
# override sale_order_id and make it computed stored field instead of regular field.
sale_order_id = fields.Many2one(compute='_compute_sale_order_id', store=True, readonly=False)
analytic_account_id = fields.Many2one('account.analytic.account', related='sale_order_id.analytic_account_id')
billable_type = fields.Selection([
('task_rate', 'At Task Rate'),
('employee_rate', 'At Employee Rate'),
@@ -161,6 +162,12 @@ class ProjectTask(models.Model):
'message': message
}}
@api.depends('analytic_account_id.active')
def _compute_analytic_account_active(self):
super()._compute_analytic_account_active()
for task in self:
task.analytic_account_active = task.analytic_account_active or task.analytic_account_id.active
@api.depends('sale_line_id', 'project_id', 'billable_type')
def _compute_sale_order_id(self):
for task in self:
@@ -81,6 +81,9 @@
<xpath expr="//group[@name='sales_order_group']" position="inside">
<field name="billable_type" invisible="1"/>
</xpath>
<xpath expr="//field[@name='email_cc']" position="after">
<field name="analytic_account_id" groups="base.group_no_one"/>
</xpath>
</field>
</record>