[IMP] hr: add onboarding/offboarding activity plannings
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/odoo#29151
This commit is contained in:
committed by
Yannick Tivisse
parent
e230050562
commit
d5fd84b89a
@@ -2,3 +2,4 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -7,3 +7,5 @@ from . import mail_alias
|
||||
from . import mail_channel
|
||||
from . import res_partner
|
||||
from . import res_users
|
||||
|
||||
from . import plan
|
||||
|
||||
+28
-1
@@ -4,6 +4,7 @@ from random import choice
|
||||
from string import digits
|
||||
import base64
|
||||
import logging
|
||||
from werkzeug import url_encode
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import tools, _
|
||||
@@ -202,6 +203,12 @@ class Employee(models.Model):
|
||||
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.")]
|
||||
|
||||
@@ -256,6 +263,8 @@ class Employee(models.Model):
|
||||
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)
|
||||
@@ -285,7 +294,25 @@ class Employee(models.Model):
|
||||
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))
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
+148
-35
@@ -30,12 +30,121 @@
|
||||
groups="group_hr_manager"
|
||||
sequence="100"/>
|
||||
|
||||
<record id="search_view_plan" model="ir.ui.view">
|
||||
<field name="name">hr.plan.search</field>
|
||||
<field name="model">hr.plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Plan">
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_plan_tree" model="ir.ui.view">
|
||||
<field name="name">hr.plan.tree</field>
|
||||
<field name="model">hr.plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Planning">
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_plan_form" model="ir.ui.view">
|
||||
<field name="name">hr.plan.form</field>
|
||||
<field name="model">hr.plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Planning">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="toggle_active" type="object"
|
||||
class="oe_stat_button" icon="fa-archive">
|
||||
<field name="active" widget="boolean_button" options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1>
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group string="Activities">
|
||||
<field name="plan_activity_type_ids" nolabel="1">
|
||||
<tree editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="responsible"/>
|
||||
<field name="responsible_id" attrs="{'readonly': [('responsible', '!=', 'other')]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_plan_activity_form" model="ir.ui.view">
|
||||
<field name="name">hr.plan.activity.type.form</field>
|
||||
<field name="model">hr.plan.activity.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Planning">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="activity_type_id"/>
|
||||
<field name="responsible"/>
|
||||
<field name="responsible_id" attrs="{'invisible': [('responsible', '!=', 'other')]}"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="plan_listing" model="ir.actions.act_window">
|
||||
<field name="name">Planning</field>
|
||||
<field name="res_model">hr.plan</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="search_view_plan"/>
|
||||
</record>
|
||||
|
||||
<record id="plan_type_listing" model="ir.actions.act_window">
|
||||
<field name="name">Planning type</field>
|
||||
<field name="res_model">hr.plan.activity.type</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_config_plan"
|
||||
name="Activity Planning"
|
||||
parent="menu_human_resources_configuration"
|
||||
groups="group_hr_manager"
|
||||
sequence="100"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_config_plan_types"
|
||||
name="Planning Types"
|
||||
action="plan_type_listing"
|
||||
parent="menu_config_plan"
|
||||
groups="base.group_no_one"
|
||||
sequence="99"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_config_plan_plan"
|
||||
name="Plans"
|
||||
action="plan_listing"
|
||||
parent="menu_config_plan"
|
||||
groups="group_hr_manager"
|
||||
sequence="100"/>
|
||||
|
||||
<!-- Employee -->
|
||||
<record id="view_employee_form" model="ir.ui.view">
|
||||
<field name="name">hr.employee.form</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Employee">
|
||||
<header>
|
||||
<button name="%(plan_wizard_action)d" string="Launch Plan" type="action" groups="hr.group_hr_manager"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="toggle_active" type="object" groups="hr.group_hr_user"
|
||||
@@ -74,6 +183,10 @@
|
||||
<field name="resource_calendar_id" required="1"/>
|
||||
<field name="tz"/>
|
||||
</group>
|
||||
<group string="Departure" attrs="{'invisible': [('active', '=', True)]}">
|
||||
<field name="departure_reason"/>
|
||||
<field name="departure_description"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="notes" placeholder="Other Information ..." colspan="4"/>
|
||||
</page>
|
||||
@@ -200,46 +313,46 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_kanban_view_employees" model="ir.ui.view">
|
||||
<field name="name">hr.employee.kanban</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_hr_employee_kanban">
|
||||
<field name="id"/>
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="message_ids"/>
|
||||
<field name="message_needaction_counter"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record">
|
||||
<!-- Medium employee's picture -->
|
||||
<div class="o_kanban_image_fill_left d-none d-md-block" t-attf-style="background-image: url(#{kanban_image('hr.employee', 'image_medium', record.id.raw_value)})" role="img"/>
|
||||
<!-- Employee's picture optimized for mobile -->
|
||||
<div class="o_kanban_image d-md-none rounded-circle" t-attf-style="background-image: url(#{kanban_image('hr.employee', 'image_small', record.id.raw_value)})" role="img"/>
|
||||
<record id="hr_kanban_view_employees" model="ir.ui.view">
|
||||
<field name="name">hr.employee.kanban</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_hr_employee_kanban">
|
||||
<field name="id"/>
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="message_ids"/>
|
||||
<field name="message_needaction_counter"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record">
|
||||
<!-- Medium employee's picture -->
|
||||
<div class="o_kanban_image_fill_left d-none d-md-block" t-attf-style="background-image: url(#{kanban_image('hr.employee', 'image_medium', record.id.raw_value)})" role="img"/>
|
||||
<!-- Employee's picture optimized for mobile -->
|
||||
<div class="o_kanban_image d-md-none rounded-circle" t-attf-style="background-image: url(#{kanban_image('hr.employee', 'image_small', record.id.raw_value)})" role="img"/>
|
||||
|
||||
<div class="oe_kanban_details">
|
||||
<div class="o_kanban_record_top">
|
||||
<div class="o_kanban_record_headings">
|
||||
<strong class="o_kanban_record_title">
|
||||
<field name="name"/>
|
||||
</strong>
|
||||
<span t-if="record.job_id.raw_value" class="o_kanban_record_subtitle"><field name="job_id"/></span>
|
||||
<div class="oe_kanban_details">
|
||||
<div class="o_kanban_record_top">
|
||||
<div class="o_kanban_record_headings">
|
||||
<strong class="o_kanban_record_title">
|
||||
<field name="name"/>
|
||||
</strong>
|
||||
<span t-if="record.job_id.raw_value" class="o_kanban_record_subtitle"><field name="job_id"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<field name="category_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
|
||||
<ul>
|
||||
<li id="last_login"/>
|
||||
<li t-if="record.work_location.raw_value"><field name="work_location"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
<field name="category_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
|
||||
<ul>
|
||||
<li id="last_login"/>
|
||||
<li t-if="record.work_location.raw_value"><field name="work_location"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="open_view_employee_tree" model="ir.actions.act_window">
|
||||
<field name="name">Employees Structure</field>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import plan_wizard
|
||||
from . import departure_wizard
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- 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 HrDepartureWizard(models.TransientModel):
|
||||
_name = 'hr.departure.wizard'
|
||||
_description = 'Departure Wizard'
|
||||
|
||||
departure_reason = fields.Selection([
|
||||
('fired', 'Fired'),
|
||||
('resigned', 'Resigned'),
|
||||
('retired', 'Retired')
|
||||
], string="Departure Reason", default="fired")
|
||||
departure_description = fields.Text(string="Additional Information")
|
||||
plan_id = fields.Many2one('hr.plan', default=lambda self: self.env['hr.plan'].search([], limit=1))
|
||||
|
||||
def action_register_departure(self):
|
||||
active_id = self.env.context.get('active_id')
|
||||
|
||||
employee = self.env['hr.employee'].browse(active_id)
|
||||
employee.departure_reason = self.departure_reason
|
||||
employee.departure_description = self.departure_description
|
||||
|
||||
for activity_type in self.plan_id.plan_activity_type_ids:
|
||||
self.env['mail.activity'].create({
|
||||
'res_id': employee.id,
|
||||
'res_model_id': self.env['ir.model']._get('hr.employee').id,
|
||||
'activity_type_id': activity_type.activity_type_id.id,
|
||||
'user_id': activity_type.get_responsible_id(employee).id,
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="hr_departure_wizard_view_form" model="ir.ui.view">
|
||||
<field name="name">hr.departure.wizard.view.form</field>
|
||||
<field name="model">hr.departure.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="plan_id"/>
|
||||
<field name="departure_reason"/>
|
||||
<field name="departure_description"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_register_departure" string="Save" type="object" class="oe_highlight"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_departure_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Register Departure</field>
|
||||
<field name="res_model">hr.departure.wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,35 @@
|
||||
# -*- 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 HrPlanWizard(models.TransientModel):
|
||||
_name = 'hr.plan.wizard'
|
||||
_description = 'Plan Wizard'
|
||||
|
||||
plan_id = fields.Many2one('hr.plan', default=lambda self: self.env['hr.plan'].search([], limit=1))
|
||||
|
||||
def launch(self):
|
||||
active_id = self.env.context.get('active_id')
|
||||
|
||||
rec = self.env['hr.employee'].browse(active_id)
|
||||
|
||||
for activity_type in self.plan_id.plan_activity_type_ids:
|
||||
self.env['mail.activity'].create({
|
||||
'res_id': rec.id,
|
||||
'res_model_id': self.env['ir.model']._get('hr.employee').id,
|
||||
'activity_type_id': activity_type.activity_type_id.id,
|
||||
'user_id': activity_type.get_responsible_id(rec).id,
|
||||
})
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'hr.employee',
|
||||
'res_id': active_id,
|
||||
'name': rec.display_name,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'views': [(False, "form")],
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="plan_wizard" model="ir.ui.view">
|
||||
<field name="name">plan wizard</field>
|
||||
<field name="model">hr.plan.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="plan_id"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="launch" string="Launch Plan" type="object" class="oe_highlight" groups="hr.group_hr_manager"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="plan_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Launch Plan</field>
|
||||
<field name="res_model">hr.plan.wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user