[IMP] hr_recruitment : Improve the UX of recruitment app

task - 3175879

closes odoo/odoo#121222

X-original-commit: 5625c013f86f3ae2617614ccde3b789bbd5ab169
Related: odoo/enterprise#40965
Signed-off-by: Kevin Baptiste <kba@odoo.com>
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
Jurgen (jugj)
2023-05-16 13:37:05 +02:00
parent 171aa0ec25
commit a9b5f5c3c1
14 changed files with 117 additions and 53 deletions
+3 -3
View File
@@ -20,15 +20,15 @@
<page string="Recruitment" name="recruitment_page">
<group>
<group name="recruitment">
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="company_id" options="{'no_create': True}" invisible="1" groups="base.group_multi_company"/>
<field name="department_id"/>
<field name="contract_type_id"/>
</group>
<group name="recruitment2">
<label for="no_of_recruitment"/>
<div class="o_row" name="recruitment_target">
<field name="no_of_recruitment" class="col-3 ps-0"/>
<span class="ps-1">new Employees</span>
<field name="no_of_recruitment" class="o_hr_narrow_field"/>
<span>new Employees</span>
</div>
</group>
</group>
+36 -5
View File
@@ -658,11 +658,6 @@ msgstr ""
msgid "Applied Job"
msgstr ""
#. module: hr_recruitment
#: model:ir.model.fields,field_description:hr_recruitment.field_hr_applicant__priority
msgid "Appreciation"
msgstr ""
#. module: hr_recruitment
#: model_terms:ir.ui.view,arch_db:hr_recruitment.view_hr_job_kanban
msgid "Archive"
@@ -1173,6 +1168,12 @@ msgstr ""
msgid "Employment Types"
msgstr ""
#. module: hr_recruitment
#: model:ir.model.fields,field_description:hr_recruitment.field_hr_applicant__priority
msgid "Evaluation"
msgstr ""
#. module: hr_recruitment
#: model:ir.model.fields.selection,name:hr_recruitment.selection__hr_applicant__priority__3
msgid "Excellent"
@@ -1853,6 +1854,14 @@ msgstr ""
#. odoo-python
#: code:addons/hr_recruitment/models/hr_applicant.py:0
#, python-format
msgid "No application found. Let's create one !"
msgstr ""
#. module: hr_recruitment
#. odoo-python
#: code:addons/hr_recruitment/models/hr_recruitment.py:0
#, python-format
msgid "No application yet"
msgstr ""
@@ -1993,6 +2002,14 @@ msgid ""
"(parent_model) and task (model))"
msgstr ""
#. module: hr_recruitment
#. odoo-python
#: code:addons/hr_recruitment/models/hr_recruitment.py:0
#, python-format
msgid "People can also apply by email to save time."
msgstr ""
#. module: hr_recruitment
#: model:ir.model.fields,help:hr_recruitment.field_hr_job__hr_responsible_id
msgid "Person responsible of validating the employee's contracts."
@@ -2735,6 +2752,14 @@ msgid ""
" of the default labels."
msgstr ""
#. module: hr_recruitment
#. odoo-python
#: code:addons/hr_recruitment/models/hr_recruitment.py:0
#, python-format
msgid ""
"You can search into attachment's content, like resumes, with the searchbar."
msgstr ""
#. module: hr_recruitment
#. odoo-python
#: code:addons/hr_recruitment/models/utm_source.py:0
@@ -2752,6 +2777,12 @@ msgstr ""
msgid "Your Job Application: {{ object.job_id.name }}"
msgstr ""
#. module: hr_recruitment
#: model_terms:ir.ui.view,arch_db:hr_recruitment.hr_applicant_view_form
#: model_terms:ir.ui.view,arch_db:hr_recruitment.quick_create_applicant_form
msgid "e.g. John Doe"
msgstr ""
#. module: hr_recruitment
#: model_terms:ir.ui.view,arch_db:hr_recruitment.hr_recruitment_source_tree
msgid "e.g. LinkedIn"
+3 -1
View File
@@ -14,7 +14,9 @@ class CalendarEvent(models.Model):
self = self.with_context(
default_res_model='hr.applicant', #res_model seems to be lost without this
default_res_model_id=self.env.ref('hr_recruitment.model_hr_applicant').id,
default_res_id=self.env.context['default_applicant_id']
default_res_id=self.env.context['default_applicant_id'],
default_partner_ids=self.env.context['default_partner_ids'],
default_name=self.env.context['default_name']
)
defaults = super(CalendarEvent, self).default_get(fields)
+21 -7
View File
@@ -30,7 +30,7 @@ class Applicant(models.Model):
name = fields.Char("Subject / Application", required=True, help="Email subject for applications sent via email", index='trigram')
active = fields.Boolean("Active", default=True, help="If the active field is set to false, it will allow you to hide the case without removing it.")
description = fields.Html("Description")
email_from = fields.Char("Email", size=128, help="Applicant email", compute='_compute_partner_phone_email',
email_from = fields.Char("Email", size=128, compute='_compute_partner_phone_email',
inverse='_inverse_partner_email', store=True, index='trigram')
probability = fields.Float("Probability")
partner_id = fields.Many2one('res.partner', "Contact", copy=False)
@@ -50,7 +50,7 @@ class Applicant(models.Model):
date_closed = fields.Datetime("Hire Date", compute='_compute_date_closed', store=True, readonly=False, tracking=True)
date_open = fields.Datetime("Assigned", readonly=True)
date_last_stage_update = fields.Datetime("Last Stage Update", index=True, default=fields.Datetime.now)
priority = fields.Selection(AVAILABLE_PRIORITIES, "Appreciation", default='0')
priority = fields.Selection(AVAILABLE_PRIORITIES, "Evaluation", default='0')
job_id = fields.Many2one('hr.job', "Applied Job", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True, index=True)
salary_proposed_extra = fields.Char("Proposed Salary Extra", help="Salary Proposed by the Organisation, extra advantages", tracking=True, groups="hr_recruitment.group_hr_recruitment_user")
salary_expected_extra = fields.Char("Expected Salary Extra", help="Salary Expected by Applicant, extra advantages", tracking=True, groups="hr_recruitment.group_hr_recruitment_user")
@@ -343,11 +343,11 @@ class Applicant(models.Model):
alias_id = False
nocontent_body = Markup("""
<p class="o_view_nocontent_empty_folder">%(help_title)s</p>
<p class="o_view_nocontent_smiling_face">%(help_title)s</p>
<p>%(para_1)s<br/>%(para_2)s</p>""") % {
'help_title': _('No application yet'),
'para_1': _('Let people apply by email to save time.'),
'para_2': _('Attachments, like resumes, get indexed automatically.'),
'help_title': _("No application found. Let's create one !"),
'para_1': _('People can also apply by email to save time.'),
'para_2': _("You can search into attachment's content, like resumes, with the searchbar."),
}
if alias_id and alias_id.alias_domain and alias_id.alias_name:
@@ -379,6 +379,19 @@ class Applicant(models.Model):
@return: Dictionary value for created Meeting view
"""
self.ensure_one()
if not self.partner_id:
if not self.partner_name:
raise UserError(_('You must define a Contact Name for this applicant.'))
self.partner_id = self.env['res.partner'].create({
'is_company': False,
'type': 'private',
'name': self.partner_name,
'email': self.email_from,
'phone': self.partner_phone,
'mobile': self.partner_mobile
})
partners = self.partner_id | self.user_id.partner_id | self.department_id.manager_id.user_id.partner_id
category = self.env.ref('hr_recruitment.categ_meet_interview')
@@ -424,7 +437,8 @@ class Applicant(models.Model):
'view_mode': 'tree,kanban,form,pivot,graph,calendar,activity',
'domain': [('id', 'in', other_applicants.ids)],
'context': {
'active_test': False
'active_test': False,
'search_default_stage': 1,
},
}
+3 -4
View File
@@ -38,7 +38,7 @@ class Job(models.Model):
hr_responsible_id = fields.Many2one(
'res.users', "HR Responsible", tracking=True,
help="Person responsible of validating the employee's contracts.")
document_ids = fields.One2many('ir.attachment', compute='_compute_document_ids', string="Documents")
document_ids = fields.One2many('ir.attachment', compute='_compute_document_ids', string="Documents", readonly=True)
documents_count = fields.Integer(compute='_compute_document_ids', string="Document Count")
alias_id = fields.Many2one(
'mail.alias', "Alias", ondelete="restrict", required=True,
@@ -260,10 +260,9 @@ class Job(models.Model):
'default_res_id': self.ids[0],
'show_partner_name': 1,
},
'view_mode': 'tree,form',
'view_mode': 'tree',
'views': [
(self.env.ref('hr_recruitment.ir_attachment_hr_recruitment_list_view').id, 'tree'),
(False, 'form'),
(self.env.ref('hr_recruitment.ir_attachment_hr_recruitment_list_view').id, 'tree')
],
'search_view_id': self.env.ref('hr_recruitment.ir_attachment_view_search_inherit_hr_recruitment').ids,
'domain': ['|',
@@ -40,6 +40,7 @@
<field name="name">Refuse Reasons</field>
<field name="res_model">hr.applicant.refuse.reason</field>
<field name="view_mode">tree,form</field>
<field name="target">new</field>
</record>
</data>
</odoo>
@@ -9,11 +9,11 @@
<field name="message_needaction" invisible="1"/>
<field name="last_stage_id" invisible="1"/>
<field name="date_last_stage_update" invisible="1"/>
<field name="partner_name" readonly="1"/>
<field name="partner_name" readonly="1" optional="show"/>
<field name="type_id" invisible="1"/>
<field name="job_id"/>
<field name="name" readonly="1"/>
<field name="stage_id"/>
<field name="job_id" optional="show"/>
<field name="name" readonly="1" optional="show"/>
<field name="stage_id" optional="show"/>
<field name="application_status" optional="show" attrs="{'invisible': [('application_status', '=', 'ongoing')]}"/>
<field name="refuse_reason_id" optional='hide'/>
<field name="priority" widget="priority" optional="show"/>
@@ -113,7 +113,7 @@
<h2 class="o_row">
<div>
<label for="partner_name" class="oe_edit_only"/>
<field name="partner_name"/>
<field name="partner_name" placeholder="e.g. John Doe"/>
</div>
</h2>
</div>
@@ -125,22 +125,23 @@
<field name="email_cc" groups="base.group_no_one"/>
<field name="partner_phone" widget="phone" options="{'enable_sms': false}"/>
<field name="partner_mobile" widget="phone"/>
<field name="type_id" placeholder="Degree"/>
<field name="linkedin_profile" widget="url"/>
<field name="type_id" placeholder="Degree"/>
</group>
<group>
<field name="categ_ids" placeholder="Tags" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
<field name="interviewer_ids" options="{'no_create': True, 'no_create_edit': True}" widget="many2many_avatar_user" />
<field name="user_id" widget="many2one_avatar_user"/>
<field name="date_closed" attrs="{'invisible': [('date_closed', '=', False)]}" />
<field name="priority" widget="priority"/>
<field name="source_id"/>
<field name="medium_id"/>
<field name="categ_ids" placeholder="Tags" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
</group>
<group string="Job">
<field name="job_id"/>
<field name="department_id"/>
<field name="company_id" groups="base.group_multi_company" options='{"no_open":True}' />
<field name="company_id" groups="base.group_multi_company" invisible="1" options='{"no_open":True}' />
</group>
<group string="Contract" name="recruitment_contract">
<label for="salary_expected"/>
@@ -227,10 +228,10 @@
<field name="attachment_ids" filter_domain="[('attachment_ids.index_content', 'ilike', self)]" string="Resume's content"/>
<filter string="My Applications" name="my_applications" domain="[('user_id', '=', uid)]"/>
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
<filter string="Reserve" name="reserve" domain="[('job_id', '=', False)]"/>
<separator/>
<filter string="Ready for Next Stage" name="done" domain="[('kanban_state', '=', 'done')]"/>
<filter string="Blocked" name="blocked" domain="[('kanban_state', '=', 'blocked')]"/>
<filter string="Reserve" name="reserve" domain="[('job_id', '=', False)]"/>
<separator/>
<filter string="Creation Date" name="filter_create" date="create_date"/>
<filter string="Last Stage Update" name="filter_date_last_stage_update" date="date_last_stage_update"/>
@@ -252,14 +253,14 @@
domain="[('stage_id.hired_stage', '=', False)]"/>
<separator/>
<group expand="0" string="Group By">
<filter string="Responsible" name="responsible" domain="[]" context="{'group_by': 'user_id'}"/>
<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="Tags" name="group_by_categ_ids" context="{'group_by':'categ_ids'}"/>
<filter string="Refuse Reason" name="refuse_reason_id" domain="[]" context="{'group_by': 'refuse_reason_id'}"/>
<filter string="Responsible" name="responsible" domain="[]" context="{'group_by': 'user_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'}"/>
<filter string="Refuse Reason" name="refuse_reason_id" domain="[]" context="{'group_by': 'refuse_reason_id'}"/>
<filter string="Degree" name="degree" domain="[]" context="{'group_by': 'type_id'}"/>
<filter string="Tags" name="group_by_categ_ids" context="{'group_by':'categ_ids'}"/>
</group>
</search>
</field>
@@ -288,7 +289,7 @@
<form>
<group>
<field name="name"/>
<field name="partner_name"/>
<field name="partner_name" placeholder="e.g. John Doe"/>
<field name="email_from"/>
<field name="job_id" options="{'no_open': True}"/>
<field name="company_id" invisible="1"/>
@@ -323,8 +324,10 @@
<progressbar field="activity_state" colors='{"planned": "success", "overdue": "danger", "today": "warning"}'/>
<templates>
<t t-name="kanban-menu">
<t t-if="widget.deletable"><a role="menuitem" type="delete" class="dropdown-item">Delete</a></t>
<a role="menuitem" name="action_makeMeeting" type="object" class="dropdown-item">Schedule Interview</a>
<a role="menuitem" name="archive_applicant" type="object" class="dropdown-item">Refuse</a>
<a role="menuitem" name="archive_applicant" type="object" class="dropdown-item">Archive</a>
<t t-if="widget.deletable"><a role="menuitem" type="delete" class="dropdown-item">Delete</a></t>
<div role="separator" class="dropdown-divider"></div>
<ul class="oe_kanban_colorpicker text-center" data-field="color"/>
</t>
@@ -407,7 +410,7 @@
<field name="res_model">hr.applicant</field>
<field name="view_mode">kanban,tree,form,graph,calendar,pivot,activity</field>
<field name="search_view_id" ref="hr_applicant_view_search_bis"/>
<field name="context">{'search_default_job_id': [active_id], 'default_job_id': active_id}</field>
<field name="context">{'search_default_job_id': [active_id], 'default_job_id': active_id, 'search_default_stage':1,'dialog_size':'medium'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No applications yet
@@ -435,7 +438,7 @@
<field name="view_mode">kanban,tree,form,pivot,graph,calendar,activity</field>
<field name="view_id" eval="False"/>
<field name="search_view_id" ref="hr_applicant_view_search_bis"/>
<field name="context">{}</field>
<field name="context">{'search_default_stage':1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No applications yet
+6 -1
View File
@@ -169,6 +169,7 @@
<field name="view_mode">form</field>
<field name="view_id" ref="hr_job_simple_form"/>
<field name="target">new</field>
<field name="context">{'dialog_size' : 'medium'}</field>
</record>
<record id="hr_job_survey" model="ir.ui.view">
@@ -194,6 +195,9 @@
</div>
</div>
</xpath>
<xpath expr="//field[@name='contract_type_id']" position="after">
<field name="company_id" groups="base.group_multi_company"/>
</xpath>
<div name="button_box" position="inside">
<button class="oe_stat_button"
icon="fa-pencil"
@@ -205,7 +209,8 @@
<button class="oe_stat_button"
icon="fa-file-text-o"
name="action_open_attachments"
type="object">
type="object"
attrs="{'invisible': [('documents_count','=',0)]}">
<field name="documents_count" widget="statinfo" string="Documents"/>
</button>
<button class="oe_stat_button" type="action"
@@ -27,7 +27,7 @@
<field name="model">ir.attachment</field>
<field name="mode">primary</field>
<field name="arch" type="xml">
<tree>
<tree create="0">
<field name="name" invisible="1"/>
<field name="res_id" invisible="1"/>
<field name="res_model" invisible="1"/>
@@ -5,17 +5,17 @@
<field name="model">applicant.get.refuse.reason</field>
<field name="arch" type="xml">
<form string="Refuse Reason">
<group col="1">
<field name="refuse_reason_id"/>
<field name="send_mail" attrs="{'invisible': [('refuse_reason_id', '=', False)]}"/>
<field name="template_id" attrs="{'invisible': [('send_mail', '=', False)], 'required': [('send_mail', '=', True)]}" />
<field name="applicant_ids" invisible="1"/>
</group>
<div class="alert alert-danger" role="alert" attrs="{'invisible': [('applicant_without_email', '=', False)]}">
<field name="applicant_without_email" class="mr4"/>
</div>
<group col="1">
<field name="refuse_reason_id" class="w-50"/>
<field name="send_mail" attrs="{'invisible': [('refuse_reason_id', '=', False)]}"/>
<field name="template_id" attrs="{'invisible': [('send_mail', '=', False)], 'required': [('send_mail', '=', True)]}" class="w-50"/>
<field name="applicant_ids" invisible="1"/>
</group>
<footer>
<button name="action_refuse_reason_apply" string="Submit" type="object" class="btn-primary" data-hotkey="q"/>
<button name="action_refuse_reason_apply" string="Refuse" type="object" class="btn-primary" data-hotkey="q"/>
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z"/>
</footer>
</form>
@@ -35,7 +35,7 @@
<xpath expr="//field[@name='email_from']" position="after">
<field name="applicant_skill_ids"/>
</xpath>
<filter name="last_stage_update" position="after">
<filter name="refuse_reason_id" position="after">
<filter string="Skills" name="groupby_skills" context="{'group_by': 'skill_ids'}"/>
</filter>
</field>
@@ -7,10 +7,13 @@
<field name="arch" type="xml">
<field name="interviewer_ids" position="after">
<label for="survey_id" groups="survey.group_survey_user"/>
<div groups="survey.group_survey_user" class="o_row">
<div groups="survey.group_survey_user">
<field name="survey_id"
context="{'default_access_mode': 'token'}"/>
<button string="Display Interview Form" name="action_test_survey" type="object" attrs="{'invisible':[('survey_id','=',False)]}" class="oe_link pb-1"/>
<div class="o_link_trackers col-6 text-end">
<a type="object" name="action_test_survey">
</a>
</div>
</div>
</field>
</field>
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
from odoo import fields, models, api
from odoo.addons.http_routing.models.ir_http import slug
from odoo.tools import mute_logger
from odoo.tools.translate import html_translate
@@ -55,6 +55,14 @@ class Job(models.Model):
for job in self:
job.published_date = job.website_published and fields.Date.today()
@api.onchange('website_published')
def _onchange_website_published(self):
if self.website_published:
self.is_published = True
else:
self.is_published = False
self.website_id = False
def _compute_website_url(self):
super(Job, self)._compute_website_url()
for job in self:
@@ -37,6 +37,7 @@
</div>
<xpath expr="//div[@name='recruitment_target']" position="after">
<field name="website_published" string="Is Published"/>
<field name="website_id" attrs="{'invisible': [('website_published', '=', False)]}" options="{'no_create': True}" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]" groups="website.group_multi_website"/>
</xpath>
</field>
</record>
@@ -46,9 +47,6 @@
<field name="model">hr.job</field>
<field name="inherit_id" ref="hr.view_hr_job_form"/>
<field name="arch" type="xml">
<group name="recruitment2" position="inside">
<field name="website_id" options="{'no_create': True}" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]" groups="website.group_multi_website"/>
</group>
<field name="description" position="attributes">
<attribute name="placeholder">You can write here a short description of your Job Description that will be displayed on the main Jobs' list page.</attribute>
</field>