[IMP] hr: make Launch Plan multi-employee action
Purpose:
Increase usability of the Plan feature
This change implies changing 'hr.plan.wizard' m2o employee_id
field into m2m employee_ids field.
task - 2797331
closes odoo/odoo#88119
Related: odoo/enterprise#26264
Related: odoo/upgrade#3439
Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -229,6 +229,9 @@
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Employees" multi_edit="1" sample="1" js_class="hr_employee_list">
|
||||
<header>
|
||||
<button name="%(plan_wizard_action)d" type="action" string="Launch Plan" context="{'action_plan': True}"/>
|
||||
</header>
|
||||
<field name="name" readonly="1"/>
|
||||
<field name="work_phone" class="o_force_ltr" readonly="1"/>
|
||||
<field name="work_email"/>
|
||||
|
||||
@@ -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: <br><ul>', wizard.plan_id.name)
|
||||
for warning in warnings:
|
||||
warning_display += '<li>%s</li>' % warning
|
||||
warning_display += '</ul>'
|
||||
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 += '<ul>'
|
||||
for activity in activities:
|
||||
body += '<li>%s</li>' % activity
|
||||
body += '</ul>'
|
||||
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)],
|
||||
}
|
||||
|
||||
@@ -9,12 +9,16 @@
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="plan_id"/>
|
||||
<field name="employee_id" invisible="1"/>
|
||||
<field name="employee_ids" invisible="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
</group>
|
||||
<div role="alert" class="alert alert-danger mb8" attrs="{'invisible': [('warning', '=', False)]}">
|
||||
<field name="warning"/>
|
||||
</div>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_launch" string="Launch Plan" type="object" class="oe_highlight" groups="hr.group_hr_manager" data-hotkey="q"/>
|
||||
<button name="action_launch" string="Launch Plan" type="object" class="oe_highlight" attrs="{'invisible': [('warning', '!=', False)]}" groups="hr.group_hr_manager" data-hotkey="q"/>
|
||||
<button name="action_launch" string="Launch Plan" type="object" class="oe_highlight" disabled="disabled" attrs="{'invisible': [('warning', '=', False)]}" groups="hr.group_hr_manager" data-hotkey="q"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z"/>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user