132 lines
6.0 KiB
Python
132 lines
6.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models
|
|
|
|
|
|
class ProjectProductEmployeeMap(models.Model):
|
|
_name = 'project.sale.line.employee.map'
|
|
_description = 'Project Sales line, employee mapping'
|
|
|
|
project_id = fields.Many2one('project.project', "Project", required=True)
|
|
employee_id = fields.Many2one('hr.employee', "Employee", required=True, domain="[('id', 'not in', existing_employee_ids)]")
|
|
existing_employee_ids = fields.Many2many('hr.employee', compute="_compute_existing_employee_ids")
|
|
sale_line_id = fields.Many2one(
|
|
'sale.order.line', "Sales Order Item",
|
|
compute="_compute_sale_line_id", store=True, readonly=False,
|
|
domain="""[
|
|
('is_service', '=', True),
|
|
('is_expense', '=', False),
|
|
('state', '=', 'sale'),
|
|
('order_partner_id', '=?', partner_id)]""")
|
|
sale_order_id = fields.Many2one(related="project_id.sale_order_id")
|
|
company_id = fields.Many2one('res.company', string='Company', related='project_id.company_id')
|
|
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 employee hourly wage in employee's HR Settings")
|
|
display_cost = fields.Monetary(currency_field='cost_currency_id', compute="_compute_display_cost", inverse="_inverse_display_cost", string="Hourly Cost")
|
|
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.'),
|
|
]
|
|
|
|
@api.depends('employee_id', 'project_id.sale_line_employee_ids.employee_id')
|
|
def _compute_existing_employee_ids(self):
|
|
project = self.project_id
|
|
if len(project) == 1:
|
|
self.existing_employee_ids = project.sale_line_employee_ids.employee_id
|
|
return
|
|
for map_entry in self:
|
|
map_entry.existing_employee_ids = map_entry.project_id.sale_line_employee_ids.employee_id
|
|
|
|
@api.depends('partner_id')
|
|
def _compute_sale_line_id(self):
|
|
self.filtered(
|
|
lambda map_entry:
|
|
map_entry.sale_line_id
|
|
and map_entry.partner_id
|
|
and map_entry.sale_line_id.order_partner_id.commercial_partner_id != map_entry.partner_id.commercial_partner_id
|
|
).update({'sale_line_id': False})
|
|
|
|
@api.depends('sale_line_id.price_unit')
|
|
def _compute_price_unit(self):
|
|
for line in self:
|
|
if line.sale_line_id:
|
|
line.price_unit = line.sale_line_id.price_unit
|
|
else:
|
|
line.price_unit = 0
|
|
|
|
@api.depends('sale_line_id.price_unit')
|
|
def _compute_currency_id(self):
|
|
for line in self:
|
|
line.currency_id = line.sale_line_id.currency_id if line.sale_line_id else False
|
|
|
|
@api.depends('employee_id.hourly_cost')
|
|
def _compute_cost(self):
|
|
self.env.remove_to_compute(self._fields['is_cost_changed'], self)
|
|
for map_entry in self:
|
|
if not map_entry.is_cost_changed:
|
|
map_entry.cost = map_entry.employee_id.hourly_cost or 0.0
|
|
|
|
def _get_working_hours_per_calendar(self, is_uom_day=False):
|
|
resource_calendar_per_hours = {}
|
|
|
|
if not is_uom_day:
|
|
return resource_calendar_per_hours
|
|
|
|
read_group_data = self.env['resource.calendar']._read_group(
|
|
[('id', 'in', self.employee_id.resource_calendar_id.ids)],
|
|
['hours_per_day'],
|
|
['id:array_agg'],
|
|
)
|
|
for hours_per_day, ids in read_group_data:
|
|
for calendar_id in ids:
|
|
resource_calendar_per_hours[calendar_id] = hours_per_day
|
|
|
|
return resource_calendar_per_hours
|
|
|
|
@api.depends_context('company')
|
|
@api.depends('cost', 'employee_id.resource_calendar_id')
|
|
def _compute_display_cost(self):
|
|
is_uom_day = self.env.ref('uom.product_uom_day') == self.env.company.timesheet_encode_uom_id
|
|
resource_calendar_per_hours = self._get_working_hours_per_calendar(is_uom_day)
|
|
|
|
for map_line in self:
|
|
if is_uom_day:
|
|
map_line.display_cost = map_line.cost * resource_calendar_per_hours.get(map_line.employee_id.resource_calendar_id.id, 1)
|
|
else:
|
|
map_line.display_cost = map_line.cost
|
|
|
|
def _inverse_display_cost(self):
|
|
is_uom_day = self.env.ref('uom.product_uom_day') == self.env.company.timesheet_encode_uom_id
|
|
resource_calendar_per_hours = self._get_working_hours_per_calendar(is_uom_day)
|
|
|
|
for map_line in self:
|
|
if is_uom_day:
|
|
map_line.cost = map_line.display_cost / resource_calendar_per_hours.get(map_line.employee_id.resource_calendar_id.id, 1)
|
|
else:
|
|
map_line.cost = map_line.display_cost
|
|
|
|
@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.hourly_cost
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
maps = super().create(vals_list)
|
|
maps._update_project_timesheet()
|
|
return maps
|
|
|
|
def write(self, values):
|
|
res = super(ProjectProductEmployeeMap, self).write(values)
|
|
self._update_project_timesheet()
|
|
return res
|
|
|
|
def _update_project_timesheet(self):
|
|
self.filtered(lambda l: l.sale_line_id).project_id._update_timesheets_sale_line_id()
|