Skip to content

Commit

Permalink
[IMP] hr: add onboarding/offboarding activity plannings
Browse files Browse the repository at this point in the history
Purpose
=======

Give the possibility to elaborate plans through Odoo. For instance, in HR,
you could create an onboarding plan when a employee is created. Someone manages
laptop and other equipment, someone check hr stuff, ... This feature is generic
but in a first time we will apply it only on the hr module.

Ease HR process in a company by creating plans: a plan is an assembly of Next
Activities that will be launched together whenever you need it.

Example of plan for an employee onboarding:

Activity: Prepare materials
Responsible: Alain
Deadline: At the contract signature

Activity: Manage Cars
Responsible: Cécile
Deadline: at the contract signature (both signature)

Activity: Plan Training
Responsible: Caroline
Deadline: After signature

Activity: Training
Responsible: Employee
Deadline: 1 week after the employement date

Specifications
==============

On HR Configuration: Add a menu "Activity Plans"

Activity plan object:
 - Name
 - Model (debug mode) (hr by default)
 - Activity Template o2m
    - Activity Type (only the one related to hr)
    - Deadline (come from Activity Type)
    - Responsible \/
        0  Coach
        0  Manager
        0  Other
        [Responsible_name] \/  (coach, manager or manually set if other)

Add datas, 2 plans:

Onboarding
    - Name: Onboarding
    - Plan lines:
        Activity: Setup IT Materials
        Responsible: [a user] (manager)
        Deadline: At the contract signature

        Activity: Plan Training
        Responsible: [manager]
        Deadline: After signature

        Activity: Training
        Responsible: [Employee]
        Deadline: 1 week after the employement date

Offboarding
    - Name: Onboarding
    - Plan lines:
        Activity: Compute Out Delais
        Responsible: [a user] (manager)
        Deadline: today

        Activity: Take Back HR Materials
        Responsible: [manager]
        Deadline: today

        Activity: Manage Car
        Responsible: [manager]
        Deadline: today

When to trigger it ?

HR specific use case:

1/ On employee, from the employee chatter:
when you create an employee, Odoobot will log a note with the following message:
"Congratulations ! May i recommand you to setup an onboarding plan?", with a link
create a plan from it.

2/ Add a button 'launch plan' to open a wizard to select the plan

3/ When archive an employee
Open a wizard with:
    - Reason (selection)
    - Action plan (m2o not required)

Error if employee not linked to a user.

Task : 1912681

closes odoo#29151
  • Loading branch information
RomainLibert authored and tivisse committed Dec 18, 2018
1 parent e230050 commit d5fd84b
Show file tree
Hide file tree
Showing 14 changed files with 440 additions and 38 deletions.
1 change: 1 addition & 0 deletions addons/hr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import models
from . import wizard
2 changes: 2 additions & 0 deletions addons/hr/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
'data': [
'security/hr_security.xml',
'security/ir.model.access.csv',
'wizard/plan_wizard_views.xml',
'wizard/departure_wizard_views.xml',
'views/hr_views.xml',
'views/hr_templates.xml',
'views/res_config_settings_views.xml',
Expand Down
74 changes: 74 additions & 0 deletions addons/hr/data/hr_data.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,80 @@
<field name="image" eval="obj(ref('base.partner_admin')).image" model="res.partner"/>
</record>

<record id="activity_type_setup_it_materials" model="mail.activity.type">
<field name="name">Setup IT Materials</field>
<field name="res_model_id" ref="hr.model_hr_employee"/>
</record>

<record id="activity_type_setup_it_materials" model="mail.activity.type">
<field name="name">Setup IT Materials</field>
<field name="res_model_id" ref="hr.model_hr_employee"/>
</record>

<record id="activity_type_plan_training" model="mail.activity.type">
<field name="name">Plan Training</field>
<field name="res_model_id" ref="hr.model_hr_employee"/>
</record>

<record id="activity_type_training" model="mail.activity.type">
<field name="name">Training</field>
<field name="res_model_id" ref="hr.model_hr_employee"/>
<field name="delay_unit">weeks</field>
<field name="delay_count">1</field>
</record>

<record id="activity_type_compute_out_delais" model="mail.activity.type">
<field name="name">Compute Out Delais</field>
<field name="res_model_id" ref="hr.model_hr_employee"/>
</record>

<record id="activity_type_take_back_hr_materials" model="mail.activity.type">
<field name="name">Take Back HR Materials</field>
<field name="res_model_id" ref="hr.model_hr_employee"/>
</record>

<record id="onboarding_setup_it_materials" model="hr.plan.activity.type">
<field name="activity_type_id" ref="hr.activity_type_setup_it_materials"/>
<field name="responsible">manager</field>
</record>

<record id="onboarding_plan_training" model="hr.plan.activity.type">
<field name="activity_type_id" ref="hr.activity_type_plan_training"/>
<field name="responsible">manager</field>
</record>

<record id="onboarding_training" model="hr.plan.activity.type">
<field name="activity_type_id" ref="hr.activity_type_training"/>
<field name="responsible">employee</field>
</record>

<record id="offboarding_setup_compute_out_delais" model="hr.plan.activity.type">
<field name="activity_type_id" ref="hr.activity_type_compute_out_delais"/>
<field name="responsible">manager</field>
</record>

<record id="offboarding_take_back_hr_materials" model="hr.plan.activity.type">
<field name="activity_type_id" ref="hr.activity_type_take_back_hr_materials"/>
<field name="responsible">manager</field>
</record>

<record id="onboarding_plan" model='hr.plan'>
<field name="name">Onboarding</field>
<field name="plan_activity_type_ids" eval="[(6, 0, [
ref('hr.onboarding_setup_it_materials'),
ref('hr.onboarding_plan_training'),
ref('hr.onboarding_training'),
])]"/>
</record>

<record id="offboarding_plan" model='hr.plan'>
<field name="name">Offboarding</field>
<field name="plan_activity_type_ids" eval="[(6, 0, [
ref('hr.offboarding_setup_compute_out_delais'),
ref('hr.offboarding_take_back_hr_materials'),
])]"/>
</record>

<record id="mail_template_data_unknown_employee_email_address" model="mail.template">
<field name="name">HR: mailgateway unknown employee bounce</field>
<field name="model_id" ref="base.model_ir_module_module"/>
Expand Down
2 changes: 1 addition & 1 deletion addons/hr/data/hr_demo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ If you have development competencies, we can propose you specific traineeships</
<field name="name">Gilles Gravie</field>
<field name="user_id" ref="base.user_demo"/>
<field name="department_id" ref="dep_rd"/>
<field name="parent_id" ref="employee_al"/>
<field name="parent_id" ref="employee_admin"/>
<field name="job_id" ref="hr.job_developer"/>
<field name="category_ids" eval="[(6, 0, [ref('employee_category_4')])]"/>
<field name="work_location">Building 1, Second Floor</field>
Expand Down
2 changes: 2 additions & 0 deletions addons/hr/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
from . import mail_channel
from . import res_partner
from . import res_users

from . import plan
29 changes: 28 additions & 1 deletion addons/hr/models/hr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from string import digits
import base64
import logging
from werkzeug import url_encode

from odoo import api, fields, models
from odoo import tools, _
Expand Down Expand Up @@ -202,6 +203,12 @@ def _default_image(self):
color = fields.Integer('Color Index', default=0)
barcode = fields.Char(string="Badge ID", help="ID used for employee identification.", copy=False)
pin = fields.Char(string="PIN", help="PIN used to Check In/Out in Kiosk Mode (if enabled in Configuration).", copy=False)
departure_reason = fields.Selection([
('fired', 'Fired'),
('resigned', 'Resigned'),
('retired', 'Retired')
], string="Departure Reason")
departure_description = fields.Text(string="Additional Information")

_sql_constraints = [('barcode_uniq', 'unique (barcode)', "The Badge ID must be unique, this one is already assigned to another employee.")]

Expand Down Expand Up @@ -256,6 +263,8 @@ def create(self, vals):
vals.update(self._sync_user(self.env['res.users'].browse(vals['user_id'])))
tools.image_resize_images(vals)
employee = super(Employee, self).create(vals)
url = '/web#%s' % url_encode({'action': 'hr.plan_wizard_action', 'active_id': employee.id, 'active_model': 'hr.employee'})
employee._message_log(_('<b>Congratulations !</b> May I recommand you to setup an <a href="%s">onboarding plan ?</a>') % (url))
if employee.department_id:
self.env['mail.channel'].sudo().search([
('subscription_department_ids', 'in', employee.department_id.id)
Expand Down Expand Up @@ -285,7 +294,25 @@ def unlink(self):
resources = self.mapped('resource_id')
super(Employee, self).unlink()
return resources.unlink()


def toggle_active(self):
res = super(Employee, self).toggle_active()
self.filtered(lambda employee: employee.active).write({
'departure_reason': False,
'departure_description': False,
})
if len(self) == 1 and not self.active:
return {
'type': 'ir.actions.act_window',
'name': _('Register Departure'),
'res_model': 'hr.departure.wizard',
'view_type': 'form',
'view_mode': 'form',
'target': 'new',
'context': {'active_id': self.id},
}
return res

@api.multi
def generate_random_barcode(self):
for i in self: i.barcode = "".join(choice(digits) for i in range(8))
Expand Down
44 changes: 44 additions & 0 deletions addons/hr/models/plan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import fields, models, _
from odoo.exceptions import UserError


class PlanActivityType(models.Model):
_name = 'hr.plan.activity.type'
_description = 'Plan activity type'

activity_type_id = fields.Many2one('mail.activity.type', 'Activity Type',
domain=lambda self: [('res_model_id', '=', self.env['ir.model']._get('hr.employee').id)])
name = fields.Char(related='activity_type_id.name')
responsible = fields.Selection([
('coach', 'Coach'),
('manager', 'Manager'),
('employee', 'Employee'),
('other', 'Other')], default='employee', string='Responsible')
responsible_id = fields.Many2one('res.users', 'Responsible Person')

def get_responsible_id(self, employee_id):
if self.responsible == 'coach':
self.responsible_id = employee_id.coach_id.user_id
if not self.responsible_id:
raise UserError(_('No user linked to the coach of %s. Please contact an administrator.') % employee_id.name)
elif self.responsible == 'manager':
self.responsible_id = employee_id.parent_id.user_id
if not self.responsible_id:
raise UserError(_('No user linked to the manager of %s. Please contact an administrator.') % employee_id.name)
elif self.responsible == 'employee':
self.responsible_id = employee_id.user_id
if not self.responsible_id:
raise UserError(_('No user linked to the employee %s. Please contact an administrator.') % employee_id.name)
return self.responsible_id


class Plan(models.Model):
_name = 'hr.plan'
_description = 'plan'

name = fields.Char('Name', required=True)
plan_activity_type_ids = fields.Many2many('hr.plan.activity.type', string='Activities')
active = fields.Boolean(default=True)
4 changes: 4 additions & 0 deletions addons/hr/security/ir.model.access.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ access_hr_department_user,hr.department.user,model_hr_department,group_hr_user,1
access_hr_department_employee,hr.department.employee,model_hr_department,base.group_user,1,0,0,0
access_hr_job_user,hr.job user,model_hr_job,group_hr_user,1,1,1,1
access_ir_property_hr_user,ir_property hr_user,base.model_ir_property,group_hr_user,1,1,1,0
access_hr_plan_activity_type_employee,access_hr_plan_activity_type,model_hr_plan_activity_type,base.group_user,1,0,0,0
access_hr_plan_employee,access_hr_plan_employee,model_hr_plan,base.group_user,1,0,0,0
access_hr_plan_activity_type_hr_user,access_hr_plan_activity_type,model_hr_plan_activity_type,group_hr_user,1,1,1,1
access_hr_plan_hr_user,access_hr_plan_hr_user,model_hr_plan,group_hr_user,1,1,1,1
Loading

0 comments on commit d5fd84b

Please sign in to comment.