diff --git a/addons/hr/models/hr_plan_activity_type.py b/addons/hr/models/hr_plan_activity_type.py
index ba569e38bb7..cab65ff80f0 100644
--- a/addons/hr/models/hr_plan_activity_type.py
+++ b/addons/hr/models/hr_plan_activity_type.py
@@ -39,24 +39,28 @@ class HrPlanActivityType(models.Model):
plan_type.summary = plan_type.activity_type_id.summary
def get_responsible_id(self, employee):
+ warning = False
if self.responsible == 'coach':
if not employee.coach_id:
- raise UserError(_('Coach of employee %s is not set.', employee.name))
+ warning = _('Coach of employee %s is not set.', employee.name)
responsible = employee.coach_id.user_id
if not responsible:
- raise UserError(_('User of coach of employee %s is not set.', employee.name))
+ warning = _('User of coach of employee %s is not set.', employee.name)
elif self.responsible == 'manager':
if not employee.parent_id:
- raise UserError(_('Manager of employee %s is not set.', employee.name))
+ warning = _('Manager of employee %s is not set.', employee.name)
responsible = employee.parent_id.user_id
if not responsible:
- raise UserError(_("The manager of %s should be linked to a user.", employee.name))
+ warning = _("The manager of %s should be linked to a user.", employee.name)
elif self.responsible == 'employee':
responsible = employee.user_id
if not responsible:
- raise UserError(_('The employee %s should be linked to a user.', employee.name))
+ warning = _('The employee %s should be linked to a user.', employee.name)
elif self.responsible == 'other':
responsible = self.responsible_id
if not responsible:
- raise UserError(_('No specific user given on activity %s.', self.activity_type_id.name))
- return responsible
+ warning = _('No specific user given on activity %s.', self.activity_type_id.name)
+ return {
+ 'responsible': responsible,
+ 'warning': warning,
+ }
diff --git a/addons/hr/static/src/js/hr_employee.js b/addons/hr/static/src/js/hr_employee.js
index f22bbe4bad2..0edc4929574 100644
--- a/addons/hr/static/src/js/hr_employee.js
+++ b/addons/hr/static/src/js/hr_employee.js
@@ -108,8 +108,28 @@ odoo.define('hr.employee_chat', function (require) {
}
}
return actionMenuItems;
- }
+ },
+
+ /**
+ * When we run Launch Plan list action, in case if we close the
+ * wizzard, the originally selected employees stay selected.
+ *
+ * @override
+ */
+ async _executeButtonAction(actionData, recordData) {
+ const prom = new Promise((resolve, reject) => {
+ this.trigger_up('execute_action', {
+ action_data: actionData,
+ env: recordData,
+ on_closed: () => this.isDestroyed() || actionData.context['action_plan'] ? Promise.resolve() : this.reload(),
+ on_success: resolve,
+ on_fail: () => this.update({}, { keepSelection: true, reload: false }).then(reject).guardedCatch(reject)
+ });
+ });
+ return this.alive(prom);
+ },
});
+
const EmployeeListView = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
diff --git a/addons/hr/views/hr_employee_views.xml b/addons/hr/views/hr_employee_views.xml
index 15ed05a2083..cd9b4056e95 100644
--- a/addons/hr/views/hr_employee_views.xml
+++ b/addons/hr/views/hr_employee_views.xml
@@ -229,6 +229,9 @@
hr.employee
+
diff --git a/addons/hr/wizard/hr_plan_wizard.py b/addons/hr/wizard/hr_plan_wizard.py
index 68e21c9eaa5..ca35bbc1fad 100644
--- a/addons/hr/wizard/hr_plan_wizard.py
+++ b/addons/hr/wizard/hr_plan_wizard.py
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import fields, models, _
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
class HrPlanWizard(models.TransientModel):
@@ -9,41 +10,97 @@ class HrPlanWizard(models.TransientModel):
_description = 'Plan Wizard'
def _default_plan_id(self):
- employee = self.env['hr.employee'].browse(self.env.context.get('active_id'))
+ # We know that all employees belong to the same company
+ employee = self.env['hr.employee'].browse(self.env.context.get('active_ids')[0] if self.env.context.get('active_ids') else [])
return self.env['hr.plan'].search([('company_id', '=', employee.company_id.id)], limit=1)
plan_id = fields.Many2one('hr.plan', default=lambda self: self._default_plan_id(), domain="[('company_id', '=', company_id)]")
- employee_id = fields.Many2one(
- 'hr.employee', string='Employee', required=True,
- default=lambda self: self.env.context.get('active_id', None),
+ employee_ids = fields.Many2many(
+ 'hr.employee', 'hr_employee_hr_plan_wizard_rel', 'employee_id', 'plan_wizard_id', string='Employee', required=True,
+ default=lambda self: self.env.context.get('active_ids', []),
)
- company_id = fields.Many2one(related='employee_id.company_id')
+ company_id = fields.Many2one('res.company', 'Company', compute='_compute_company_id', required=True)
+ warning = fields.Html(compute='_compute_warning')
+
+ @api.constrains('employee_ids')
+ def _check_employee_companies(self):
+ for wizard in self:
+ if len(wizard.employee_ids.mapped('company_id')) > 1:
+ raise ValidationError(_('The employees should belong to the same company.'))
+
+ @api.depends('employee_ids')
+ def _compute_company_id(self):
+ for wizard in self:
+ wizard.company_id = wizard.employee_ids[0].company_id
+
+ def _get_warnings(self):
+ self.ensure_one()
+ warnings = set()
+ for employee in self.employee_ids:
+ for activity_type in self.plan_id.plan_activity_type_ids:
+ warning = activity_type.get_responsible_id(employee)['warning']
+ if warning:
+ warnings.add(warning)
+ return warnings
+
+ @api.depends('employee_ids', 'plan_id')
+ def _compute_warning(self):
+ for wizard in self:
+ warnings = wizard._get_warnings()
+
+ if warnings:
+ warning_display = _('The plan %s cannot be launched:
', wizard.plan_id.name)
+ for warning in warnings:
+ warning_display += '- %s
' % warning
+ warning_display += '
'
+ else:
+ warning_display = False
+ wizard.warning = warning_display
def _get_activities_to_schedule(self):
return self.plan_id.plan_activity_type_ids
def action_launch(self):
- for activity_type in self._get_activities_to_schedule():
- responsible = activity_type.get_responsible_id(self.employee_id)
+ self.ensure_one()
+ for employee in self.employee_ids:
+ body = _('The plan %s has been started', self.plan_id.name)
+ activities = set()
+ for activity_type in self._get_activities_to_schedule():
+ responsible = activity_type.get_responsible_id(employee)['responsible']
+ if self.env['hr.employee'].with_user(responsible).check_access_rights('read', raise_exception=False):
+ date_deadline = self.env['mail.activity']._calculate_date_deadline(activity_type.activity_type_id)
+ employee.activity_schedule(
+ activity_type_id=activity_type.activity_type_id.id,
+ summary=activity_type.summary,
+ note=activity_type.note,
+ user_id=responsible.id,
+ date_deadline=date_deadline
+ )
+ activity = _('%(activity)s, assigned to %(name)s, due on the %(deadline)s', activity=activity_type.summary, name=responsible.name, deadline=date_deadline)
+ activities.add(activity)
- if self.env['hr.employee'].with_user(responsible).check_access_rights('read', raise_exception=False):
- date_deadline = self.env['mail.activity']._calculate_date_deadline(activity_type.activity_type_id)
- self.employee_id.activity_schedule(
- activity_type_id=activity_type.activity_type_id.id,
- summary=activity_type.summary,
- note=activity_type.note,
- user_id=responsible.id,
- date_deadline=date_deadline
- )
+ if activities:
+ body += ''
+ for activity in activities:
+ body += '- %s
' % activity
+ body += '
'
+ employee.message_post(body=body)
- for plan in self:
- plan.employee_id.message_post(body=_('The plan %s has been started', plan.plan_id.name))
+ if len(self.employee_ids) == 1:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'hr.employee',
+ 'res_id': self.employee_ids.id,
+ 'name': self.employee_ids.display_name,
+ 'view_mode': 'form',
+ 'views': [(False, "form")],
+ }
return {
'type': 'ir.actions.act_window',
'res_model': 'hr.employee',
- 'res_id': self.employee_id.id,
- 'name': self.employee_id.display_name,
- 'view_mode': 'form',
- 'views': [(False, "form")],
+ 'name': _('Launch Plans'),
+ 'view_mode': 'tree,form',
+ 'target': 'current',
+ 'domain': [('id', 'in', self.employee_ids.ids)],
}
diff --git a/addons/hr/wizard/hr_plan_wizard_views.xml b/addons/hr/wizard/hr_plan_wizard_views.xml
index d9da9ced4ec..b9d9690ad69 100644
--- a/addons/hr/wizard/hr_plan_wizard_views.xml
+++ b/addons/hr/wizard/hr_plan_wizard_views.xml
@@ -9,12 +9,16 @@
-
+
+
+
+