#
##############################################################################
-from base_status.base_stage import base_stage
import time
-from datetime import datetime, timedelta
+import tools
+from base_status.base_stage import base_stage
+from datetime import datetime
from osv import fields, osv
-import tools
-import collections
-import binascii
from tools.translate import _
+from tools import html2plaintext
AVAILABLE_STATES = [
('draft', 'New'),
'name': fields.char('Name', size=64, required=True, translate=True),
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."),
'department_id':fields.many2one('hr.department', 'Specific to a Department', help="Stages of the recruitment process may be different per department. If this stage is common to all departments, keep this field empty."),
- 'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change according to the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."),
+ 'state': fields.selection(AVAILABLE_STATES, 'Status', required=True, help="The related status for the stage. The status of your document will automatically change according to the selected stage. Example, a stage is related to the status 'Close', when your document reach this stage, it will be automatically closed."),
'fold': fields.boolean('Hide in views if empty', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."),
'requirements': fields.text('Requirements'),
}
_name = "hr.applicant"
_description = "Applicant"
_order = "id desc"
- _inherit = ['ir.needaction_mixin', 'mail.thread']
- _mail_compose_message = True
+ _inherit = ['mail.thread', 'ir.needaction_mixin']
def _get_default_department_id(self, cr, uid, context=None):
""" Gives default department by checking if present in the context """
department_id = self._resolve_department_id_from_context(cr, uid, context=context)
search_domain = []
if department_id:
- search_domain += ['|', '&', ('department_id', '=', department_id), ('fold', '=', False)]
- search_domain += ['|', ('id', 'in', ids), '&', ('department_id', '=', False), ('fold', '=', False)]
+ search_domain += ['|', ('department_id', '=', department_id)]
+ search_domain += ['|', ('id', 'in', ids), ('department_id', '=', False)]
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)
# restore order of the search
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
- return result
+
+ fold = {}
+ for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context):
+ fold[stage.id] = stage.fold or False
+ return result, fold
def _compute_day(self, cr, uid, ids, fields, args, context=None):
"""
date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
date_open = datetime.strptime(issue.date_open, "%Y-%m-%d %H:%M:%S")
ans = date_open - date_create
- date_until = issue.date_open
elif field in ['day_close']:
if issue.date_closed:
date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
date_close = datetime.strptime(issue.date_closed, "%Y-%m-%d %H:%M:%S")
- date_until = issue.date_closed
ans = date_close - date_create
if ans:
duration = float(ans.days)
'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',
- domain="['|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
+ domain="['&', ('fold', '=', False), '|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
'state': fields.related('stage_id', 'state', type="selection", store=True,
- selection=AVAILABLE_STATES, string="State", readonly=True,
- help='The state is set to \'Draft\', when a case is created.\
- If the case is in progress the state is set to \'Open\'.\
- When the case is over, the state is set to \'Done\'.\
- If the case needs to be reviewed then the state is \
+ selection=AVAILABLE_STATES, string="Status", readonly=True,
+ help='The status is set to \'Draft\', when a case is created.\
+ If the case is in progress the status is set to \'Open\'.\
+ When the case is over, the status is set to \'Done\'.\
+ If the case needs to be reviewed then the status is \
set to \'Pending\'.'),
+ 'categ_ids': fields.many2many('hr.applicant_category', string='Tags'),
'company_id': fields.many2one('res.company', 'Company'),
'user_id': fields.many2one('res.users', 'Responsible'),
# Applicant Columns
multi='day_close', type="float", store=True),
'color': fields.integer('Color Index'),
'emp_id': fields.many2one('hr.employee', 'employee'),
- 'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True),
+ 'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
}
_defaults = {
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
'department_id': lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c),
- 'priority': lambda *a: '',
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.applicant', context=c),
'color': 0,
}
_group_by_full = {
'stage_id': _read_group_stage_ids
}
-
- def onchange_stage_id(self, cr, uid, ids, stage_id, context={}):
- if context is None:
- context = {}
- if not stage_id:
- return {'value':{}}
- stage = self.pool.get('hr.recruitment.stage').browse(cr, uid, stage_id, context)
- if stage.state == 'done':
- context['onchange'] = True
- self.case_close_with_emp(cr, uid, ids, context)
- if stage.state == "draft":
- return {'value':{'active': True,'date_open': False, 'date_closed': False}}
- if stage.state == "open":
- cases = self.browse(cr, uid, ids, context=context)
- data = {'active': True}
- for case in cases:
- if case.stage_id and case.stage_id.state == 'draft':
- data['date_open'] = fields.datetime.now()
- if not case.user_id:
- data['user_id'] = uid
- return {'value':data}
- return {'value':{}}
-
- def onchange_job(self,cr, uid, ids, job, context=None):
+
+ def onchange_job(self, cr, uid, ids, job, context=None):
result = {}
if job:
res['context'] = {
'default_partner_ids': applicant.partner_id and [applicant.partner_id.id] or False,
'default_user_id': uid,
- 'default_state': 'open',
'default_name': applicant.name,
'default_categ_ids': category and [category.id] or False,
}
This override updates the document according to the email.
"""
if custom_values is None: custom_values = {}
+ desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
- 'description': msg.get('body_text'),
+ 'description': desc,
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
})
if msg.get('priority'):
custom_values['priority'] = msg.get('priority')
- custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
return super(hr_applicant,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
if isinstance(ids, (str, int, long)):
ids = [ids]
if update_vals is None: vals = {}
-
+
update_vals.update({
'description': msg.get('body'),
'email_from': msg.get('from'),
'revenue': 'planned_revenue',
'probability': 'probability',
}
- for line in msg.get('body_text', '').split('\n'):
+ for line in msg.get('body', '').split('\n'):
line = line.strip()
res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower(), False):
for applicant in self.browse(cr, uid, ids, context=context):
address_id = False
if applicant.partner_id:
- address_id = applicant.partner_id.address_get(['contact'])['contact']
+ address_id = self.pool.get('res.partner').address_get(cr,uid,[applicant.partner_id.id],['contact'])['contact']
if applicant.job_id:
applicant.job_id.write({'no_of_recruitment': applicant.job_id.no_of_recruitment - 1})
emp_id = hr_employee.create(cr,uid,{'name': applicant.partner_name or applicant.name,
'address_home_id': address_id,
'department_id': applicant.department_id.id
})
- if context.get('onchange'):
- return {'value':{'emp_id': emp_id,'active': True, 'date_closed': fields.datetime.now()}}
- else:
- self.write(cr, uid, [applicant.id], {'emp_id': emp_id}, context=context)
- self.case_close(cr, uid, [applicant.id], context)
+ self.write(cr, uid, [applicant.id], {'emp_id': emp_id}, context=context)
+ self.case_close(cr, uid, [applicant.id], context)
else:
raise osv.except_osv(_('Warning!'),_('You must define Applied Job for this applicant.'))
# OpenChatter methods and notifications
# -------------------------------------------------------
- def message_get_subscribers(self, cr, uid, ids, context=None):
- """ Override to add responsible user. """
- user_ids = super(hr_applicant, self).message_get_subscribers(cr, uid, ids, context=context)
- for obj in self.browse(cr, uid, ids, context=context):
- if obj.user_id and not obj.user_id.id in user_ids:
- user_ids.append(obj.user_id.id)
- return user_ids
-
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """
if not stage_id: return True
stage_name = self.pool.get('hr.recruitment.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
- return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
+ return self.message_post(cr, uid, ids, body=_("Stage changed to <b>%s</b>.") % (stage_name), context=context)
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
return 'Applicant'
def case_open_send_note(self, cr, uid, ids, context=None):
message = _("Applicant has been set <b>in progress</b>.")
- return self.message_append_note(cr, uid, ids, body=message, context=context)
+ return self.message_post(cr, uid, ids, body=message, context=context)
def case_close_send_note(self, cr, uid, ids, context=None):
if context is None:
context = {}
for applicant in self.browse(cr, uid, ids, context=context):
+ if applicant.job_id:
+ self.pool.get('hr.job').message_post(cr, uid, [applicant.job_id.id], body=_('New employee joined the company %s.')%(applicant.name,), subtype="hr_recruitment.mt_hired", context=context)
if applicant.emp_id:
message = _("Applicant has been <b>hired</b> and created as an employee.")
- self.message_append_note(cr, uid, [applicant.id], body=message, context=context)
+ self.message_post(cr, uid, [applicant.id], body=message, context=context)
else:
message = _("Applicant has been <b>hired</b>.")
- self.message_append_note(cr, uid, [applicant.id], body=message, context=context)
+ self.message_post(cr, uid, [applicant.id], body=message, context=context)
return True
def case_cancel_send_note(self, cr, uid, ids, context=None):
msg = 'Applicant <b>refused</b>.'
- return self.message_append_note(cr, uid, ids, body=msg, context=context)
+ return self.message_post(cr, uid, ids, body=msg, context=context)
def case_reset_send_note(self, cr, uid, ids, context=None):
message =_("Applicant has been set as <b>new</b>.")
- return self.message_append_note(cr, uid, ids, body=message, context=context)
+ return self.message_post(cr, uid, ids, body=message, context=context)
def create_send_note(self, cr, uid, ids, context=None):
message = _("Applicant has been <b>created</b>.")
- return self.message_append_note(cr, uid, ids, body=message, context=context)
-
+ for applicant in self.browse(cr, uid, ids, context=context):
+ if applicant.job_id:
+ self.pool.get('hr.job').message_post(cr, uid, [applicant.job_id.id], body=message, subtype="hr_recruitment.mt_applicant_new", context=context)
+ return self.message_post(cr, uid, ids, body=message, context=context)
class hr_job(osv.osv):
_inherit = "hr.job"
_name = "hr.job"
+ _inherits = {'mail.alias': 'alias_id'}
_columns = {
'survey_id': fields.many2one('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="cascade", required=True,
+ help="Email alias for this job position. New emails will automatically "
+ "create new applicants for this job position."),
}
-
+ _defaults = {
+ 'alias_domain': False, # always hide alias during creation
+ }
+
+ def _auto_init(self, cr, context=None):
+ """Installation hook to create aliases for all jobs and avoid constraint errors."""
+ self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(hr_job,self)._auto_init,
+ self._columns['alias_id'], 'name', alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=context)
+
+ def create(self, cr, uid, vals, context=None):
+ mail_alias = self.pool.get('mail.alias')
+ if not vals.get('alias_id'):
+ vals.pop('alias_name', None) # prevent errors during copy()
+ alias_id = mail_alias.create_unique_alias(cr, uid,
+ # Using '+' allows using subaddressing for those who don't
+ # have a catchall domain setup.
+ {'alias_name': 'jobs+'+vals['name']},
+ model_name="hr.applicant",
+ context=context)
+ vals['alias_id'] = alias_id
+ res = super(hr_job, self).create(cr, uid, vals, context)
+ mail_alias.write(cr, uid, [vals['alias_id']], {"alias_defaults": {'job_id': res}}, context)
+ return res
+
+ 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
+
def action_print_survey(self, cr, uid, ids, context=None):
if context is None:
context = {}
datas['model'] = 'survey.print'
context.update({'response_id': [0], 'response_no': 0,})
return {
- 'type': 'ir.actions.report.xml',
- 'report_name': 'survey.form',
- 'datas': datas,
- 'context' : context,
- 'nodestroy':True,
- }
+ 'type': 'ir.actions.report.xml',
+ 'report_name': 'survey.form',
+ 'datas': datas,
+ 'context' : context,
+ 'nodestroy':True,
+ }
+
+class applicant_category(osv.osv):
+ """ Category of applicant """
+ _name = "hr.applicant_category"
+ _description = "Category of applicant"
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True, translate=True),
+ }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: