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 @@ + +