[IMP] hr{,sale}_timesheet: add employee mapping cost

Prior to this commit, the timesheet amount was computed based on the
employee timesheet cost.
The sale order line related to the employee was also required

This commit allows the project owner to configure a employee mapping
cost that will override the employee timesheet cost if defined.
This commit removes the fact that the sale order line is no more
required, thus the mapping will have no effect.

PR : #70527

task-2458135
This commit is contained in:
Thibault Libioulle
2021-09-03 12:45:58 +02:00
committed by Laurent Stukkens (LTU)
parent dd706ea024
commit dbbfce18a4
4 changed files with 35 additions and 3 deletions
+5 -1
View File
@@ -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
+12 -1
View File
@@ -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()
@@ -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)
@@ -33,7 +33,9 @@
<field name="employee_id" options="{'no_create': True}"/>
<field name="sale_line_id" attrs="{'required': True}" options="{'no_create': True}"/>
<field name="price_unit" widget="monetary" force_save="1" options="{'currency_field': 'currency_id'}"/>
<field name="cost"/>
<field name="currency_id" invisible="1"/>
<field name="cost_currency_id" invisible="1"/>
</tree>
</field>
</page>