diff options
| author | RomainLibert <rli@odoo.com> | 2018-11-29 14:52:26 +0000 |
|---|---|---|
| committer | Yannick Tivisse <yti@odoo.com> | 2018-12-18 11:20:54 +0000 |
| commit | d5fd84b89a51ef41ca0aa13cf7acc94e684d40ce (patch) | |
| tree | 2753ec37157e97767212b2faca1b2c41b6d24f30 | |
| parent | e230050562e1adc67a09590cf55690ac85a9f0da (diff) | |
[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
| -rw-r--r-- | addons/hr/__init__.py | 1 | ||||
| -rw-r--r-- | addons/hr/__manifest__.py | 2 | ||||
| -rw-r--r-- | addons/hr/data/hr_data.xml | 74 | ||||
| -rw-r--r-- | addons/hr/data/hr_demo.xml | 2 | ||||
| -rw-r--r-- | addons/hr/models/__init__.py | 2 | ||||
| -rw-r--r-- | addons/hr/models/hr.py | 29 | ||||
| -rw-r--r-- | addons/hr/models/plan.py | 44 | ||||
| -rw-r--r-- | addons/hr/security/ir.model.access.csv | 4 | ||||
| -rw-r--r-- | addons/hr/views/hr_views.xml | 185 | ||||
| -rw-r--r-- | addons/hr/wizard/__init__.py | 5 | ||||
| -rw-r--r-- | addons/hr/wizard/departure_wizard.py | 33 | ||||
| -rw-r--r-- | addons/hr/wizard/departure_wizard_views.xml | 32 | ||||
| -rw-r--r-- | addons/hr/wizard/plan_wizard.py | 35 | ||||
| -rw-r--r-- | addons/hr/wizard/plan_wizard_views.xml | 30 |
14 files changed, 440 insertions, 38 deletions
diff --git a/addons/hr/__init__.py b/addons/hr/__init__.py index dc5e6b693d1..2ae6446f9dc 100644 --- a/addons/hr/__init__.py +++ b/addons/hr/__init__.py @@ -2,3 +2,4 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import models +from . import wizard diff --git a/addons/hr/__manifest__.py b/addons/hr/__manifest__.py index d77cb860431..028e8fa4712 100644 --- a/addons/hr/__manifest__.py +++ b/addons/hr/__manifest__.py @@ -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', diff --git a/addons/hr/data/hr_data.xml b/addons/hr/data/hr_data.xml index 53fac18b8c6..7436e422be6 100644 --- a/addons/hr/data/hr_data.xml +++ b/addons/hr/data/hr_data.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"/> diff --git a/addons/hr/data/hr_demo.xml b/addons/hr/data/hr_demo.xml index 6a57335ad97..fd6084e854a 100644 --- a/addons/hr/data/hr_demo.xml +++ b/addons/hr/data/hr_demo.xml @@ -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> diff --git a/addons/hr/models/__init__.py b/addons/hr/models/__init__.py index 6a7da3df60c..6f85baf065b 100644 --- a/addons/hr/models/__init__.py +++ b/addons/hr/models/__init__.py @@ -7,3 +7,5 @@ from . import mail_alias from . import mail_channel from . import res_partner from . import res_users + +from . import plan diff --git a/addons/hr/models/hr.py b/addons/hr/models/hr.py index 353920a9695..b2d5dc6445b 100644 --- a/addons/hr/models/hr.py +++ b/addons/hr/models/hr.py @@ -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)) diff --git a/addons/hr/models/plan.py b/addons/hr/models/plan.py new file mode 100644 index 00000000000..fee13675130 --- /dev/null +++ b/addons/hr/models/plan.py @@ -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) diff --git a/addons/hr/security/ir.model.access.csv b/addons/hr/security/ir.model.access.csv index 74e19969a2a..345374b31fe 100644 --- a/addons/hr/security/ir.model.access.csv +++ b/addons/hr/security/ir.model.access.csv @@ -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
diff --git a/addons/hr/views/hr_views.xml b/addons/hr/views/hr_views.xml index ca5eecab771..9bf5f22c7b8 100644 --- a/addons/hr/views/hr_views.xml +++ b/addons/hr/views/hr_views.xml @@ -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"/> - - <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> + <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> </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> diff --git a/addons/hr/wizard/__init__.py b/addons/hr/wizard/__init__.py new file mode 100644 index 00000000000..d2c87d24a36 --- /dev/null +++ b/addons/hr/wizard/__init__.py @@ -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 diff --git a/addons/hr/wizard/departure_wizard.py b/addons/hr/wizard/departure_wizard.py new file mode 100644 index 00000000000..9efa96351c3 --- /dev/null +++ b/addons/hr/wizard/departure_wizard.py @@ -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, + }) diff --git a/addons/hr/wizard/departure_wizard_views.xml b/addons/hr/wizard/departure_wizard_views.xml new file mode 100644 index 00000000000..4e0ca36abfe --- /dev/null +++ b/addons/hr/wizard/departure_wizard_views.xml @@ -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> diff --git a/addons/hr/wizard/plan_wizard.py b/addons/hr/wizard/plan_wizard.py new file mode 100644 index 00000000000..b08428829ee --- /dev/null +++ b/addons/hr/wizard/plan_wizard.py @@ -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")], + } diff --git a/addons/hr/wizard/plan_wizard_views.xml b/addons/hr/wizard/plan_wizard_views.xml new file mode 100644 index 00000000000..b6829e17ea3 --- /dev/null +++ b/addons/hr/wizard/plan_wizard_views.xml @@ -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> |
