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