diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py
index 9533ed792f3..b12a9e58308 100644
--- a/addons/hr_timesheet/models/hr_timesheet.py
+++ b/addons/hr_timesheet/models/hr_timesheet.py
@@ -237,7 +237,7 @@ class AccountAnalyticLine(models.Model):
# (re)compute the amount (depending on unit_amount, employee_id for the cost, and account_id for currency)
if any(field_name in values for field_name in ['unit_amount', 'employee_id', 'account_id']):
for timesheet in sudo_self:
- cost = timesheet.employee_id.timesheet_cost or 0.0
+ cost = timesheet._employee_timesheet_cost()
amount = -timesheet.unit_amount * cost
amount_converted = timesheet.employee_id.currency_id._convert(
amount, timesheet.account_id.currency_id, self.env.company, timesheet.date)
@@ -258,3 +258,7 @@ class AccountAnalyticLine(models.Model):
def _get_timesheet_time_day(self):
return self._convert_hours_to_days(self.unit_amount)
+
+ def _employee_timesheet_cost(self):
+ self.ensure_one()
+ return self.employee_id.timesheet_cost or 0.0
diff --git a/addons/sale_timesheet/models/account.py b/addons/sale_timesheet/models/account.py
index 3704da2b4da..8b9e65168b4 100644
--- a/addons/sale_timesheet/models/account.py
+++ b/addons/sale_timesheet/models/account.py
@@ -98,7 +98,7 @@ class AccountAnalyticLine(models.Model):
if not self.task_id:
if self.project_id.pricing_type == 'employee_rate':
- map_entry = self.env['project.sale.line.employee.map'].search([('project_id', '=', self.project_id.id), ('employee_id', '=', self.employee_id.id)])
+ map_entry = self._get_employee_mapping_entry()
if map_entry:
return map_entry.sale_line_id
if self.project_id.sale_line_id:
@@ -149,3 +149,14 @@ class AccountAnalyticLine(models.Model):
def _unlink_except_invoiced(self):
if any(line.timesheet_invoice_id and line.timesheet_invoice_id.state == 'posted' for line in self):
raise UserError(_('You cannot remove a timesheet that has already been invoiced.'))
+
+ def _get_employee_mapping_entry(self):
+ self.ensure_one()
+ return self.env['project.sale.line.employee.map'].search([('project_id', '=', self.project_id.id), ('employee_id', '=', self.employee_id.id)])
+
+ def _employee_timesheet_cost(self):
+ if self.project_id.pricing_type == 'employee_rate':
+ mapping_entry = self._get_employee_mapping_entry()
+ if mapping_entry:
+ return mapping_entry.cost
+ return super()._employee_timesheet_cost()
diff --git a/addons/sale_timesheet/models/project_sale_line_employee_map.py b/addons/sale_timesheet/models/project_sale_line_employee_map.py
index 7e12c500274..187e0bcbb60 100644
--- a/addons/sale_timesheet/models/project_sale_line_employee_map.py
+++ b/addons/sale_timesheet/models/project_sale_line_employee_map.py
@@ -10,7 +10,7 @@ class ProjectProductEmployeeMap(models.Model):
project_id = fields.Many2one('project.project', "Project", required=True)
employee_id = fields.Many2one('hr.employee', "Employee", required=True)
- sale_line_id = fields.Many2one('sale.order.line', "Sale Order Item", compute="_compute_sale_line_id", store=True, readonly=False, required=True,
+ sale_line_id = fields.Many2one('sale.order.line', "Sale Order Item", compute="_compute_sale_line_id", store=True, readonly=False,
domain="""[
('is_service', '=', True),
('is_expense', '=', False),
@@ -21,6 +21,10 @@ class ProjectProductEmployeeMap(models.Model):
partner_id = fields.Many2one(related='project_id.partner_id')
price_unit = fields.Float("Unit Price", compute='_compute_price_unit', store=True, readonly=True)
currency_id = fields.Many2one('res.currency', string="Currency", compute='_compute_currency_id', store=True, readonly=False)
+ cost = fields.Monetary(currency_field='cost_currency_id', compute='_compute_cost', store=True, readonly=False,
+ help="This cost overrides the employee's default timesheet cost in employee's HR Settings")
+ cost_currency_id = fields.Many2one('res.currency', string="Cost Currency", related='employee_id.currency_id', readonly=True)
+ is_cost_changed = fields.Boolean('Is Cost Manually Changed', compute='_compute_is_cost_changed', store=True)
_sql_constraints = [
('uniqueness_employee', 'UNIQUE(project_id,employee_id)', 'An employee cannot be selected more than once in the mapping. Please remove duplicate(s) and try again.'),
@@ -48,6 +52,17 @@ class ProjectProductEmployeeMap(models.Model):
for line in self:
line.currency_id = line.sale_line_id.currency_id if line.sale_line_id else False
+ @api.depends('employee_id.timesheet_cost')
+ def _compute_cost(self):
+ for map_entry in self:
+ if not map_entry.is_cost_changed:
+ map_entry.cost = map_entry.employee_id.timesheet_cost or 0.0
+
+ @api.depends('cost')
+ def _compute_is_cost_changed(self):
+ for map_entry in self:
+ map_entry.is_cost_changed = map_entry.employee_id and map_entry.cost != map_entry.employee_id.timesheet_cost
+
@api.model
def create(self, values):
res = super(ProjectProductEmployeeMap, self).create(values)
diff --git a/addons/sale_timesheet/views/project_task_views.xml b/addons/sale_timesheet/views/project_task_views.xml
index 91c69de17f3..159a4514528 100644
--- a/addons/sale_timesheet/views/project_task_views.xml
+++ b/addons/sale_timesheet/views/project_task_views.xml
@@ -33,7 +33,9 @@
+
+