[MIGR] hr_recruitment: migrate to the new API.
This commit should not contain heavy code cleaning or refactoring. The code has been translated and maybe slightly improved or simplified.
This commit is contained in:
committed by
Thibault Delavallée
parent
2ed1cf80e1
commit
a805e091c6
@@ -357,7 +357,7 @@
|
||||
</div>
|
||||
<group name="employee_data">
|
||||
<group>
|
||||
<field name="department_id" groups="hr.group_multi_departments" class="oe_inline"/>
|
||||
<field name="department_id" class="oe_inline"/>
|
||||
<field name="no_of_recruitment" class="oe_inline"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_department(models.Model):
|
||||
class HrDepartment(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
new_applicant_count = fields.Integer(
|
||||
compute='_compute_new_applicant_count', string='New Applicant')
|
||||
new_hired_employee = fields.Integer(
|
||||
compute='_compute_recruitment_stats', string='New Hired Employee')
|
||||
expected_employee = fields.Integer(
|
||||
compute='_compute_recruitment_stats', string='Expected Employee')
|
||||
|
||||
@api.multi
|
||||
def _compute_new_applicant_count(self):
|
||||
applicant_data = self.env['hr.applicant'].read_group(
|
||||
@@ -24,10 +31,3 @@ class hr_department(models.Model):
|
||||
for department in self:
|
||||
department.new_hired_employee = new_emp.get(department.id, 0)
|
||||
department.expected_employee = expected_emp.get(department.id, 0)
|
||||
|
||||
new_applicant_count = fields.Integer(
|
||||
compute='_compute_new_applicant_count', string='New Applicant')
|
||||
new_hired_employee = fields.Integer(
|
||||
compute='_compute_recruitment_stats', string='New Hired Employee')
|
||||
expected_employee = fields.Integer(
|
||||
compute='_compute_recruitment_stats', string='Expected Employee')
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_employee(osv.Model):
|
||||
class hr_employee(models.Model):
|
||||
_inherit = "hr.employee"
|
||||
|
||||
def _newly_hired_employee(self, cr, uid, ids, field_name, arg, context=None):
|
||||
data = self.pool['hr.applicant'].read_group(cr, uid,
|
||||
[('emp_id', 'in', ids), ('job_id.state', '=', 'recruit')],
|
||||
['emp_id'], ['emp_id'], context=context)
|
||||
result = dict.fromkeys(ids, False)
|
||||
for d in data:
|
||||
if d['emp_id_count'] >= 1:
|
||||
result[d['emp_id'][0]] = True
|
||||
return result
|
||||
newly_hired_employee = fields.Boolean('Newly hired employee', compute='_compute_newly_hired_employee',
|
||||
search='_search_newly_hired_employee')
|
||||
|
||||
def _search_newly_hired_employee(self, cr, uid, obj, name, args, context=None):
|
||||
applicant_ids = self.pool['hr.applicant'].search_read(cr, uid, [('job_id.state', '=', 'recruit')], ['emp_id'], context=context)
|
||||
hired_emp_ids = [applicant['emp_id'][0] for applicant in applicant_ids if applicant['emp_id']]
|
||||
return [('id', 'in', hired_emp_ids)]
|
||||
@api.multi
|
||||
def _compute_newly_hired_employee(self):
|
||||
read_group_result = self.env['hr.applicant'].read_group(
|
||||
[('emp_id', 'in', self.ids), ('job_id.state', '=', 'recruit')],
|
||||
['emp_id'], ['emp_id'])
|
||||
result = dict((data['emp_id'], data['emp_id_count'] > 0) for data in read_group_result)
|
||||
for record in self:
|
||||
record.newly_hired_employee = result.get(record.id, False)
|
||||
|
||||
_columns = {
|
||||
'newly_hired_employee': fields.function(_newly_hired_employee, fnct_search=_search_newly_hired_employee, type='boolean', string='Newly hired employees')
|
||||
}
|
||||
def _search_newly_hired_employee(self, operator, value):
|
||||
applicants = self.env['hr.applicant'].search([('job_id.state', '=', 'recruit')])
|
||||
return [('id', 'in', applicants.ids)]
|
||||
|
||||
@@ -1,102 +1,107 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_job(osv.osv):
|
||||
class Job(models.Model):
|
||||
_inherit = "hr.job"
|
||||
_name = "hr.job"
|
||||
_inherits = {'mail.alias': 'alias_id'}
|
||||
|
||||
def _track_subtype(self, cr, uid, ids, init_values, context=None):
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
if 'state' in init_values and record.state == 'open':
|
||||
return 'hr_recruitment.mt_job_new'
|
||||
return super(hr_job, self)._track_subtype(cr, uid, ids, init_values, context=context)
|
||||
@api.model
|
||||
def _default_address_id(self):
|
||||
return self.env.user.company_id.partner_id
|
||||
|
||||
def _get_attached_docs(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
attachment_obj = self.pool.get('ir.attachment')
|
||||
for job_id in ids:
|
||||
applicant_ids = self.pool.get('hr.applicant').search(cr, uid, [('job_id', '=', job_id)], context=context)
|
||||
res[job_id] = attachment_obj.search(
|
||||
cr, uid, [
|
||||
'|',
|
||||
'&', ('res_model', '=', 'hr.job'), ('res_id', '=', job_id),
|
||||
'&', ('res_model', '=', 'hr.applicant'), ('res_id', 'in', applicant_ids)
|
||||
], context=context)
|
||||
address_id = fields.Many2one(
|
||||
'res.partner', "Job Location", default=_default_address_id,
|
||||
help="Address where employees are working")
|
||||
application_ids = fields.One2many('hr.applicant', 'job_id', "Applications")
|
||||
application_count = fields.Integer(compute='_compute_application_count', string="Applications")
|
||||
manager_id = fields.Many2one(
|
||||
'hr.employee', related='department_id.manager_id', string="Department Manager",
|
||||
readonly=True, store=True)
|
||||
user_id = fields.Many2one('res.users', "Recruitment Responsible", track_visibility='onchange')
|
||||
stage_ids = fields.Many2many(
|
||||
'hr.recruitment.stage', 'job_stage_rel', 'job_id', 'stage_id',
|
||||
'Job Stages')
|
||||
document_ids = fields.One2many('ir.attachment', compute='_compute_document_ids', string="Applications")
|
||||
documents_count = fields.Integer(compute='_compute_document_ids', string="Documents")
|
||||
survey_id = fields.Many2one(
|
||||
'survey.survey', "Interview Form",
|
||||
help="Choose an interview form for this job position and you will be able to print/answer this interview from all applicants who apply for this job")
|
||||
alias_id = fields.Many2one(
|
||||
'mail.alias', "Alias", ondelete="restrict", required=True,
|
||||
help="Email alias for this job position. New emails will automatically create new applicants for this job position.")
|
||||
color = fields.Integer("Color Index")
|
||||
|
||||
def _compute_document_ids(self):
|
||||
applicants = self.mapped('application_ids')
|
||||
app_to_job = dict((applicant.id, applicant.job_id.id) for applicant in applicants)
|
||||
attachments = self.env['ir.attachment'].search([
|
||||
'|',
|
||||
'&', ('res_model', '=', 'hr.job'), ('res_id', 'in', self.ids),
|
||||
'&', ('res_model', '=', 'hr.applicant'), ('res_id', 'in', self.mapped('application_ids').ids)])
|
||||
result = dict.fromkeys(self.ids, self.env['ir.attachment'])
|
||||
for attachment in attachments:
|
||||
if attachment.res_model == 'hr.applicant':
|
||||
result[app_to_job[attachment.res_id]] |= attachment
|
||||
else:
|
||||
result[attachment.res_id] |= attachment
|
||||
|
||||
for job in self:
|
||||
job.document_ids = result[job.id]
|
||||
job.documents_count = len(job.document_ids)
|
||||
|
||||
@api.multi
|
||||
def _compute_application_count(self):
|
||||
read_group_result = self.env['hr.applicant'].read_group([('job_id', '=', self.id)], ['job_id'], ['job_id'])
|
||||
result = dict((data['job_id'], data['job_id_count']) for data in read_group_result)
|
||||
for job in self:
|
||||
job.application_count = result.get(job.id, 0)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
job = super(Job, self.with_context(alias_model_name='hr.applicant',
|
||||
mail_create_nolog=True,
|
||||
alias_parent_model_name=self._name)).create(vals)
|
||||
job.alias_id.write({'alias_parent_thread_id': job.id, "alias_defaults": {'job_id': job.id}})
|
||||
return job
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
# Cascade-delete mail aliases as well, as they should not exist without the job position.
|
||||
aliases = self.mapped('alias_id')
|
||||
res = super(Job, self).unlink()
|
||||
aliases.unlink()
|
||||
return res
|
||||
|
||||
def _count_all(self, cr, uid, ids, field_name, arg, context=None):
|
||||
Applicant = self.pool['hr.applicant']
|
||||
return {
|
||||
job_id: {
|
||||
'application_count': Applicant.search_count(cr,uid, [('job_id', '=', job_id)], context=context),
|
||||
'documents_count': len(self._get_attached_docs(cr, uid, [job_id], field_name, arg, context=context)[job_id])
|
||||
}
|
||||
for job_id in ids
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'survey_id': fields.many2one('survey.survey', 'Interview Form', help="Choose an interview form for this job position and you will be able to print/answer this interview from all applicants who apply for this job"),
|
||||
'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="restrict", required=True,
|
||||
help="Email alias for this job position. New emails will automatically "
|
||||
"create new applicants for this job position."),
|
||||
'address_id': fields.many2one('res.partner', 'Job Location', help="Address where employees are working"),
|
||||
'application_ids': fields.one2many('hr.applicant', 'job_id', 'Applications'),
|
||||
'application_count': fields.function(_count_all, type='integer', string='Applications', multi=True),
|
||||
'manager_id': fields.related('department_id', 'manager_id', type='many2one', string='Department Manager', relation='hr.employee', readonly=True, store=True),
|
||||
'stage_ids': fields.many2many('hr.recruitment.stage', 'job_stage_rel', 'job_id', 'stage_id', 'Job Stages'),
|
||||
'document_ids': fields.function(_get_attached_docs, type='one2many', relation='ir.attachment', string='Applications'),
|
||||
'documents_count': fields.function(_count_all, type='integer', string='Documents', multi=True),
|
||||
'user_id': fields.many2one('res.users', 'Recruitment Responsible', track_visibility='onchange'),
|
||||
'color': fields.integer('Color Index'),
|
||||
}
|
||||
|
||||
def _address_get(self, cr, uid, context=None):
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
return user.company_id.partner_id.id
|
||||
|
||||
_defaults = {
|
||||
'address_id': _address_get,
|
||||
}
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
"""Installation hook to create aliases for all jobs and avoid constraint errors."""
|
||||
return self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(hr_job, self)._auto_init,
|
||||
'hr.applicant', self._columns['alias_id'], 'name', alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=context)
|
||||
return self.pool.get('mail.alias').migrate_to_alias(
|
||||
cr, self._name, self._table, super(Job, self)._auto_init,
|
||||
'hr.applicant', self._columns['alias_id'], 'name',
|
||||
alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=context)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
create_context = dict(context,
|
||||
alias_model_name='hr.applicant',
|
||||
mail_create_nolog=True,
|
||||
alias_parent_model_name=self._name)
|
||||
job_id = super(hr_job, self).create(cr, uid, vals, context=create_context)
|
||||
job = self.browse(cr, uid, job_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [job.alias_id.id], {'alias_parent_thread_id': job_id, "alias_defaults": {'job_id': job_id}}, context)
|
||||
return job_id
|
||||
@api.multi
|
||||
def _track_subtype(self, init_values):
|
||||
if 'state' in init_values and self.state == 'open':
|
||||
return 'hr_recruitment.mt_job_new'
|
||||
return super(Job, self)._track_subtype(init_values)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade-delete mail aliases as well, as they should not exist without the job position.
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
alias_ids = [job.alias_id.id for job in self.browse(cr, uid, ids, context=context) if job.alias_id]
|
||||
res = super(hr_job, self).unlink(cr, uid, ids, context=context)
|
||||
mail_alias.unlink(cr, uid, alias_ids, context=context)
|
||||
return res
|
||||
@api.multi
|
||||
def action_print_survey(self):
|
||||
return self.survey_id.action_print_survey()
|
||||
|
||||
def action_print_survey(self, cr, uid, ids, context=None):
|
||||
job = self.browse(cr, uid, ids, context=context)[0]
|
||||
survey_id = job.survey_id.id
|
||||
return self.pool.get('survey.survey').action_print_survey(cr, uid, [survey_id], context=context)
|
||||
|
||||
def action_get_attachment_tree_view(self, cr, uid, ids, context=None):
|
||||
#open attachments of job and related applicantions.
|
||||
model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'action_attachment')
|
||||
action = self.pool.get(model).read(cr, uid, action_id, context=context)
|
||||
applicant_ids = self.pool.get('hr.applicant').search(cr, uid, [('job_id', 'in', ids)], context=context)
|
||||
action['context'] = {'default_res_model': self._name, 'default_res_id': ids[0]}
|
||||
action['domain'] = str(['|', '&', ('res_model', '=', 'hr.job'), ('res_id', 'in', ids), '&', ('res_model', '=', 'hr.applicant'), ('res_id', 'in', applicant_ids)])
|
||||
@api.multi
|
||||
def action_get_attachment_tree_view(self):
|
||||
action = self.env.ref('base.action_attachment').read()[0]
|
||||
action['context'] = {
|
||||
'default_res_model': self._name,
|
||||
'default_res_id': self.ids[0]
|
||||
}
|
||||
action['domain'] = '%s' % ['|', '&', ('res_model', '=', 'hr.job'), ('res_id', 'in', self.ids), '&', ('res_model', '=', 'hr.applicant'), ('res_id', 'in', self.mapped('application_ids'))]
|
||||
return action
|
||||
|
||||
def action_set_no_of_recruitment(self, cr, uid, id, value, context=None):
|
||||
return self.write(cr, uid, [id], {'no_of_recruitment': value}, context=context)
|
||||
@api.multi
|
||||
def action_set_no_of_recruitment(self, value):
|
||||
return self.write({'no_of_recruitment': value})
|
||||
|
||||
@@ -4,14 +4,10 @@
|
||||
import werkzeug
|
||||
from datetime import datetime
|
||||
|
||||
from openerp import api
|
||||
from openerp import tools
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import api, fields, models, tools
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
AVAILABLE_PRIORITIES = [
|
||||
('0', 'Normal'),
|
||||
('1', 'Good'),
|
||||
@@ -20,390 +16,438 @@ AVAILABLE_PRIORITIES = [
|
||||
]
|
||||
|
||||
|
||||
class hr_recruitment_source(osv.osv):
|
||||
""" Sources of HR Recruitment """
|
||||
class RecruitmentSource(models.Model):
|
||||
_name = "hr.recruitment.source"
|
||||
_description = "Source of Applicants"
|
||||
_inherits = {"utm.source": "source_id"}
|
||||
|
||||
def _get_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
result = {}
|
||||
imd = self.pool['ir.model.data']
|
||||
for source in self.browse(cr, uid, ids, context=context):
|
||||
if not source.alias_id.id:
|
||||
result[source.id] = ''
|
||||
else:
|
||||
result[source.id] = werkzeug.url_encode({
|
||||
'utm_campaign': imd.xmlid_to_object(cr, SUPERUSER_ID, 'hr_recruitment.utm_campaign_job').name,
|
||||
'utm_medium': imd.xmlid_to_object(cr, SUPERUSER_ID, 'utm.utm_medium_website').name,
|
||||
'utm_source': source.source_id.name
|
||||
})
|
||||
return result
|
||||
source_id = fields.Many2one('utm.source', "Source", ondelete='cascade', required=True)
|
||||
url = fields.Char(string="Url parameters", compute='_compute_url')
|
||||
email = fields.Char(related='alias_id.alias_name', string="Email", readonly=True)
|
||||
job_id = fields.Many2one('hr.job', "Job ID")
|
||||
alias_id = fields.Many2one('mail.alias', "Alias ID")
|
||||
|
||||
def create_alias(self, cr, uid, ids, context=None):
|
||||
imd = self.pool['ir.model.data']
|
||||
for source in self.browse(cr, uid, ids, context=context):
|
||||
alias_context = dict(context or {}, alias_model_name='hr.applicant', alias_parent_model_name='hr.job')
|
||||
@api.depends('source_id', 'source_id.name')
|
||||
@api.one
|
||||
def _compute_url(self):
|
||||
if not self.alias_id.id:
|
||||
self.url = ""
|
||||
else:
|
||||
self.url = werkzeug.url_encode({
|
||||
'utm_campaign': self.env.ref('hr_recruitment.utm_campaign_job').name,
|
||||
'utm_medium': self.env.ref('utm.utm_medium_website').name,
|
||||
'utm_source': self.source_id.name
|
||||
})
|
||||
|
||||
@api.multi
|
||||
def create_alias(self):
|
||||
campaign = self.env.ref('hr_recruitment.utm_campaign_job')
|
||||
medium = self.env.ref('utm.utm_medium_email')
|
||||
for source in self:
|
||||
vals = {
|
||||
'alias_parent_thread_id': source.job_id.id,
|
||||
'alias_name': "%s+%s" % (source.job_id.alias_name or source.job_id.name, source.name),
|
||||
'alias_defaults': {
|
||||
'job_id': source.job_id.id,
|
||||
'campaign_id': imd.xmlid_to_res_id(cr, SUPERUSER_ID, 'hr_recruitment.utm_campaign_job'),
|
||||
'medium_id': imd.xmlid_to_res_id(cr, SUPERUSER_ID, 'utm.utm_medium_email'),
|
||||
'campaign_id': campaign.id,
|
||||
'medium_id': medium.id,
|
||||
'source_id': source.source_id.id,
|
||||
},
|
||||
}
|
||||
new_alias_id = self.pool['mail.alias'].create(cr, uid, vals, alias_context)
|
||||
source.write({'alias_id': new_alias_id, 'name': source.source_id.name})
|
||||
return
|
||||
source.alias_id = self.with_context(alias_model_name='hr.applicant', alias_parent_model_name='hr.job').env['mail.alias'].create(vals)
|
||||
source.name = source.source_id.name
|
||||
|
||||
def _get_source(self, cr, uid, ids, context=None):
|
||||
if ids:
|
||||
return self.pool['hr.recruitment.source'].search(cr, uid, [('source_id', 'in', ids)], context=context)
|
||||
return []
|
||||
|
||||
_columns = {
|
||||
'source_id': fields.many2one('utm.source', 'Source', ondelete='cascade', required=True),
|
||||
'url': fields.function(_get_url, string='Url Parameters', type='char', store={
|
||||
'hr.recruitment.source': (lambda self, cr, uid, ids, ctx: ids, ['source_id'], 20),
|
||||
'utm.source': (_get_source, ['name'], 20),
|
||||
}),
|
||||
'email': fields.related('alias_id', 'alias_name', string='Email', readonly=True, type='char'),
|
||||
'job_id': fields.many2one('hr.job', 'Job ID'),
|
||||
'alias_id': fields.many2one('mail.alias', 'Alias ID'),
|
||||
}
|
||||
|
||||
class hr_recruitment_stage(osv.osv):
|
||||
""" Stage of HR Recruitment """
|
||||
class RecruitmentStage(models.Model):
|
||||
_name = "hr.recruitment.stage"
|
||||
_description = "Stage of Recruitment"
|
||||
_order = 'sequence'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Stage Name', required=True, translate=True),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."),
|
||||
'job_ids': fields.many2many('hr.job', 'job_stage_rel', 'stage_id', 'job_id', 'Job Stages'),
|
||||
'requirements': fields.text('Requirements', help="Enter here the internal requirements for this stage (ex: Offer sent to applicant). It will appear as a tooltip over the stage's name."),
|
||||
'template_id': fields.many2one('mail.template', 'Use template', help="If set, a message is posted on the applicant using the template when the applicant is set to the stage."),
|
||||
'fold': fields.boolean('Folded in Kanban View',
|
||||
help='This stage is folded in the kanban view when'
|
||||
'there are no records in that stage to display.'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'sequence': 1,
|
||||
'job_ids': lambda self, cr, uid, context=None: [context['default_job_id']] if context and context.get('default_job_id') else None,
|
||||
}
|
||||
name = fields.Char("Stage name", required=True, translate=True)
|
||||
sequence = fields.Integer(
|
||||
"Sequence", default=1,
|
||||
help="Gives the sequence order when displaying a list of stages.")
|
||||
job_ids = fields.Many2many(
|
||||
'hr.job', 'job_stage_rel', 'stage_id', 'job_id',
|
||||
string='Job Stages',
|
||||
default=lambda self: [(4, self._context['default_job_id'])] if self._context.get('default_job_id') else None)
|
||||
requirements = fields.Text("Requirements")
|
||||
template_id = fields.Many2one(
|
||||
'mail.template', "Use template",
|
||||
help="If set, a message is posted on the applicant using the template when the applicant is set to the stage.")
|
||||
fold = fields.Boolean(
|
||||
"Folded in Kanban View",
|
||||
help="This stage is folded in the kanban view when there are no records in that stage to display.")
|
||||
|
||||
|
||||
class hr_recruitment_degree(osv.osv):
|
||||
""" Degree of HR Recruitment """
|
||||
class RecruitmentDegree(models.Model):
|
||||
_name = "hr.recruitment.degree"
|
||||
_description = "Degree of Recruitment"
|
||||
_columns = {
|
||||
'name': fields.char('Degree', required=True, translate=True),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of degrees."),
|
||||
}
|
||||
_defaults = {
|
||||
'sequence': 1,
|
||||
}
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', 'The name of the Degree of Recruitment must be unique!')
|
||||
]
|
||||
|
||||
name = fields.Char("Degree", required=True, translate=True)
|
||||
sequence = fields.Integer("Sequence", default=1, help="Gives the sequence order when displaying a list of degrees.")
|
||||
|
||||
class hr_applicant(osv.Model):
|
||||
|
||||
class Applicant(models.Model):
|
||||
_name = "hr.applicant"
|
||||
_description = "Applicant"
|
||||
_order = "priority desc, id desc"
|
||||
_inherit = ['mail.thread', 'ir.needaction_mixin', 'utm.mixin']
|
||||
_mail_mass_mailing = _('Applicants')
|
||||
|
||||
def _get_default_stage_id(self, cr, uid, context=None):
|
||||
job_id = context and context.get('default_job_id')
|
||||
return self.stage_find(cr, uid, [], job_id, [('fold', '=', False)], context=context)
|
||||
def _default_stage_id(self):
|
||||
if self._context.get('default_job_id'):
|
||||
return self.env['hr.recruitment.stage'].search([
|
||||
('job_ids', '=', self._context['default_job_id']),
|
||||
('fold', '=', False)
|
||||
], order='sequence asc', limit=1).ids[0]
|
||||
return False
|
||||
|
||||
def _get_default_company_id(self, cr, uid, department_id=None, context=None):
|
||||
def _default_company_id(self):
|
||||
company_id = False
|
||||
if department_id:
|
||||
department = self.pool['hr.department'].browse(cr, uid, department_id, context=context)
|
||||
company_id = department.company_id.id if department and department.company_id else False
|
||||
if self._context.get('default_department_id'):
|
||||
department = self.env['hr.department'].browse(self._context['default_department_id'])
|
||||
company_id = department.company_id.id
|
||||
if not company_id:
|
||||
company_id = self.pool['res.company']._company_default_get(cr, uid, 'hr.applicant', context=context)
|
||||
company_id = self.env['res.company']._company_default_get('hr.applicant')
|
||||
return company_id
|
||||
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
stage_obj = self.pool.get('hr.recruitment.stage')
|
||||
order = stage_obj._order
|
||||
name = fields.Char("Subject / Application Name", required=True)
|
||||
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.Text("Description")
|
||||
email_from = fields.Char("Email", size=128, help="These people will receive email.")
|
||||
email_cc = fields.Text("Watchers Emails", size=252,
|
||||
help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma")
|
||||
probability = fields.Float("Probability")
|
||||
partner_id = fields.Many2one('res.partner', "Contact")
|
||||
create_date = fields.Datetime("Creation Date", readonly=True, select=True)
|
||||
write_date = fields.Datetime("Update Date", readonly=True)
|
||||
stage_id = fields.Many2one('hr.recruitment.stage', 'Stage', track_visibility='onchange',
|
||||
domain="[('job_ids', '=', job_id)]", copy=False, select=1,
|
||||
default=_default_stage_id)
|
||||
last_stage_id = fields.Many2one('hr.recruitment.stage', "Last Stage",
|
||||
help="Stage of the applicant before being in the current stage. Used for lost cases analysis.")
|
||||
categ_ids = fields.Many2many('hr.applicant.category', string="Tags")
|
||||
company_id = fields.Many2one('res.company', "Company", default=_default_company_id)
|
||||
user_id = fields.Many2one('res.users', "Responsible", track_visibility="onchange", default=lambda self: self.env.uid)
|
||||
date_closed = fields.Datetime("Closed", readonly=True, select=True)
|
||||
date_open = fields.Datetime("Assigned", readonly=True, select=True)
|
||||
date_last_stage_update = fields.Datetime("Last Stage Update", select=True, default=fields.Datetime.now)
|
||||
date_action = fields.Date("Next Action Date")
|
||||
title_action = fields.Char("Next Action", size=64)
|
||||
priority = fields.Selection(AVAILABLE_PRIORITIES, "Appreciation", default='0')
|
||||
job_id = fields.Many2one('hr.job', "Applied Job")
|
||||
salary_proposed_extra = fields.Char("Proposed Salary Extra", help="Salary Proposed by the Organisation, extra advantages")
|
||||
salary_expected_extra = fields.Char("Expected Salary Extra", help="Salary Expected by Applicant, extra advantages")
|
||||
salary_proposed = fields.Float("Proposed Salary", help="Salary Proposed by the Organisation")
|
||||
salary_expected = fields.Float("Expected Salary", help="Salary Expected by Applicant")
|
||||
availability = fields.Date("Availability", help="The date at which the applicant will be available to start working")
|
||||
partner_name = fields.Char("Applicant's Name")
|
||||
partner_phone = fields.Char("Phone", size=32)
|
||||
partner_mobile = fields.Char("Mobile", size=32)
|
||||
type_id = fields.Many2one('hr.recruitment.degree', "Degree")
|
||||
department_id = fields.Many2one('hr.department', "Department")
|
||||
survey = fields.Many2one('survey.survey', related='job_id.survey_id', string="Survey") # TDE FIXME: rename to survey_id
|
||||
response_id = fields.Many2one('survey.user_input', "Response", ondelete="set null", oldname="response")
|
||||
reference = fields.Char("Referred By")
|
||||
day_open = fields.Float(compute='_compute_day', string="Days to Open")
|
||||
day_close = fields.Float(compute='_compute_day', string="Days to Close")
|
||||
color = fields.Integer("Color Index", default=0)
|
||||
emp_id = fields.Many2one('hr.employee', string="Employee", track_visibility="onchange", help="Employee linked to the applicant.")
|
||||
user_email = fields.Char(related='user_id.email', type="char", string="User Email", readonly=True)
|
||||
attachment_number = fields.Integer(compute='_get_attachment_number', string="Number of Attachments")
|
||||
employee_name = fields.Char(related='emp_id.name', string="Employee Name")
|
||||
|
||||
@api.depends('date_open', 'date_closed')
|
||||
@api.one
|
||||
def _compute_day(self):
|
||||
if self.date_open:
|
||||
date_create = datetime.strptime(self.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
date_open = datetime.strptime(self.date_open, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
self.day_open = (date_open - date_create).total_seconds() / (24.0 * 3600)
|
||||
|
||||
if self.date_closed:
|
||||
date_create = datetime.strptime(self.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
date_closed = datetime.strptime(self.date_closed, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
self.day_close = (date_closed - date_create).total_seconds() / (24.0 * 3600)
|
||||
|
||||
@api.multi
|
||||
def _get_attachment_number(self):
|
||||
read_group_res = self.env['ir.attachment'].read_group(
|
||||
[('res_model', '=', 'hr.applicant'), ('res_id', 'in', self.ids)],
|
||||
['res_id'], ['res_id'])
|
||||
attach_data = dict((res['res_id'], res['res_id_count']) for res in read_group_res)
|
||||
for record in self:
|
||||
record.attachment_number = attach_data.get(record.id, 0)
|
||||
|
||||
@api.model
|
||||
def _read_group_stage_ids(self, ids, domain, read_group_order=None, access_rights_uid=None):
|
||||
access_rights_uid = access_rights_uid or self.env.uid
|
||||
Stage = self.env['hr.recruitment.stage']
|
||||
order = Stage._order
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
if read_group_order == 'stage_id desc':
|
||||
order = "%s desc" % order
|
||||
# retrieve job_id from the context and write the domain: ids + contextual columns (job or default)
|
||||
job_id = context and context.get('default_job_id')
|
||||
job_id = self._context.get('default_job_id')
|
||||
department_id = self._context.get('default_department_id')
|
||||
search_domain = []
|
||||
if job_id:
|
||||
search_domain += ['|', ('job_ids', '=', job_id)]
|
||||
search_domain += [('id', 'in', ids)]
|
||||
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
search_domain = [('job_ids', '=', job_id)]
|
||||
if department_id:
|
||||
if search_domain:
|
||||
search_domain = ['|', ('job_ids.department_id', '=', department_id)] + search_domain
|
||||
else:
|
||||
search_domain = [('job_ids.department_id', '=', department_id)]
|
||||
if self.ids:
|
||||
if search_domain:
|
||||
search_domain = ['|', ('id', 'in', self.ids)] + search_domain
|
||||
else:
|
||||
search_domain = [('id', 'in', self.ids)]
|
||||
|
||||
stage_ids = Stage._search(search_domain, order=order, access_rights_uid=access_rights_uid)
|
||||
stages = Stage.sudo(access_rights_uid).browse(stage_ids)
|
||||
result = stages.name_get()
|
||||
# restore order of the search
|
||||
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
result.sort(lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
|
||||
fold = {}
|
||||
for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context):
|
||||
for stage in stages:
|
||||
fold[stage.id] = stage.fold or False
|
||||
return result, fold
|
||||
|
||||
def _compute_day(self, cr, uid, ids, fields, args, context=None):
|
||||
res = dict((res_id, {}) for res_id in ids)
|
||||
for issue in self.browse(cr, uid, ids, context=context):
|
||||
values = {
|
||||
'day_open': 0.0,
|
||||
'day_close': 0.0,
|
||||
}
|
||||
|
||||
if issue.date_open:
|
||||
date_create = datetime.strptime(issue.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
date_open = datetime.strptime(issue.date_open, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
values['day_open'] = (date_open - date_create).total_seconds() / (24.0 * 3600)
|
||||
|
||||
if issue.date_closed:
|
||||
date_create = datetime.strptime(issue.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
date_closed = datetime.strptime(issue.date_closed, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
values['day_close'] = (date_closed - date_create).total_seconds() / (24.0 * 3600)
|
||||
|
||||
# filter only required values
|
||||
for field in fields:
|
||||
res[issue.id][field] = values[field]
|
||||
return res
|
||||
|
||||
def _get_attachment_number(self, cr, uid, ids, fields, args, context=None):
|
||||
res = dict.fromkeys(ids, 0)
|
||||
for app_id in ids:
|
||||
res[app_id] = self.pool['ir.attachment'].search_count(cr, uid, [('res_model', '=', 'hr.applicant'), ('res_id', '=', app_id)], context=context)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Subject / Application Name', required=True),
|
||||
'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the case without removing it."),
|
||||
'description': fields.text('Description'),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'email_cc': fields.text('Watchers Emails', size=252, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
|
||||
'probability': fields.float('Probability'),
|
||||
'partner_id': fields.many2one('res.partner', 'Contact'),
|
||||
'create_date': fields.datetime('Creation Date', readonly=True, select=True),
|
||||
'write_date': fields.datetime('Update Date', readonly=True),
|
||||
'stage_id': fields.many2one(
|
||||
'hr.recruitment.stage', 'Stage', track_visibility='onchange',
|
||||
domain="[('job_ids', '=', job_id)]", copy=False, select=1),
|
||||
'last_stage_id': fields.many2one('hr.recruitment.stage', 'Last Stage',
|
||||
help='Stage of the applicant before being in the current stage. Used for lost cases analysis.'),
|
||||
'categ_ids': fields.many2many('hr.applicant.category', string='Tags'),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'user_id': fields.many2one('res.users', 'Responsible', track_visibility='onchange'),
|
||||
'date_closed': fields.datetime('Closed', readonly=True, select=True),
|
||||
'date_open': fields.datetime('Assigned', readonly=True, select=True),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
|
||||
'date_action': fields.date('Next Action Date'),
|
||||
'title_action': fields.char('Next Action', size=64),
|
||||
'priority': fields.selection(AVAILABLE_PRIORITIES, 'Appreciation'),
|
||||
'job_id': fields.many2one('hr.job', 'Applied Job'),
|
||||
'salary_proposed_extra': fields.char('Proposed Salary Extra', help="Salary Proposed by the Organisation, extra advantages"),
|
||||
'salary_expected_extra': fields.char('Expected Salary Extra', help="Salary Expected by Applicant, extra advantages"),
|
||||
'salary_proposed': fields.float('Proposed Salary', help="Salary Proposed by the Organisation"),
|
||||
'salary_expected': fields.float('Expected Salary', help="Salary Expected by Applicant"),
|
||||
'availability': fields.date('Availability', help="The date in which the applicant will be available to start working. \n\nAdditional information like 'Not before the first 15 days of March' or 'Depends on the notice negociation' can be written in the application summary field."),
|
||||
'partner_name': fields.char("Applicant's Name"),
|
||||
'partner_phone': fields.char('Phone', size=32),
|
||||
'partner_mobile': fields.char('Mobile', size=32),
|
||||
'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
|
||||
'department_id': fields.many2one('hr.department', 'Department'),
|
||||
'survey': fields.related('job_id', 'survey_id', type='many2one', relation='survey.survey', string='Survey'),
|
||||
'response_id': fields.many2one('survey.user_input', "Response", ondelete='set null', oldname="response"),
|
||||
'reference': fields.char('Referred By'),
|
||||
'day_open': fields.function(_compute_day, string='Days to Open',
|
||||
multi='day_open', type="float",
|
||||
store={'hr.applicant': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)}),
|
||||
'day_close': fields.function(_compute_day, string='Days to Close',
|
||||
multi='day_close', type="float",
|
||||
store={'hr.applicant': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)}),
|
||||
'color': fields.integer('Color Index'),
|
||||
'emp_id': fields.many2one('hr.employee', string='Employee', track_visibility='onchange', help='Employee linked to the applicant.'),
|
||||
'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
|
||||
'attachment_number': fields.function(_get_attachment_number, string='Number of Attachments', type="integer"),
|
||||
'employee_name': fields.related('emp_id', 'name', type='char', string='Employee Name'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'active': lambda *a: 1,
|
||||
'user_id': lambda s, cr, uid, c: uid,
|
||||
'stage_id': _get_default_stage_id,
|
||||
'company_id': lambda s, cr, uid, c: s._get_default_company_id(cr, uid, c and c.get('default_department_id'), c),
|
||||
'color': 0,
|
||||
'priority': '0',
|
||||
'date_last_stage_update': fields.datetime.now,
|
||||
}
|
||||
|
||||
_group_by_full = {
|
||||
'stage_id': _read_group_stage_ids
|
||||
}
|
||||
|
||||
def action_get_created_employee(self, cr, uid, ids, context=None):
|
||||
if isinstance(ids, (list, tuple)):
|
||||
ids = ids and ids[0] or False
|
||||
applicant = self.browse(cr, uid, ids, context=context)
|
||||
action = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'hr', 'open_view_employee_list', context=context)
|
||||
action['res_id'] = applicant and applicant.emp_id.id or False
|
||||
return action
|
||||
@api.onchange('job_id')
|
||||
def onchange_job_id(self):
|
||||
vals = self._onchange_job_id_internal(self.job_id.id)
|
||||
self.department_id = vals['value']['department_id']
|
||||
self.user_id = vals['value']['user_id']
|
||||
self.stage_id = vals['value']['stage_id']
|
||||
|
||||
def onchange_job(self, cr, uid, ids, job_id=False, stage_id=False, context=None):
|
||||
def _onchange_job_id_internal(self, job_id):
|
||||
department_id = False
|
||||
user_id = False
|
||||
stage_id = self.stage_id.id
|
||||
if job_id:
|
||||
job_record = self.pool.get('hr.job').browse(cr, uid, job_id, context=context)
|
||||
department_id = job_record and job_record.department_id and job_record.department_id.id or False
|
||||
user_id = job_record and job_record.user_id and job_record.user_id.id or False
|
||||
if not stage_id and job_id:
|
||||
stage_id = self.stage_find(cr, uid, [], job_id, [('fold', '=', False)], context=context)
|
||||
return {'value': {'department_id': department_id, 'user_id': user_id, 'stage_id': stage_id}}
|
||||
job = self.env['hr.job'].browse(job_id)
|
||||
department_id = job.department_id.id
|
||||
user_id = job.user_id.id
|
||||
if not self.stage_id:
|
||||
stage_id = self.env['hr.recruitment.stage'].search([
|
||||
('job_ids', '=', job.id),
|
||||
('fold', '=', False)
|
||||
], order='sequence asc', limit=1).ids[0]
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
|
||||
data = {'partner_phone': False,
|
||||
'partner_mobile': False,
|
||||
'email_from': False}
|
||||
if partner_id:
|
||||
addr = self.pool.get('res.partner').browse(cr, uid, partner_id, context)
|
||||
data.update({'partner_phone': addr.phone,
|
||||
'partner_mobile': addr.mobile,
|
||||
'email_from': addr.email})
|
||||
return {'value': data}
|
||||
return {'value': {
|
||||
'department_id': department_id,
|
||||
'user_id': user_id,
|
||||
'stage_id': stage_id
|
||||
}}
|
||||
|
||||
def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
|
||||
@api.onchange('partner_id')
|
||||
def onchange_partner_id(self):
|
||||
self.partner_phone = self.partner_id.phone
|
||||
self.partner_mobile = self.partner_id.mobile
|
||||
self.email_from = self.partner_id.email
|
||||
|
||||
@api.onchange('stage_id')
|
||||
def onchange_stage_id(self):
|
||||
vals = self._onchange_stage_id_internal(self.stage_id.id)
|
||||
if vals['value'].get('date_closed'):
|
||||
self.date_closed = vals['value']['date_closed']
|
||||
|
||||
def _onchange_stage_id_internal(self, stage_id):
|
||||
if not stage_id:
|
||||
return {'value': {}}
|
||||
stage = self.pool['hr.recruitment.stage'].browse(cr, uid, stage_id, context=context)
|
||||
stage = self.env['hr.recruitment.stage'].browse(stage_id)
|
||||
if stage.fold:
|
||||
return {'value': {'date_closed': fields.datetime.now()}}
|
||||
return {'value': {'date_closed': False}}
|
||||
|
||||
def stage_find(self, cr, uid, applicants, job_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the lead:
|
||||
- job_id: if set, stages must belong to this section or
|
||||
be a default case
|
||||
"""
|
||||
search_domain = []
|
||||
if isinstance(applicants, (int, long)):
|
||||
applicants = self.browse(cr, uid, applicants, context=context)
|
||||
job_ids = set([applicant.job_id.id for applicant in applicants if applicant.job_id])
|
||||
if job_id:
|
||||
job_ids.add(job_id)
|
||||
# OR all job_id and OR with applicant_default
|
||||
if job_ids:
|
||||
search_domain += [('job_ids', 'in', list(job_ids))]
|
||||
# AND with the domain in parameter
|
||||
search_domain += list(domain)
|
||||
# perform search, return the first found
|
||||
stage_ids = self.pool.get('hr.recruitment.stage').search(cr, uid, search_domain, order=order, limit=1, context=context)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('department_id') and not self._context.get('default_department_id'):
|
||||
self = self.with_context(default_department_id=vals.get('department_id'))
|
||||
if vals.get('job_id') or self._context.get('default_job_id'):
|
||||
job_id = vals.get('job_id') or self._context.get('default_job_id')
|
||||
for key, value in self._onchange_job_id_internal(job_id)['value'].iteritems():
|
||||
if key not in vals:
|
||||
vals[key] = value
|
||||
if vals.get('user_id'):
|
||||
vals['date_open'] = fields.Datetime.now()
|
||||
if 'stage_id' in vals:
|
||||
vals.update(self._onchange_stage_id_internal(vals.get('stage_id'))['value'])
|
||||
applicant = super(Applicant, self.with_context(mail_create_nolog=True)).create(vals)
|
||||
if applicant.job_id:
|
||||
name = applicant.partner_name if applicant.partner_name else applicant.name
|
||||
applicant.job_id.message_post(
|
||||
body=_('New application from %s') % name,
|
||||
subtype="hr_recruitment.mt_job_applicant_new")
|
||||
return applicant
|
||||
|
||||
def action_makeMeeting(self, cr, uid, ids, context=None):
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
# user_id change: update date_open
|
||||
if vals.get('user_id'):
|
||||
vals['date_open'] = fields.Datetime.now()
|
||||
# stage_id: track last stage before update
|
||||
if 'stage_id' in vals:
|
||||
vals['date_last_stage_update'] = fields.Datetime.now()
|
||||
vals.update(self._onchange_stage_id_internal(vals.get('stage_id'))['value'])
|
||||
for applicant in self:
|
||||
vals['last_stage_id'] = applicant.stage_id.id
|
||||
res = super(Applicant, self).write(vals)
|
||||
else:
|
||||
res = super(Applicant, self).write(vals)
|
||||
|
||||
# post processing: if job changed, post a message on the job
|
||||
if vals.get('job_id'):
|
||||
for applicant in self:
|
||||
name = applicant.partner_name if applicant.partner_name else applicant.name
|
||||
self.env['hr.job'].browse([vals['job_id']]).message_post(
|
||||
body=_('New application from %s') % name,
|
||||
subtype="hr_recruitment.mt_job_applicant_new")
|
||||
|
||||
# post processing: if stage changed, post a message in the chatter
|
||||
if vals.get('stage_id'):
|
||||
if self.stage_id.template_id:
|
||||
# TDENOTE: probably factorize me in a message_post_with_template generic method FIXME
|
||||
composer = self.env['mail.compose.message'].with_context(active_ids=self.ids).create(
|
||||
{
|
||||
'model': self._name,
|
||||
'composition_mode': 'mass_mail',
|
||||
'template_id': self.stage_id.template_id.id,
|
||||
'notify': True,
|
||||
})
|
||||
values = composer.onchange_template_id(
|
||||
self.stage_id.template_id.id, 'mass_mail', self._name, False)['value']
|
||||
if values.get('attachment_ids'):
|
||||
values['attachment_ids'] = [(6, 0, values['attachment_ids'])]
|
||||
composer.write(values)
|
||||
composer.send_mail()
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _broadcast_welcome(self):
|
||||
""" Broadcast the welcome message to all users in the employee company. """
|
||||
IrModelData = self.env['ir.model.data']
|
||||
channel_all_employees = IrModelData.xmlid_to_object('mail.channel_all_employees')
|
||||
template_new_employee = IrModelData.xmlid_to_object('hr_recruitment.hr_welcome_new_employee')
|
||||
if template_new_employee:
|
||||
MailTemplate = self.env['mail.template']
|
||||
body_html = MailTemplate.render_template(template_new_employee.body_html, 'hr.employee', self.id)
|
||||
subject = MailTemplate.render_template(template_new_employee.subject, 'hr.employee', self.id)
|
||||
channel_all_employees.message_post(
|
||||
body=body_html, subject=subject,
|
||||
subtype='mail.mt_comment')
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def get_empty_list_help(self, help):
|
||||
return super(Applicant, self.with_context(empty_list_help_model='hr.job',
|
||||
empty_list_help_id=self.env.context.get('default_job_id'),
|
||||
empty_list_help_document_name=_("job applicants"))).get_empty_list_help(help)
|
||||
|
||||
@api.multi
|
||||
def action_get_created_employee(self):
|
||||
self.ensure_one()
|
||||
action = self.env['ir.actions.act_window'].for_xml_id('hr', 'open_view_employee_list')
|
||||
action['res_id'] = self.mapped('emp_id').ids[0]
|
||||
return action
|
||||
|
||||
@api.multi
|
||||
def action_makeMeeting(self):
|
||||
""" This opens Meeting's calendar view to schedule meeting on current applicant
|
||||
@return: Dictionary value for created Meeting view
|
||||
"""
|
||||
applicant = self.browse(cr, uid, ids[0], context)
|
||||
applicant_ids = []
|
||||
if applicant.partner_id:
|
||||
applicant_ids.append(applicant.partner_id.id)
|
||||
if applicant.department_id and applicant.department_id.manager_id and applicant.department_id.manager_id.user_id and applicant.department_id.manager_id.user_id.partner_id:
|
||||
applicant_ids.append(applicant.department_id.manager_id.user_id.partner_id.id)
|
||||
category = self.pool.get('ir.model.data').get_object(cr, uid, 'hr_recruitment', 'categ_meet_interview', context)
|
||||
res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'calendar', 'action_calendar_event', context)
|
||||
self.ensure_one()
|
||||
partners = self.partner_id
|
||||
if self.department_id and self.department_id.manager_id and self.department_id.manager_id.user_id:
|
||||
partners |= self.department_id.manager_id.user_id.partner_id
|
||||
|
||||
category = self.env.ref('hr_recruitment.categ_meet_interview')
|
||||
res = self.env['ir.actions.act_window'].for_xml_id('calendar', 'action_calendar_event')
|
||||
res['context'] = {
|
||||
'default_partner_ids': applicant_ids,
|
||||
'default_user_id': uid,
|
||||
'default_name': applicant.name,
|
||||
'default_partner_ids': partners.ids,
|
||||
'default_user_id': self.env.uid,
|
||||
'default_name': self.name,
|
||||
'default_categ_ids': category and [category.id] or False,
|
||||
}
|
||||
return res
|
||||
|
||||
def action_start_survey(self, cr, uid, ids, context=None):
|
||||
context = dict(context or {})
|
||||
applicant = self.browse(cr, uid, ids, context=context)[0]
|
||||
survey_obj = self.pool.get('survey.survey')
|
||||
response_obj = self.pool.get('survey.user_input')
|
||||
@api.multi
|
||||
def action_start_survey(self):
|
||||
self.ensure_one()
|
||||
# create a response and link it to this applicant
|
||||
if not applicant.response_id:
|
||||
response_id = response_obj.create(cr, uid, {'survey_id': applicant.survey.id, 'partner_id': applicant.partner_id.id}, context=context)
|
||||
self.write(cr, uid, ids[0], {'response_id': response_id}, context=context)
|
||||
if not self.response_id:
|
||||
response = self.env['survey.user_input'].create({'survey_id': self.survey.id, 'partner_id': self.partner_id.id})
|
||||
self.response_id = response.id
|
||||
else:
|
||||
response_id = applicant.response_id.id
|
||||
response = self.response_id
|
||||
# grab the token of the response and start surveying
|
||||
response = response_obj.browse(cr, uid, response_id, context=context)
|
||||
context.update({'survey_token': response.token})
|
||||
return survey_obj.action_start_survey(cr, uid, [applicant.survey.id], context=context)
|
||||
return self.survey.with_context(survey_token=response.token).action_start_survey()
|
||||
|
||||
def action_print_survey(self, cr, uid, ids, context=None):
|
||||
@api.multi
|
||||
def action_print_survey(self):
|
||||
""" If response is available then print this response otherwise print survey form (print template of the survey) """
|
||||
context = dict(context or {})
|
||||
applicant = self.browse(cr, uid, ids, context=context)[0]
|
||||
survey_obj = self.pool.get('survey.survey')
|
||||
response_obj = self.pool.get('survey.user_input')
|
||||
if not applicant.response_id:
|
||||
return survey_obj.action_print_survey(cr, uid, [applicant.survey.id], context=context)
|
||||
self.ensure_one()
|
||||
if not self.response_id:
|
||||
return self.survey.action_print_survey()
|
||||
else:
|
||||
response = response_obj.browse(cr, uid, applicant.response_id.id, context=context)
|
||||
context.update({'survey_token': response.token})
|
||||
return survey_obj.action_print_survey(cr, uid, [applicant.survey.id], context=context)
|
||||
response = self.response_id
|
||||
return self.survey.with_context(survey_token=response.token).action_print_survey()
|
||||
|
||||
def action_get_attachment_tree_view(self, cr, uid, ids, context=None):
|
||||
model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'action_attachment')
|
||||
action = self.pool.get(model).read(cr, uid, action_id, context=context)
|
||||
action['context'] = {'default_res_model': self._name, 'default_res_id': ids[0]}
|
||||
action['domain'] = str(['&', ('res_model', '=', self._name), ('res_id', 'in', ids)])
|
||||
@api.multi
|
||||
def action_get_attachment_tree_view(self):
|
||||
attachment_action = self.env.ref('base.action_attachment')
|
||||
action = attachment_action.read()[0]
|
||||
action['context'] = {'default_res_model': self._name, 'default_res_id': self.ids[0]}
|
||||
action['domain'] = str(['&', ('res_model', '=', self._name), ('res_id', 'in', self.ids)])
|
||||
return action
|
||||
|
||||
def _track_subtype(self, cr, uid, ids, init_values, context=None):
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
@api.multi
|
||||
def _track_subtype(self, init_values):
|
||||
record = self[0]
|
||||
if 'emp_id' in init_values and record.emp_id:
|
||||
return 'hr_recruitment.mt_applicant_hired'
|
||||
elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence <= 1:
|
||||
return 'hr_recruitment.mt_applicant_new'
|
||||
elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence > 1:
|
||||
return 'hr_recruitment.mt_applicant_stage_changed'
|
||||
return super(hr_applicant, self)._track_subtype(cr, uid, ids, init_values, context=context)
|
||||
return super(Applicant, self)._track_subtype(init_values)
|
||||
|
||||
@api.cr_uid_context
|
||||
def message_get_reply_to(self, cr, uid, ids, default=None, context=None):
|
||||
@api.model
|
||||
def message_get_reply_to(self, ids, default=None):
|
||||
""" Override to get the reply_to of the parent project. """
|
||||
applicants = self.browse(cr, SUPERUSER_ID, ids, context=context)
|
||||
job_ids = set([applicant.job_id.id for applicant in applicants if applicant.job_id])
|
||||
aliases = self.pool['hr.job'].message_get_reply_to(cr, uid, list(job_ids), default=default, context=context)
|
||||
applicants = self.sudo().browse(ids)
|
||||
aliases = self.env['hr.job'].message_get_reply_to(applicants.mapped('job_id').ids, default=default)
|
||||
return dict((applicant.id, aliases.get(applicant.job_id and applicant.job_id.id or 0, False)) for applicant in applicants)
|
||||
|
||||
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
|
||||
recipients = super(hr_applicant, self).message_get_suggested_recipients(cr, uid, ids, context=context)
|
||||
for applicant in self.browse(cr, uid, ids, context=context):
|
||||
@api.multi
|
||||
def message_get_suggested_recipients(self):
|
||||
recipients = super(Applicant, self).message_get_suggested_recipients()
|
||||
for applicant in self:
|
||||
if applicant.partner_id:
|
||||
applicant._message_add_suggested_recipient(recipients, partner=applicant.partner_id, reason=_('Contact'))
|
||||
elif applicant.email_from:
|
||||
applicant._message_add_suggested_recipient(recipients, email=applicant.email_from, reason=_('Contact Email'))
|
||||
return recipients
|
||||
|
||||
def message_new(self, cr, uid, msg, custom_values=None, context=None):
|
||||
@api.model
|
||||
def message_new(self, msg, custom_values=None):
|
||||
""" Overrides mail_thread message_new that is called by the mailgateway
|
||||
through message_process.
|
||||
This override updates the document according to the email.
|
||||
"""
|
||||
if custom_values is None:
|
||||
custom_values = {}
|
||||
val = msg.get('from').split('<')[0]
|
||||
defaults = {
|
||||
'name': msg.get('subject') or _("No Subject"),
|
||||
'name': msg.get('subject') or _("No Subject"),
|
||||
'partner_name': val,
|
||||
'email_from': msg.get('from'),
|
||||
'email_cc': msg.get('cc'),
|
||||
@@ -412,148 +456,46 @@ class hr_applicant(osv.Model):
|
||||
}
|
||||
if msg.get('priority'):
|
||||
defaults['priority'] = msg.get('priority')
|
||||
defaults.update(custom_values)
|
||||
return super(hr_applicant, self).message_new(cr, uid, msg, custom_values=defaults, context=context)
|
||||
if custom_values:
|
||||
defaults.update(custom_values)
|
||||
return super(Applicant, self).message_new(msg, custom_values=defaults)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
context = dict(context or {})
|
||||
context['mail_create_nolog'] = True
|
||||
if vals.get('department_id') and not context.get('default_department_id'):
|
||||
context['default_department_id'] = vals.get('department_id')
|
||||
if vals.get('job_id') or context.get('default_job_id'):
|
||||
job_id = vals.get('job_id') or context.get('default_job_id')
|
||||
vals.update(self.onchange_job(cr, uid, [], job_id, context=context)['value'])
|
||||
if vals.get('user_id'):
|
||||
vals['date_open'] = fields.datetime.now()
|
||||
if 'stage_id' in vals:
|
||||
vals.update(self.onchange_stage_id(cr, uid, None, vals.get('stage_id'), context=context)['value'])
|
||||
obj_id = super(hr_applicant, self).create(cr, uid, vals, context=context)
|
||||
applicant = self.browse(cr, uid, obj_id, context=context)
|
||||
if applicant.job_id:
|
||||
name = applicant.partner_name if applicant.partner_name else applicant.name
|
||||
self.pool['hr.job'].message_post(
|
||||
cr, uid, [applicant.job_id.id],
|
||||
body=_('New application from %s') % name,
|
||||
subtype="hr_recruitment.mt_job_applicant_new", context=context)
|
||||
return obj_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
res = True
|
||||
|
||||
# user_id change: update date_open
|
||||
if vals.get('user_id'):
|
||||
vals['date_open'] = fields.datetime.now()
|
||||
# stage_id: track last stage before update
|
||||
if 'stage_id' in vals:
|
||||
vals['date_last_stage_update'] = fields.datetime.now()
|
||||
vals.update(self.onchange_stage_id(cr, uid, ids, vals.get('stage_id'), context=context)['value'])
|
||||
for applicant in self.browse(cr, uid, ids, context=None):
|
||||
vals['last_stage_id'] = applicant.stage_id.id
|
||||
res = super(hr_applicant, self).write(cr, uid, [applicant.id], vals, context=context)
|
||||
else:
|
||||
res = super(hr_applicant, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
# post processing: if job changed, post a message on the job
|
||||
if vals.get('job_id'):
|
||||
for applicant in self.browse(cr, uid, ids, context=None):
|
||||
name = applicant.partner_name if applicant.partner_name else applicant.name
|
||||
self.pool['hr.job'].message_post(
|
||||
cr, uid, [vals['job_id']],
|
||||
body=_('New application from %s') % name,
|
||||
subtype="hr_recruitment.mt_job_applicant_new", context=context)
|
||||
|
||||
# post processing: if stage changed, post a message in the chatter
|
||||
if vals.get('stage_id'):
|
||||
stage = self.pool['hr.recruitment.stage'].browse(cr, uid, vals['stage_id'], context=context)
|
||||
if stage.template_id:
|
||||
# TDENOTE: probably factorize me in a message_post_with_template generic method FIXME
|
||||
compose_ctx = dict(context,
|
||||
active_ids=ids)
|
||||
compose_id = self.pool['mail.compose.message'].create(
|
||||
cr, uid, {
|
||||
'model': self._name,
|
||||
'composition_mode': 'mass_mail',
|
||||
'template_id': stage.template_id.id,
|
||||
'notify': True,
|
||||
}, context=compose_ctx)
|
||||
values = self.pool['mail.compose.message'].onchange_template_id(
|
||||
cr, uid, [compose_id], stage.template_id.id, 'mass_mail', self._name, False, context=compose_ctx)['value']
|
||||
if values.get('attachment_ids'):
|
||||
values['attachment_ids'] = [(6, 0, values['attachment_ids'])]
|
||||
self.pool['mail.compose.message'].write(
|
||||
cr, uid, [compose_id],
|
||||
values,
|
||||
context=compose_ctx)
|
||||
self.pool['mail.compose.message'].send_mail(cr, uid, [compose_id], context=compose_ctx)
|
||||
return res
|
||||
|
||||
def _broadcast_welcome(self, cr, uid, employee_id, context=None):
|
||||
""" Broadcast the welcome message to all users in the employee company. """
|
||||
IrModelData = self.pool['ir.model.data']
|
||||
group_all_employees = IrModelData.xmlid_to_object(cr, uid, 'mail.channel_all_employees', context=context)
|
||||
template_new_employee = IrModelData.xmlid_to_object(cr, uid, 'hr_recruitment.hr_welcome_new_employee', context=context)
|
||||
if template_new_employee:
|
||||
MailTemplate = self.pool['mail.template']
|
||||
body_html = MailTemplate.render_template(cr, uid, template_new_employee.body_html, 'hr.employee', employee_id, context=context)
|
||||
subject = MailTemplate.render_template(cr, uid, template_new_employee.subject, 'hr.employee', employee_id, context=context)
|
||||
self.pool['mail.channel'].message_post(cr, uid, [group_all_employees.id],
|
||||
body=body_html, subject=subject,
|
||||
subtype='mail.mt_comment', context=context)
|
||||
return True
|
||||
|
||||
def create_employee_from_applicant(self, cr, uid, ids, context=None):
|
||||
@api.multi
|
||||
def create_employee_from_applicant(self):
|
||||
""" Create an hr.employee from the hr.applicants """
|
||||
if context is None:
|
||||
context = {}
|
||||
hr_employee = self.pool.get('hr.employee')
|
||||
model_data = self.pool.get('ir.model.data')
|
||||
act_window = self.pool.get('ir.actions.act_window')
|
||||
emp_id = False
|
||||
for applicant in self.browse(cr, uid, ids, context=context):
|
||||
employee = False
|
||||
for applicant in self:
|
||||
address_id = contact_name = False
|
||||
if applicant.partner_id:
|
||||
address_id = self.pool.get('res.partner').address_get(cr, uid, [applicant.partner_id.id], ['contact'])['contact']
|
||||
contact_name = self.pool.get('res.partner').name_get(cr, uid, [applicant.partner_id.id])[0][1]
|
||||
address_id = applicant.partner_id.address_get(['contact'])['contact']
|
||||
contact_name = applicant.partner_id.name_get()[0][1]
|
||||
if applicant.job_id and (applicant.partner_name or contact_name):
|
||||
applicant.job_id.write({'no_of_hired_employee': applicant.job_id.no_of_hired_employee + 1})
|
||||
emp_id = hr_employee.create(cr, uid, {'name': applicant.partner_name or contact_name,
|
||||
'job_id': applicant.job_id.id,
|
||||
'address_home_id': address_id,
|
||||
'department_id': applicant.department_id.id or False,
|
||||
'address_id': applicant.company_id and applicant.company_id.partner_id and applicant.company_id.partner_id.id or False,
|
||||
'work_email': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.email or False,
|
||||
'work_phone': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.phone or False,
|
||||
}, context=context)
|
||||
self.write(cr, uid, [applicant.id], {'emp_id': emp_id}, context=context)
|
||||
self.pool['hr.job'].message_post(
|
||||
cr, uid, [applicant.job_id.id],
|
||||
employee = self.env['hr.employee'].create({'name': applicant.partner_name or contact_name,
|
||||
'job_id': applicant.job_id.id,
|
||||
'address_home_id': address_id,
|
||||
'department_id': applicant.department_id.id or False,
|
||||
'address_id': applicant.company_id and applicant.company_id.partner_id and applicant.company_id.partner_id.id or False,
|
||||
'work_email': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.email or False,
|
||||
'work_phone': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.phone or False})
|
||||
applicant.write({'emp_id': employee.id})
|
||||
applicant.job_id.message_post(
|
||||
body=_('New Employee %s Hired') % applicant.partner_name if applicant.partner_name else applicant.name,
|
||||
subtype="hr_recruitment.mt_job_applicant_hired", context=context)
|
||||
self._broadcast_welcome(cr, uid, emp_id, context=context)
|
||||
subtype="hr_recruitment.mt_job_applicant_hired")
|
||||
employee._broadcast_welcome()
|
||||
else:
|
||||
raise UserError(_('You must define an Applied Job and a Contact Name for this applicant.'))
|
||||
|
||||
action_model, action_id = model_data.get_object_reference(cr, uid, 'hr', 'open_view_employee_list')
|
||||
dict_act_window = act_window.read(cr, uid, [action_id], [])[0]
|
||||
if emp_id:
|
||||
dict_act_window['res_id'] = emp_id
|
||||
employee_action = self.env.ref('hr.open_view_employee_list')
|
||||
dict_act_window = employee_action.read([])[0]
|
||||
if employee:
|
||||
dict_act_window['res_id'] = employee.id
|
||||
dict_act_window['view_mode'] = 'form,tree'
|
||||
return dict_act_window
|
||||
|
||||
def get_empty_list_help(self, cr, uid, help, context=None):
|
||||
context = dict(context or {})
|
||||
context['empty_list_help_model'] = 'hr.job'
|
||||
context['empty_list_help_id'] = context.get('default_job_id', None)
|
||||
context['empty_list_help_document_name'] = _("job applicants")
|
||||
return super(hr_applicant, self).get_empty_list_help(cr, uid, help, context=context)
|
||||
|
||||
|
||||
class applicant_category(osv.osv):
|
||||
""" Category of applicant """
|
||||
class applicant_category(models.Model):
|
||||
_name = "hr.applicant.category"
|
||||
_description = "Category of applicant"
|
||||
_columns = {
|
||||
'name': fields.char('Name', required=True, translate=True),
|
||||
}
|
||||
|
||||
name = fields.Char("Name", required=True, translate=True)
|
||||
|
||||
@@ -1,54 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_applicant_settings(osv.TransientModel):
|
||||
class RecruitmentSettings(models.TransientModel):
|
||||
_name = 'hr.recruitment.config.settings'
|
||||
_inherit = ['res.config.settings', 'fetchmail.config.settings']
|
||||
|
||||
_columns = {
|
||||
'module_document': fields.boolean('Allow the automatic indexation of resumes',
|
||||
help='Manage your CV\'s and motivation letter related to all applicants.\n'
|
||||
'-This installs the module document_ftp. This will install the knowledge management module in order to allow you to search using specific keywords through the content of all documents (PDF, .DOCx...)'),
|
||||
'alias_prefix': fields.char('Default Alias Name for Jobs'),
|
||||
'alias_domain': fields.char('Alias Domain'),
|
||||
}
|
||||
module_document = fields.Boolean(string='Allow the automatic indexation of resumes',
|
||||
help='Manage your CV\'s and motivation letter related to all applicants.\n'
|
||||
'-This installs the module document_ftp. This will install the knowledge management module in order to allow you to search using specific keywords through the content of all documents (PDF, .DOCx...)')
|
||||
alias_prefix = fields.Char(string='Default Alias Name for Jobs')
|
||||
alias_domain = fields.Char(string='Alias Domain',
|
||||
default=lambda self: self.env["ir.config_parameter"].get_param("mail.catchall.domain"))
|
||||
|
||||
_defaults = {
|
||||
'alias_domain': lambda self, cr, uid, context: self.pool["ir.config_parameter"].get_param(cr, uid, "mail.catchall.domain", context=context),
|
||||
}
|
||||
@api.model
|
||||
def _find_default_job_alias_id(self):
|
||||
jobs_alias = self.env.ref('hr_recruitment.mail_alias_jobs')
|
||||
if not jobs_alias:
|
||||
aliases = self.env['mail.alias'].search([
|
||||
('alias_model_id.model', '=', 'hr.applicant'),
|
||||
('alias_force_thread_id', '=', False),
|
||||
('alias_parent_model_id.model', '=', 'hr.job'),
|
||||
('alias_parent_thread_id', '=', False),
|
||||
('alias_defaults', '=', '{}')], limit=1)
|
||||
jobs_alias = aliases and aliases[0] or False
|
||||
return jobs_alias
|
||||
|
||||
def _find_default_job_alias_id(self, cr, uid, context=None):
|
||||
alias_id = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'hr_recruitment.mail_alias_jobs')
|
||||
if not alias_id:
|
||||
alias_ids = self.pool['mail.alias'].search(
|
||||
cr, uid, [
|
||||
('alias_model_id.model', '=', 'hr.applicant'),
|
||||
('alias_force_thread_id', '=', False),
|
||||
('alias_parent_model_id.model', '=', 'hr.job'),
|
||||
('alias_parent_thread_id', '=', False),
|
||||
('alias_defaults', '=', '{}')
|
||||
], context=context)
|
||||
alias_id = alias_ids and alias_ids[0] or False
|
||||
return alias_id
|
||||
@api.multi
|
||||
def get_default_alias_prefix(self):
|
||||
alias = self._find_default_job_alias_id()
|
||||
return {'alias_prefix': alias and alias.alias_name or False}
|
||||
|
||||
def get_default_alias_prefix(self, cr, uid, ids, context=None):
|
||||
alias_name = False
|
||||
alias_id = self._find_default_job_alias_id(cr, uid, context=context)
|
||||
if alias_id:
|
||||
alias_name = self.pool['mail.alias'].browse(cr, uid, alias_id, context=context).alias_name
|
||||
return {'alias_prefix': alias_name}
|
||||
|
||||
def set_default_alias_prefix(self, cr, uid, ids, context=None):
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
alias_id = self._find_default_job_alias_id(cr, uid, context=context)
|
||||
if not alias_id:
|
||||
create_ctx = dict(context, alias_model_name='hr.applicant', alias_parent_model_name='hr.job')
|
||||
alias_id = self.pool['mail.alias'].create(cr, uid, {'alias_name': record.alias_prefix}, context=create_ctx)
|
||||
@api.multi
|
||||
def set_default_alias_prefix(self):
|
||||
for record in self:
|
||||
alias = self._find_default_job_alias_id()
|
||||
if not alias:
|
||||
alias = self.env['mail.alias'].with_context(alias_model_name='hr.applicant', alias_parent_model_name='hr.job').create({'alias_name': record.alias_prefix})
|
||||
else:
|
||||
mail_alias.write(cr, uid, alias_id, {'alias_name': record.alias_prefix}, context=context)
|
||||
alias.write({'alias_name': record.alias_prefix})
|
||||
return True
|
||||
|
||||
@@ -1,40 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import tools
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import fields, models, tools
|
||||
from ..models import hr_recruitment
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
|
||||
|
||||
class hr_recruitment_report(osv.Model):
|
||||
class hr_recruitment_report(models.Model):
|
||||
_name = "hr.recruitment.report"
|
||||
_description = "Recruitments Statistics"
|
||||
_auto = False
|
||||
_rec_name = 'date_create'
|
||||
_order = 'date_create desc'
|
||||
|
||||
_columns = {
|
||||
'user_id': fields.many2one('res.users', 'User', readonly=True),
|
||||
'company_id': fields.many2one('res.company', 'Company', readonly=True),
|
||||
'date_create': fields.datetime('Create Date', readonly=True),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', readonly=True),
|
||||
'date_closed': fields.date('Closed', readonly=True),
|
||||
'job_id': fields.many2one('hr.job', 'Applied Job',readonly=True),
|
||||
'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage'),
|
||||
'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
|
||||
'department_id': fields.many2one('hr.department','Department',readonly=True),
|
||||
'priority': fields.selection(hr_recruitment.AVAILABLE_PRIORITIES, 'Appreciation'),
|
||||
'salary_prop' : fields.float("Salary Proposed", digits=0),
|
||||
'salary_prop_avg' : fields.float("Avg. Proposed Salary", group_operator="avg", digits=0),
|
||||
'salary_exp' : fields.float("Salary Expected", digits=0),
|
||||
'salary_exp_avg' : fields.float("Avg. Expected Salary", group_operator="avg", digits=0),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner',readonly=True),
|
||||
'delay_close': fields.float('Avg. Delay to Close', digits=(16,2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to close the project issue"),
|
||||
'last_stage_id': fields.many2one ('hr.recruitment.stage', 'Last Stage'),
|
||||
}
|
||||
|
||||
user_id = fields.Many2one('res.users', 'User', readonly=True)
|
||||
company_id = fields.Many2one('res.company', 'Company', readonly=True)
|
||||
date_create = fields.Datetime('Create Date', readonly=True)
|
||||
date_last_stage_update = fields.Datetime('Last Stage Update', readonly=True)
|
||||
date_closed = fields.Date('Closed', readonly=True)
|
||||
job_id = fields.Many2one('hr.job', 'Applied Job', readonly=True)
|
||||
stage_id = fields.Many2one('hr.recruitment.stage', 'Stage')
|
||||
type_id = fields.Many2one('hr.recruitment.degree', 'Degree')
|
||||
department_id = fields.Many2one('hr.department', 'Department', readonly=True)
|
||||
priority = fields.Selection(hr_recruitment.AVAILABLE_PRIORITIES, 'Appreciation')
|
||||
salary_prop = fields.Float("Salary Proposed", digits=0)
|
||||
salary_prop_avg = fields.Float("Avg. Proposed Salary", group_operator="avg", digits=0)
|
||||
salary_exp = fields.Float("Salary Expected", digits=0)
|
||||
salary_exp_avg = fields.Float("Avg. Expected Salary", group_operator="avg", digits=0)
|
||||
partner_id = fields.Many2one('res.partner', 'Partner', readonly=True)
|
||||
delay_close = fields.Float('Avg. Delay to Close', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to close the project issue")
|
||||
last_stage_id = fields.Many2one('hr.recruitment.stage', 'Last Stage')
|
||||
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'hr_recruitment_report')
|
||||
cr.execute("""
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
-
|
||||
!python {model: mail.thread}: |
|
||||
request_file = open(openerp.modules.module.get_module_resource('hr_recruitment','test', 'resume.eml'),'rb')
|
||||
job_id = self.pool["ir.model.data"].xmlid_to_res_id(cr, uid, "hr.job_developer")
|
||||
request_message = request_file.read()
|
||||
self.message_process(cr, uid, 'hr.applicant', request_message)
|
||||
self.message_process(cr, uid, 'hr.applicant', request_message, custom_values={"job_id": job_id})
|
||||
-
|
||||
After getting the mail, I check the details of the new applicant.
|
||||
-
|
||||
@@ -52,11 +53,3 @@
|
||||
!python {model: hr.applicant}: |
|
||||
context.update({'active_model': 'hr.applicant', 'active_ids': [ref("hr_recruitment.hr_case_programmer")], 'active_id': ref("hr_recruitment.hr_case_programmer")})
|
||||
self.action_print_survey(cr, uid, [ref('hr_case_programmer')])
|
||||
-
|
||||
Now hired employee want to be a partner of company.
|
||||
-
|
||||
!record {model: hr.recruitment.partner.create, id: hr_recruitment_partner_id1 }:
|
||||
-
|
||||
!python {model: hr.recruitment.partner.create}: |
|
||||
context.update({'active_model': 'hr.applicant', 'active_ids': [ref("hr_recruitment.hr_case_programmer")], 'active_id': ref("hr_recruitment.hr_case_programmer")})
|
||||
self.make_order(cr, uid, [ref("hr_recruitment_partner_id1")], context=context)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<!-- Stage -->
|
||||
<record id="hr_job_stage_act" model="ir.actions.act_window">
|
||||
<field name="name">Recruitment / Applicants Stages</field>
|
||||
@@ -118,8 +118,7 @@
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id"
|
||||
on_change="onchange_partner_id(partner_id)"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="email_from" widget="email"/>
|
||||
<field name="partner_phone"/>
|
||||
<field name="partner_mobile"/>
|
||||
@@ -141,7 +140,7 @@
|
||||
<group string="Job">
|
||||
<field name="survey" invisible="1"/>
|
||||
<field name="response_id" invisible="1"/>
|
||||
<field name="job_id" on_change="onchange_job(job_id,stage_id)"/>
|
||||
<field name="job_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options='{"no_open":True}' />
|
||||
</group>
|
||||
@@ -663,7 +662,7 @@
|
||||
<field name="res_model">hr.applicant</field>
|
||||
<field name="view_mode">kanban,tree,form,graph,calendar</field>
|
||||
<field name="context">{
|
||||
'search_default_department_id': [active_id],
|
||||
'search_default_department_id': active_id,
|
||||
'default_department_id': active_id}
|
||||
</field>
|
||||
<field name="domain">[('stage_id.sequence','<=','1')]</field>
|
||||
|
||||
Reference in New Issue
Block a user