diff --git a/addons/hr/models/hr_employee_base.py b/addons/hr/models/hr_employee_base.py
index 75eef28fa8c..02f0d91b00b 100644
--- a/addons/hr/models/hr_employee_base.py
+++ b/addons/hr/models/hr_employee_base.py
@@ -29,7 +29,9 @@ class HrEmployeeBase(models.AbstractModel):
resource_id = fields.Many2one('resource.resource')
resource_calendar_id = fields.Many2one('resource.calendar', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
parent_id = fields.Many2one('hr.employee', 'Manager', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
- coach_id = fields.Many2one('hr.employee', 'Coach', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
+ coach_id = fields.Many2one(
+ 'hr.employee', 'Coach', compute='_compute_coach', store=True, readonly=False,
+ domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
tz = fields.Selection(
string='Timezone', related='resource_id.tz', readonly=False,
help="This field is used in order to define in which timezone the resources will work.")
@@ -77,9 +79,10 @@ class HrEmployeeBase(models.AbstractModel):
employee.last_activity = False
employee.last_activity_time = False
- @api.onchange('parent_id')
- def _onchange_parent_id(self):
- manager = self.parent_id
- previous_manager = self._origin.parent_id
- if manager and (self.coach_id == previous_manager or not self.coach_id):
- self.coach_id = manager
+ @api.depends('parent_id')
+ def _compute_coach(self):
+ for employee in self:
+ manager = employee.parent_id
+ previous_manager = employee._origin.parent_id
+ if manager and (employee.coach_id == previous_manager or not employee.coach_id):
+ employee.coach_id = manager
diff --git a/addons/hr/views/hr_employee_views.xml b/addons/hr/views/hr_employee_views.xml
index 4320ec08924..494b00ccc33 100644
--- a/addons/hr/views/hr_employee_views.xml
+++ b/addons/hr/views/hr_employee_views.xml
@@ -200,14 +200,15 @@
hr.employee.tree
hr.employee
-
-
-
+
+
+
-
+
+
diff --git a/addons/hr_contract/models/hr_contract.py b/addons/hr_contract/models/hr_contract.py
index 6f92ca248af..4b931f9e50c 100644
--- a/addons/hr_contract/models/hr_contract.py
+++ b/addons/hr_contract/models/hr_contract.py
@@ -145,8 +145,8 @@ class Contract(models.Model):
self._assign_open_contract()
calendar = vals.get('resource_calendar_id')
- if calendar and (self.state == 'open' or (self.state == 'draft' and self.kanban_state == 'done')):
- self.mapped('employee_id').write({'resource_calendar_id': calendar})
+ if calendar:
+ self.filtered(lambda c: c.state == 'open' or (c.state == 'draft' and c.kanban_state == 'done')).mapped('employee_id').write({'resource_calendar_id': calendar})
if 'state' in vals and 'kanban_state' not in vals:
self.write({'kanban_state': 'normal'})
diff --git a/addons/hr_contract/views/hr_contract_views.xml b/addons/hr_contract/views/hr_contract_views.xml
index 35fa68756b9..5b4a0f08a18 100644
--- a/addons/hr_contract/views/hr_contract_views.xml
+++ b/addons/hr_contract/views/hr_contract_views.xml
@@ -206,18 +206,19 @@
decoration-bf="message_needaction == True"
decoration-info="state == 'draft'"
decoration-muted="state in ('close', 'cancel')"
- decoration-danger="state == 'pending'">
-
-
+ decoration-danger="state == 'pending'"
+ multi_edit="1">
+
+
-
-
+
+
-
+
diff --git a/addons/hr_expense/models/hr_employee.py b/addons/hr_expense/models/hr_employee.py
index 6b09198d7fb..fb7f158d1f8 100644
--- a/addons/hr_expense/models/hr_employee.py
+++ b/addons/hr_expense/models/hr_employee.py
@@ -20,15 +20,16 @@ class Employee(models.Model):
expense_manager_id = fields.Many2one(
'res.users', string='Expense',
domain=_group_hr_expense_user_domain,
+ compute='_compute_expense_manager', store=True, readonly=False,
help="User responsible of expense approval. Should be Expense approver.")
- @api.onchange('parent_id')
- def _onchange_parent_id(self):
- super(Employee, self)._onchange_parent_id()
- previous_manager = self._origin.parent_id.user_id
- manager = self.parent_id.user_id
- if manager and manager.has_group('hr_expense.group_hr_expense_user') and (self.expense_manager_id == previous_manager or not self.expense_manager_id):
- self.expense_manager_id = manager
+ @api.depends('parent_id')
+ def _compute_expense_manager(self):
+ for employee in self:
+ previous_manager = employee._origin.parent_id.user_id
+ manager = employee.parent_id.user_id
+ if manager and manager.has_group('hr_expense.group_hr_expense_user') and (employee.expense_manager_id == previous_manager or not employee.expense_manager_id):
+ employee.expense_manager_id = manager
class EmployeePublic(models.Model):
diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml
index 08b88107ac9..4e6ad936c84 100644
--- a/addons/hr_expense/views/hr_expense_views.xml
+++ b/addons/hr_expense/views/hr_expense_views.xml
@@ -12,6 +12,17 @@
+
+ hr.employee.tree.expense
+ hr.employee
+
+
+
+
+
+
+
+
hr.user.preferences.form.inherit.hr.expense
res.users
diff --git a/addons/hr_holidays/models/hr_employee.py b/addons/hr_holidays/models/hr_employee.py
index 39a2a3e704e..45b3ca0ecd4 100644
--- a/addons/hr_holidays/models/hr_employee.py
+++ b/addons/hr_holidays/models/hr_employee.py
@@ -12,6 +12,7 @@ class HrEmployeeBase(models.AbstractModel):
leave_manager_id = fields.Many2one(
'res.users', string='Time Off',
+ compute='_compute_leave_manager', store=True, readonly=False,
help="User responsible of leaves approval.")
remaining_leaves = fields.Float(
compute='_compute_remaining_leaves', string='Remaining Paid Time Off',
@@ -119,13 +120,13 @@ class HrEmployeeBase(models.AbstractModel):
employee.current_leave_id = leave_data.get(employee.id, {}).get('current_leave_id')
employee.is_absent = leave_data.get(employee.id) and leave_data.get(employee.id, {}).get('current_leave_state') not in ['cancel', 'refuse', 'draft']
- @api.onchange('parent_id')
- def _onchange_parent_id(self):
- super(HrEmployeeBase, self)._onchange_parent_id()
- previous_manager = self._origin.parent_id.user_id
- manager = self.parent_id.user_id
- if manager and self.leave_manager_id == previous_manager or not self.leave_manager_id:
- self.leave_manager_id = manager
+ @api.depends('parent_id')
+ def _compute_leave_manager(self):
+ for employee in self:
+ previous_manager = employee._origin.parent_id.user_id
+ manager = employee.parent_id.user_id
+ if manager and employee.leave_manager_id == previous_manager or not employee.leave_manager_id:
+ employee.leave_manager_id = manager
def _compute_show_leaves(self):
show_leaves = self.env['res.users'].has_group('hr_holidays.group_hr_holidays_user')
@@ -144,20 +145,7 @@ class HrEmployeeBase(models.AbstractModel):
])
return [('id', 'in', holidays.mapped('employee_id').ids)]
- @api.model
- def create(self, values):
- if 'parent_id' in values:
- manager = self.env['hr.employee'].browse(values['parent_id']).user_id
- values['leave_manager_id'] = values.get('leave_manager_id', manager.id)
- return super(HrEmployeeBase, self).create(values)
-
def write(self, values):
- if 'parent_id' in values:
- manager = self.env['hr.employee'].browse(values['parent_id']).user_id
- if manager:
- to_change = self.filtered(lambda e: e.leave_manager_id == e.parent_id.user_id or not e.leave_manager_id)
- to_change.write({'leave_manager_id': values.get('leave_manager_id', manager.id)})
-
res = super(HrEmployeeBase, self).write(values)
if 'parent_id' in values or 'department_id' in values:
today_date = fields.Datetime.now()
diff --git a/addons/hr_holidays/views/hr_views.xml b/addons/hr_holidays/views/hr_views.xml
index d4d08dae23f..a5936b0759f 100644
--- a/addons/hr_holidays/views/hr_views.xml
+++ b/addons/hr_holidays/views/hr_views.xml
@@ -182,6 +182,17 @@
+
+ hr.employee.tree.leave
+ hr.employee
+
+
+
+
+
+
+
+
hr.employee.public.leave.form.inherit
hr.employee.public
diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py
index f0ebe71a7f5..df1924dcb62 100644
--- a/addons/hr_recruitment/models/hr_recruitment.py
+++ b/addons/hr_recruitment/models/hr_recruitment.py
@@ -93,45 +93,26 @@ class Applicant(models.Model):
_order = "priority desc, id desc"
_inherit = ['mail.thread.cc', 'mail.activity.mixin', 'utm.mixin']
- def _default_stage_id(self):
- if self._context.get('default_job_id'):
- return self.env['hr.recruitment.stage'].search([
- '|',
- ('job_ids', '=', False),
- ('job_ids', '=', self._context['default_job_id']),
- ('fold', '=', False)
- ], order='sequence asc', limit=1).id
- return False
-
- def _default_company_id(self):
- company_id = False
- if self._context.get('default_department_id'):
- department = self.env['hr.department'].browse(self._context['default_department_id'])
- company_id = department.company_id.id
- if not company_id and self.job_id:
- company_id = self.env['hr.job'].browse(self._context['default_job_id']).company_id.ids
- if not company_id:
- company_id = self.env.company
- return company_id
-
name = fields.Char("Subject / Application Name", required=True)
active = fields.Boolean("Active", default=True, help="If the active field is set to false, it will allow you to hide the case without removing it.")
description = fields.Text("Description")
- email_from = fields.Char("Email", size=128, help="Applicant email")
+ email_from = fields.Char("Email", size=128, help="Applicant email", compute='_compute_partner_phone_email', store=True, readonly=False)
probability = fields.Float("Probability")
partner_id = fields.Many2one('res.partner', "Contact", copy=False)
create_date = fields.Datetime("Creation Date", readonly=True, index=True)
stage_id = fields.Many2one('hr.recruitment.stage', 'Stage', ondelete='restrict', tracking=True,
+ compute='_compute_stage', store=True, readonly=False,
domain="['|', ('job_ids', '=', False), ('job_ids', '=', job_id)]",
copy=False, index=True,
- group_expand='_read_group_stage_ids',
- default=_default_stage_id)
+ group_expand='_read_group_stage_ids')
last_stage_id = fields.Many2one('hr.recruitment.stage', "Last Stage",
help="Stage of the applicant before being in the current stage. Used for lost cases analysis.")
categ_ids = fields.Many2many('hr.applicant.category', string="Tags")
- company_id = fields.Many2one('res.company', "Company", default=_default_company_id)
- user_id = fields.Many2one('res.users', "Responsible", tracking=True, default=lambda self: self.env.uid)
- date_closed = fields.Datetime("Closed", readonly=True, index=True)
+ company_id = fields.Many2one('res.company', "Company", compute='_compute_company', store=True, readonly=False)
+ user_id = fields.Many2one(
+ 'res.users', "Responsible", compute='_compute_user',
+ tracking=True, default=lambda self: self.env.uid, store=True, readonly=False)
+ date_closed = fields.Datetime("Closed", compute='_compute_date_closed', store=True, index=True)
date_open = fields.Datetime("Assigned", readonly=True, index=True)
date_last_stage_update = fields.Datetime("Last Stage Update", index=True, default=fields.Datetime.now)
priority = fields.Selection(AVAILABLE_PRIORITIES, "Appreciation", default='0')
@@ -142,10 +123,12 @@ class Applicant(models.Model):
salary_expected = fields.Float("Expected Salary", group_operator="avg", help="Salary Expected by Applicant")
availability = fields.Date("Availability", help="The date at which the applicant will be available to start working")
partner_name = fields.Char("Applicant's Name")
- partner_phone = fields.Char("Phone", size=32)
- partner_mobile = fields.Char("Mobile", size=32)
+ partner_phone = fields.Char("Phone", size=32, compute='_compute_partner_phone_email', store=True, readonly=False)
+ partner_mobile = fields.Char("Mobile", size=32, compute='_compute_partner_phone_email', store=True, readonly=False)
type_id = fields.Many2one('hr.recruitment.degree', "Degree")
- department_id = fields.Many2one('hr.department', "Department", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
+ department_id = fields.Many2one(
+ 'hr.department', "Department", compute='_compute_department', store=True, readonly=False,
+ domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
day_open = fields.Float(compute='_compute_day', string="Days to Open", compute_sudo=True)
day_close = fields.Float(compute='_compute_day', string="Days to Close", compute_sudo=True)
delay_close = fields.Float(compute="_compute_day", string='Delay to Close', readonly=True, group_operator="avg", help="Number of days to close", store=True)
@@ -220,38 +203,41 @@ class Applicant(models.Model):
stage_ids = stages._search(search_domain, order=order, access_rights_uid=SUPERUSER_ID)
return stages.browse(stage_ids)
- @api.onchange('job_id')
- def onchange_job_id(self):
- vals = self._onchange_job_id_internal(self.job_id.id)
- self.department_id = vals['value']['department_id']
- self.user_id = vals['value']['user_id']
- self.stage_id = vals['value']['stage_id']
+ @api.depends('job_id', 'department_id')
+ def _compute_company(self):
+ for applicant in self:
+ company_id = False
+ if applicant.department_id:
+ company_id = applicant.department_id.company_id.id
+ if not company_id and applicant.job_id:
+ company_id = applicant.job_id.company_id.id
+ applicant.company_id = company_id or self.env.company.id
- def _onchange_job_id_internal(self, job_id):
- department_id = False
- user_id = False
- company_id = False
- stage_id = self.stage_id.id or self._context.get('default_stage_id')
- if job_id:
- job = self.env['hr.job'].browse(job_id)
- department_id = job.department_id.id
- user_id = job.user_id.id
- company_id = job.company_id.id
- if not stage_id:
- stage_ids = self.env['hr.recruitment.stage'].search([
- '|',
- ('job_ids', '=', False),
- ('job_ids', '=', job.id),
- ('fold', '=', False)
- ], order='sequence asc', limit=1).ids
- stage_id = stage_ids[0] if stage_ids else False
+ @api.depends('job_id')
+ def _compute_department(self):
+ for applicant in self.filtered(lambda a: a.job_id):
+ applicant.department_id = applicant.job_id.department_id.id
+
+ @api.depends('job_id')
+ def _compute_stage(self):
+ for applicant in self:
+ if applicant.job_id:
+ if not applicant.stage_id:
+ stage_ids = self.env['hr.recruitment.stage'].search([
+ '|',
+ ('job_ids', '=', False),
+ ('job_ids', '=', applicant.job_id.id),
+ ('fold', '=', False)
+ ], order='sequence asc', limit=1).ids
+ applicant.stage_id = stage_ids[0] if stage_ids else False
+ else:
+ applicant.stage_id = False
+
+ @api.depends('job_id')
+ def _compute_user(self):
+ for applicant in self.filtered(lambda a: a.job_id):
+ applicant.user_id = applicant.job_id.user_id.id
- return {'value': {
- 'department_id': department_id,
- 'company_id': company_id,
- 'user_id': user_id,
- 'stage_id': stage_id
- }}
@api.onchange('email_from')
def onchange_email_from(self):
@@ -268,39 +254,27 @@ class Applicant(models.Model):
if self.partner_id and self.partner_mobile and not self.partner_id.mobile:
self.partner_id.mobile = self.partner_mobile
- @api.onchange('partner_id')
- def onchange_partner_id(self):
- self.partner_phone = self.partner_id.phone
- self.partner_mobile = self.partner_id.mobile
- self.email_from = self.partner_id.email
+ @api.depends('partner_id')
+ def _compute_partner_phone_email(self):
+ for applicant in self:
+ applicant.partner_phone = applicant.partner_id.phone
+ applicant.partner_mobile = applicant.partner_id.mobile
+ applicant.email_from = applicant.partner_id.email
- @api.onchange('stage_id')
- def onchange_stage_id(self):
- vals = self._onchange_stage_id_internal(self.stage_id.id)
- if vals['value'].get('date_closed'):
- self.date_closed = vals['value']['date_closed']
-
- def _onchange_stage_id_internal(self, stage_id):
- if not stage_id:
- return {'value': {}}
- stage = self.env['hr.recruitment.stage'].browse(stage_id)
- if stage.fold:
- return {'value': {'date_closed': fields.datetime.now()}}
- return {'value': {'date_closed': False}}
+ @api.depends('stage_id')
+ def _compute_date_closed(self):
+ for applicant in self:
+ if applicant.stage_id and applicant.stage_id.fold:
+ applicant.date_closed = fields.datetime.now()
+ else:
+ applicant.date_closed = False
@api.model
def create(self, vals):
if vals.get('department_id') and not self._context.get('default_department_id'):
self = self.with_context(default_department_id=vals.get('department_id'))
- if vals.get('job_id') or self._context.get('default_job_id'):
- job_id = vals.get('job_id') or self._context.get('default_job_id')
- for key, value in self._onchange_job_id_internal(job_id)['value'].items():
- if key not in vals:
- vals[key] = value
if vals.get('user_id'):
vals['date_open'] = fields.Datetime.now()
- if 'stage_id' in vals:
- vals.update(self._onchange_stage_id_internal(vals.get('stage_id'))['value'])
return super(Applicant, self).create(vals)
def write(self, vals):
@@ -310,7 +284,6 @@ class Applicant(models.Model):
# stage_id: track last stage before update
if 'stage_id' in vals:
vals['date_last_stage_update'] = fields.Datetime.now()
- vals.update(self._onchange_stage_id_internal(vals.get('stage_id'))['value'])
if 'kanban_state' not in vals:
vals['kanban_state'] = 'normal'
for applicant in self:
diff --git a/addons/hr_recruitment/views/hr_recruitment_views.xml b/addons/hr_recruitment/views/hr_recruitment_views.xml
index 3b515db7953..cb1d2888095 100644
--- a/addons/hr_recruitment/views/hr_recruitment_views.xml
+++ b/addons/hr_recruitment/views/hr_recruitment_views.xml
@@ -24,25 +24,25 @@
Applicants
hr.applicant
-
+
-
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
diff --git a/addons/hr_work_entry/models/hr_work_entry.py b/addons/hr_work_entry/models/hr_work_entry.py
index af17c110d07..dafb2c0793d 100644
--- a/addons/hr_work_entry/models/hr_work_entry.py
+++ b/addons/hr_work_entry/models/hr_work_entry.py
@@ -35,7 +35,7 @@ class HrWorkEntry(models.Model):
('_work_entry_start_before_end', 'check (date_stop > date_start)', 'Starting time should be before end time.')
]
- @api.onchange('state')
+ @api.depends('state')
def _compute_conflict(self):
for rec in self:
rec.conflict = rec.state == 'conflict'
diff --git a/addons/hr_work_entry/views/hr_work_entry_views.xml b/addons/hr_work_entry/views/hr_work_entry_views.xml
index b054c0ff029..00d647d0621 100644
--- a/addons/hr_work_entry/views/hr_work_entry_views.xml
+++ b/addons/hr_work_entry/views/hr_work_entry_views.xml
@@ -72,12 +72,12 @@
hr.work.entry.tree
hr.work.entry
-
-
-
-
+
+
+
+
-
+