summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjbm-odoo <jbm@odoo.com>2019-10-10 09:54:11 +0000
committerYannick Tivisse <yti@odoo.com>2019-11-06 11:55:34 +0000
commitb2a2d0a73055cb3a7cc2fb823d399407019fac9f (patch)
tree13aaa744321ad70178676e9b9d124bc3ce6259ce
parent90fa3e3c60e9b96e8d9ba071ae655a576d949a96 (diff)
[IMP] hr_recruitment: Add refuse reason and a wizard when archiving
Purpose ======= Like in crm, having a refusal reason to get some metrics on recruitment + recruitement dashboard id=2003841 closes odoo/odoo#38467 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
-rw-r--r--addons/hr_recruitment/__init__.py1
-rw-r--r--addons/hr_recruitment/__manifest__.py1
-rw-r--r--addons/hr_recruitment/data/hr_recruitment_data.xml11
-rw-r--r--addons/hr_recruitment/data/hr_recruitment_demo.xml5
-rw-r--r--addons/hr_recruitment/models/hr_recruitment.py42
-rw-r--r--addons/hr_recruitment/security/ir.model.access.csv1
-rw-r--r--addons/hr_recruitment/views/hr_recruitment_views.xml55
-rw-r--r--addons/hr_recruitment/wizard/__init__.py4
-rw-r--r--addons/hr_recruitment/wizard/applicant_refuse_reason.py14
-rw-r--r--addons/hr_recruitment/wizard/applicant_refuse_reason_views.xml28
10 files changed, 157 insertions, 5 deletions
diff --git a/addons/hr_recruitment/__init__.py b/addons/hr_recruitment/__init__.py
index 8134f974fbf..52497701d2b 100644
--- a/addons/hr_recruitment/__init__.py
+++ b/addons/hr_recruitment/__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_recruitment/__manifest__.py b/addons/hr_recruitment/__manifest__.py
index d1e5abc2fd8..73f6719ff1b 100644
--- a/addons/hr_recruitment/__manifest__.py
+++ b/addons/hr_recruitment/__manifest__.py
@@ -31,6 +31,7 @@
'views/hr_job_views.xml',
'views/mail_activity_views.xml',
'views/digest_views.xml',
+ 'wizard/applicant_refuse_reason_views.xml',
],
'demo': [
'data/hr_recruitment_demo.xml',
diff --git a/addons/hr_recruitment/data/hr_recruitment_data.xml b/addons/hr_recruitment/data/hr_recruitment_data.xml
index 66f75fe5fc3..1bfcfc3cd11 100644
--- a/addons/hr_recruitment/data/hr_recruitment_data.xml
+++ b/addons/hr_recruitment/data/hr_recruitment_data.xml
@@ -382,5 +382,16 @@
<field name="fold" eval="True"/>
</record>
+ <!-- applicant refuse reason -->
+ <record id="refuse_reason_1" model="hr.applicant.refuse.reason">
+ <field name="name">Doesn't fit the job requirements</field>
+ </record>
+ <record id="refuse_reason_2" model="hr.applicant.refuse.reason">
+ <field name="name">The applicant is not interested anymore</field>
+ </record>
+ <record id="refuse_reason_3" model="hr.applicant.refuse.reason">
+ <field name="name">The applicant gets a better offer</field>
+ </record>
+
</data>
</odoo>
diff --git a/addons/hr_recruitment/data/hr_recruitment_demo.xml b/addons/hr_recruitment/data/hr_recruitment_demo.xml
index c31f1317f0f..193cfe6b3f4 100644
--- a/addons/hr_recruitment/data/hr_recruitment_demo.xml
+++ b/addons/hr_recruitment/data/hr_recruitment_demo.xml
@@ -44,6 +44,7 @@
<field name="name">Sales Manager</field>
<field name="job_id" ref="hr.job_marketing"/>
<field name="department_id" ref="hr.dep_sales"/>
+ <field name="medium_id" ref="utm.utm_medium_direct"/>
<field name="type_id" ref="degree_graduate"/>
<field name="categ_ids" eval="[(6,0,[ref('tag_applicant_sales')])]"/>
<field name="user_id" ref="base.user_demo"/>
@@ -68,6 +69,7 @@
<field name="name">Developer PHP</field>
<field name="job_id" ref="hr.job_developer"/>
<field name="department_id" ref="hr.dep_rd"/>
+ <field name="medium_id" ref="utm.utm_medium_email"/>
<field name="type_id" ref="degree_graduate"/>
<field name="categ_ids" eval="[(6,0,[ref('tag_applicant_it')])]"/>
<field name="user_id" ref="base.user_admin"/>
@@ -92,6 +94,7 @@
<field name="name">Developer Python</field>
<field name="job_id" ref="hr.job_developer"/>
<field name="department_id" ref="hr.dep_rd"/>
+ <field name="medium_id" ref="utm.utm_medium_email"/>
<field name="type_id" ref="degree_graduate"/>
<field name="categ_ids" eval="[(6,0,[ref('tag_applicant_it')])]"/>
<field name="user_id" ref="base.user_admin"/>
@@ -160,6 +163,7 @@
</record>
<record id="hr_case_yrsexperienceinphp0" model="hr.applicant">
<field name="name">Marketing Job</field>
+ <field eval="(datetime.now()+relativedelta(months=-2)).strftime('%Y-%m-03 01:00:00')" name="create_date"/>
<field name="job_id" ref="hr.job_marketing"/>
<field name="department_id" ref="hr.dep_sales"/>
<field name="type_id" ref="degree_graduate"/>
@@ -170,6 +174,7 @@
</record>
<record id="hr_case_marketingjob0" model="hr.applicant">
<field name="name">More than 5 yrs Experience in PHP</field>
+ <field eval="(datetime.now()+relativedelta(months=-1)).strftime('%Y-%m-08 01:00:00')" name="create_date"/>
<field name="job_id" ref="hr.job_developer"/>
<field name="department_id" ref="hr.dep_rd"/>
<field name="type_id" ref="degree_licenced"/>
diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py
index e7b8595092e..f0ebe71a7f5 100644
--- a/addons/hr_recruitment/models/hr_recruitment.py
+++ b/addons/hr_recruitment/models/hr_recruitment.py
@@ -165,6 +165,7 @@ class Applicant(models.Model):
legend_normal = fields.Char(related='stage_id.legend_normal', string='Kanban Ongoing', readonly=False)
application_count = fields.Integer(compute='_compute_application_count', help='Applications with the same email')
meeting_count = fields.Integer(compute='_compute_meeting_count', help='Meeting Count')
+ refuse_reason_id = fields.Many2one('hr.applicant.refuse.reason', string='Refuse Reason', tracking=True)
@api.depends('date_open', 'date_closed')
def _compute_day(self):
@@ -488,12 +489,39 @@ class Applicant(models.Model):
return dict_act_window
def archive_applicant(self):
- self.write({'active': False})
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Refuse Reason'),
+ 'res_model': 'applicant.get.refuse.reason',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {'default_applicant_ids': self.ids, 'active_test': False},
+ 'views': [[False, 'form']]
+ }
def reset_applicant(self):
""" Reinsert the applicant into the recruitment pipe in the first stage"""
- default_stage_id = self._default_stage_id()
- self.write({'active': True, 'stage_id': default_stage_id})
+ default_stage = dict()
+ for job_id in self.mapped('job_id'):
+ default_stage[job_id.id] = self.env['hr.recruitment.stage'].search(
+ ['|',
+ ('job_ids', '=', False),
+ ('job_ids', '=', job_id.id),
+ ('fold', '=', False)
+ ], order='sequence asc', limit=1).id
+ for applicant in self:
+ applicant.write(
+ {'stage_id': default_stage[applicant.job_id.id], 'refuse_reason_id': False})
+
+ def toggle_active(self):
+ res = super(Applicant, self).toggle_active()
+ applicant_active = self.filtered(lambda applicant: applicant.active)
+ if applicant_active:
+ applicant_active.reset_applicant()
+ applicant_inactive = self.filtered(lambda applicant: not applicant.active)
+ if applicant_inactive:
+ return applicant_inactive.archive_applicant()
+ return res
class ApplicantCategory(models.Model):
@@ -506,3 +534,11 @@ class ApplicantCategory(models.Model):
_sql_constraints = [
('name_uniq', 'unique (name)', "Tag name already exists !"),
]
+
+
+class ApplicantRefuseReason(models.Model):
+ _name = "hr.applicant.refuse.reason"
+ _description = 'Refuse Reason of Applicant'
+
+ name = fields.Char('Description', required=True, translate=True)
+ active = fields.Boolean('Active', default=True)
diff --git a/addons/hr_recruitment/security/ir.model.access.csv b/addons/hr_recruitment/security/ir.model.access.csv
index a30b91b9667..c33c641e7b7 100644
--- a/addons/hr_recruitment/security/ir.model.access.csv
+++ b/addons/hr_recruitment/security/ir.model.access.csv
@@ -3,6 +3,7 @@ access_hr_applicant_user,hr.applicant.user,model_hr_applicant,group_hr_recruitme
access_hr_recruitment_stage_user,hr.recruitment.stage.user,model_hr_recruitment_stage,group_hr_recruitment_user,1,0,0,0
access_hr_recruitment_stage_manager,hr.recruitment.stage.manager,model_hr_recruitment_stage,group_hr_recruitment_user,1,1,1,1
access_hr_recruitment_degree,hr.recruitment.degree,model_hr_recruitment_degree,group_hr_recruitment_user,1,1,1,1
+access_hr_recruitment_refuse_reason,hr.applicant.refuse.reason,model_hr_applicant_refuse_reason,group_hr_recruitment_user,1,1,1,1
access_res_partner_hr_user,res.partner.user,base.model_res_partner,group_hr_recruitment_user,1,1,1,1
access_calendar_event_hruser,calendar.event.hruser,calendar.model_calendar_event,group_hr_recruitment_user,1,1,1,1
access_hr_recruitment_source_hr_officer,hr.recruitment.source,model_hr_recruitment_source,group_hr_recruitment_user,1,1,1,1
diff --git a/addons/hr_recruitment/views/hr_recruitment_views.xml b/addons/hr_recruitment/views/hr_recruitment_views.xml
index 6d47e50c0e9..3b515db7953 100644
--- a/addons/hr_recruitment/views/hr_recruitment_views.xml
+++ b/addons/hr_recruitment/views/hr_recruitment_views.xml
@@ -71,8 +71,8 @@
<header>
<button string="Create Employee" name="create_employee_from_applicant" type="object"
class="oe_highlight" attrs="{'invisible': ['|',('emp_id', '!=', False),('active', '=', False)]}" confirm="Are you sure?"/>
- <button string="Refuse" name="archive_applicant" type="object" attrs="{'invisible': [('active', '=', False)]}"/>
- <button string="Restore" name="reset_applicant" type="object" attrs="{'invisible': [('active', '=', True)]}"/>
+ <button string="Refuse" name="toggle_active" type="object" attrs="{'invisible': [('active', '=', False)]}"/>
+ <button string="Restore" name="toggle_active" type="object" attrs="{'invisible': [('active', '=', True)]}"/>
<field name="stage_id" widget="statusbar" options="{'clickable': '1', 'fold_field': 'fold'}" attrs="{'invisible': [('active', '=', False),('emp_id', '=', False)]}"/>
</header>
<sheet>
@@ -108,6 +108,7 @@
<group>
<group>
<field name="partner_id" invisible="1" />
+ <field name="refuse_reason_id" attrs="{'invisible': [('active', '=', True)]}"/>
<field name="email_from" widget="email"/>
<field name="email_cc" groups="base.group_no_one"/>
<field name="partner_phone" widget="phone"/>
@@ -189,6 +190,7 @@
<field name="user_id"/>
<field name="stage_id" domain="[]"/>
<field name="categ_ids"/>
+ <field name="refuse_reason_id"/>
<field name="attachment_ids" filter_domain="[('attachment_ids.index_content', 'ilike', self)]" string="Attachments"/>
<filter string="My Applications" name="my_applications" domain="[('user_id', '=', uid)]"/>
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
@@ -213,6 +215,7 @@
<filter string="Job" name="job" domain="[]" context="{'group_by': 'job_id'}"/>
<filter string="Degree" name="degree" domain="[]" context="{'group_by': 'type_id'}"/>
<filter string="Stage" name="stage" domain="[]" context="{'group_by': 'stage_id'}"/>
+ <filter string="Refuse Reason" name="refuse_reason_id" domain="[]" context="{'group_by': 'refuse_reason_id'}"/>
<filter string="Creation Date" name="creation_date" context="{'group_by': 'create_date'}"/>
<filter string="Last Stage Update" name="last_stage_update" context="{'group_by': 'date_last_stage_update'}"/>
</group>
@@ -501,6 +504,46 @@
</field>
</record>
+ <!--
+ hr.applicant.refuse.reason views
+ -->
+ <record id="hr_applicant_refuse_reason_view_form" model="ir.ui.view">
+ <field name="name">Applicant refuse reason form</field>
+ <field name="model">hr.applicant.refuse.reason</field>
+ <field name="arch" type="xml">
+ <form string="Refuse Reason">
+ <sheet>
+ <widget name="web_ribbon" text="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
+ <div class="oe_title">
+ <div class="oe_edit_only">
+ <label for="name"/>
+ </div>
+ <h1>
+ <field name="name"/>
+ </h1>
+ <field name="active" invisible="1"/>
+ </div>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="hr_applicant_refuse_reason_view_tree" model="ir.ui.view">
+ <field name="name">Applicant refuse reason tree</field>
+ <field name="model">hr.applicant.refuse.reason</field>
+ <field name="arch" type="xml">
+ <tree string="Refuse Reason" editable="bottom">
+ <field name="name"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="hr_applicant_refuse_reason_action" model="ir.actions.act_window">
+ <field name="name">Refuse Reasons</field>
+ <field name="res_model">hr.applicant.refuse.reason</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
######################## JOB OPPORTUNITIES (menu) ###########################
<record model="ir.actions.act_window" id="crm_case_categ0_act_job">
<field name="name">Applications</field>
@@ -570,6 +613,13 @@
<!-- ALL JOBS REQUESTS -->
<menuitem parent="menu_hr_recruitment_configuration" id="menu_hr_job_position_config" action="action_hr_job_config" sequence="10"/>
+
+ <menuitem
+ id="menu_hr_applicant_refuse_reason"
+ action="hr_applicant_refuse_reason_action"
+ parent="menu_hr_recruitment_configuration"
+ sequence="10"/>
+
<menuitem
name="Applications"
parent="menu_hr_recruitment_root"
@@ -933,6 +983,7 @@ action = act
</record>
<menuitem name="Reporting" id="report_hr_recruitment" parent="menu_hr_recruitment_root"
sequence="99"/>
+
<menuitem name="Recruitment Analysis" id="hr_applicant_report_menu" parent="report_hr_recruitment"
sequence="50" action="hr_applicant_action_analysis"/>
<record id="action_hr_recruitment_report_filtered_department" model="ir.actions.act_window">
diff --git a/addons/hr_recruitment/wizard/__init__.py b/addons/hr_recruitment/wizard/__init__.py
new file mode 100644
index 00000000000..6a456a24112
--- /dev/null
+++ b/addons/hr_recruitment/wizard/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import applicant_refuse_reason
diff --git a/addons/hr_recruitment/wizard/applicant_refuse_reason.py b/addons/hr_recruitment/wizard/applicant_refuse_reason.py
new file mode 100644
index 00000000000..ffb0259a571
--- /dev/null
+++ b/addons/hr_recruitment/wizard/applicant_refuse_reason.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+
+from odoo import api, fields, models
+
+
+class ApplicantGetRefuseReason(models.TransientModel):
+ _name = 'applicant.get.refuse.reason'
+ _description = 'Get Refuse Reason'
+
+ refuse_reason_id = fields.Many2one('hr.applicant.refuse.reason', 'Refuse Reason')
+ applicant_ids = fields.Many2many('hr.applicant')
+
+ def action_refuse_reason_apply(self):
+ return self.applicant_ids.write({'refuse_reason_id': self.refuse_reason_id.id})
diff --git a/addons/hr_recruitment/wizard/applicant_refuse_reason_views.xml b/addons/hr_recruitment/wizard/applicant_refuse_reason_views.xml
new file mode 100644
index 00000000000..7de80d1d11f
--- /dev/null
+++ b/addons/hr_recruitment/wizard/applicant_refuse_reason_views.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<odoo>
+ <record id="applicant_get_refuse_reason_view_form" model="ir.ui.view">
+ <field name="name">applicant.get.refuse.reason.form</field>
+ <field name="model">applicant.get.refuse.reason</field>
+ <field name="arch" type="xml">
+ <form string="Refuse Reason">
+ <group class="oe_title">
+ <field name="refuse_reason_id"/>
+ <field name="applicant_ids" invisible="1"/>
+ </group>
+ <footer>
+ <button name="action_refuse_reason_apply" string="Submit" type="object" class="btn-primary"/>
+ <button string="Cancel" class="btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="applicant_get_refuse_reason_action" model="ir.actions.act_window">
+ <field name="name">Refuse Reason</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">applicant.get.refuse.reason</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="applicant_get_refuse_reason_view_form"/>
+ <field name="target">new</field>
+ </record>
+</odoo>