1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
23 from datetime import datetime, timedelta
25 from osv import fields, osv
31 from tools.translate import _
35 ('open', 'In Progress'),
36 ('cancel', 'Refused'),
38 ('pending', 'Pending')
41 AVAILABLE_PRIORITIES = [
49 class hr_recruitment_stage(osv.osv):
50 """ Stage of HR Recruitment """
51 _name = "hr.recruitment.stage"
52 _description = "Stage of Recruitment"
55 'name': fields.char('Name', size=64, required=True, translate=True),
56 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."),
57 'department_id':fields.many2one('hr.department', 'Department'),
58 'requirements': fields.text('Requirements')
63 hr_recruitment_stage()
65 class hr_recruitment_degree(osv.osv):
66 """ Degree of HR Recruitment """
67 _name = "hr.recruitment.degree"
68 _description = "Degree of Recruitment"
70 'name': fields.char('Name', size=64, required=True, translate=True),
71 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of degrees."),
76 hr_recruitment_degree()
78 class hr_applicant(crm.crm_case, osv.osv):
79 _name = "hr.applicant"
80 _description = "Applicant"
82 _inherit = ['mailgate.thread']
84 def _compute_day(self, cr, uid, ids, fields, args, context=None):
88 @param cr: the current row, from the database cursor,
89 @param uid: the current user’s ID for security checks,
90 @param ids: List of Openday’s IDs
91 @return: difference between current date and log date
92 @param context: A standard dictionary for contextual values
95 for issue in self.browse(cr, uid, ids, context=context):
102 if field in ['day_open']:
104 date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
105 date_open = datetime.strptime(issue.date_open, "%Y-%m-%d %H:%M:%S")
106 ans = date_open - date_create
107 date_until = issue.date_open
109 elif field in ['day_close']:
110 if issue.date_closed:
111 date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
112 date_close = datetime.strptime(issue.date_closed, "%Y-%m-%d %H:%M:%S")
113 date_until = issue.date_closed
114 ans = date_close - date_create
116 duration = float(ans.days)
117 res[issue.id][field] = abs(float(duration))
121 'name': fields.char('Name', size=128, required=True),
122 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
123 'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the case without removing it."),
124 'description': fields.text('Description'),
125 'email_from': fields.char('Email', size=128, help="These people will receive email."),
126 '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"),
127 'probability': fields.float('Probability'),
128 'partner_id': fields.many2one('res.partner', 'Partner'),
129 'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
130 domain="[('partner_id','=',partner_id)]"),
131 'create_date': fields.datetime('Creation Date' , readonly=True),
132 'write_date': fields.datetime('Update Date' , readonly=True),
133 'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage'),
134 'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True,
135 help='The state is set to \'Draft\', when a case is created.\
136 \nIf the case is in progress the state is set to \'Open\'.\
137 \nWhen the case is over, the state is set to \'Done\'.\
138 \nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
139 'company_id': fields.many2one('res.company', 'Company'),
140 'user_id': fields.many2one('res.users', 'Responsible'),
142 'date_closed': fields.datetime('Closed', readonly=True),
143 'date_open': fields.datetime('Opened', readonly=True),
144 'date': fields.datetime('Date'),
145 'date_action': fields.date('Next Action Date'),
146 'title_action': fields.char('Next Action', size=64),
147 'priority': fields.selection(AVAILABLE_PRIORITIES, 'Appreciation'),
148 'job_id': fields.many2one('hr.job', 'Applied Job'),
149 'salary_proposed': fields.float('Proposed Salary', help="Salary Proposed by the Organisation"),
150 'salary_expected': fields.float('Expected Salary', help="Salary Expected by Applicant"),
151 'availability': fields.integer('Availability (Days)'),
152 'partner_name': fields.char("Applicant's Name", size=64),
153 'partner_phone': fields.char('Phone', size=32),
154 'partner_mobile': fields.char('Mobile', size=32),
155 'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
156 'department_id':fields.many2one('hr.department', 'Department'),
157 'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True),
158 'survey' : fields.related('job_id', 'survey_id', type='many2one', relation='survey', string='Survey'),
159 'response' : fields.integer("Response"),
160 'reference': fields.char('Reference', size=128),
161 'day_open': fields.function(_compute_day, string='Days to Open', \
162 method=True, multi='day_open', type="float", store=True),
163 'day_close': fields.function(_compute_day, string='Days to Close', \
164 method=True, multi='day_close', type="float", store=True),
167 def _get_stage(self, cr, uid, context=None):
170 ids = self.pool.get('hr.recruitment.stage').search(cr, uid, [], context=context)
171 return ids and ids[0] or False
174 'active': lambda *a: 1,
175 'stage_id': _get_stage,
176 'user_id': lambda self, cr, uid, context: uid,
177 'email_from': crm.crm_case. _get_default_email,
178 'state': lambda *a: 'draft',
179 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
180 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
183 def onchange_job(self,cr, uid, ids, job, context=None):
184 job_obj = self.pool.get('hr.job')
190 result['department_id'] = job_obj.browse(cr, uid, job, context=context).department_id.id
191 return {'value': result}
192 return {'value': {'department_id': []}}
194 def stage_previous(self, cr, uid, ids, context=None):
195 """This function computes previous stage for case from its current stage
196 using available stage for that case type
197 @param self: The object pointer
198 @param cr: the current row, from the database cursor,
199 @param uid: the current user’s ID for security checks,
200 @param ids: List of case IDs
201 @param context: A standard dictionary for contextual values"""
202 stage_obj = self.pool.get('hr.recruitment.stage')
205 for case in self.browse(cr, uid, ids, context=context):
206 department = (case.department_id.id or False)
207 st = case.stage_id.id or False
208 stage_ids = stage_obj.search(cr, uid, ['|',('department_id','=',department),('department_id','=',False)], context=context)
209 if st and stage_ids.index(st):
210 self.write(cr, uid, [case.id], {'stage_id': stage_ids[stage_ids.index(st)-1]}, context=context)
213 def stage_next(self, cr, uid, ids, context=None):
214 """This function computes next stage for case from its current stage
215 using available stage for that case type
216 @param self: The object pointer
217 @param cr: the current row, from the database cursor,
218 @param uid: the current user’s ID for security checks,
219 @param ids: List of case IDs
220 @param context: A standard dictionary for contextual values"""
221 stage_obj = self.pool.get('hr.recruitment.stage')
224 for case in self.browse(cr, uid, ids, context=context):
225 department = (case.department_id.id or False)
226 st = case.stage_id.id or False
227 stage_ids = stage_obj.search(cr, uid, ['|',('department_id','=',department),('department_id','=',False)], context=context)
228 if st and len(stage_ids) != stage_ids.index(st)+1:
229 self.write(cr, uid, [case.id], {'stage_id': stage_ids[stage_ids.index(st)+1]}, context=context)
232 def action_makeMeeting(self, cr, uid, ids, context=None):
234 This opens Meeting's calendar view to schedule meeting on current Opportunity
235 @param self: The object pointer
236 @param cr: the current row, from the database cursor,
237 @param uid: the current user’s ID for security checks,
238 @param ids: List of Opportunity to Meeting IDs
239 @param context: A standard dictionary for contextual values
241 @return : Dictionary value for created Meeting view
243 data_obj = self.pool.get('ir.model.data')
247 for opp in self.browse(cr, uid, ids, context=context):
249 result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
250 res = data_obj.read(cr, uid, result, ['res_id'], context=context)
251 id1 = data_obj._get_id(cr, uid, 'crm', 'crm_case_calendar_view_meet')
252 id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_meet')
253 id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_meet')
255 id1 = data_obj.browse(cr, uid, id1, context=context).res_id
257 id2 = data_obj.browse(cr, uid, id2, context=context).res_id
259 id3 = data_obj.browse(cr, uid, id3, context=context).res_id
262 'default_opportunity_id': opp.id,
263 'default_partner_id': opp.partner_id and opp.partner_id.id or False,
264 'default_email_from': opp.email_from,
265 'default_state': 'open',
266 'default_name': opp.name
269 'name': ('Meetings'),
270 'domain': "[('user_id','=',%s)]" % (uid),
273 'view_mode': 'calendar,form,tree',
274 'res_model': 'crm.meeting',
276 'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
277 'type': 'ir.actions.act_window',
278 'search_view_id': res['res_id'],
283 def action_print_survey(self, cr, uid, ids, context=None):
285 If response is available then print this response otherwise print survey form(print template of the survey).
287 @param self: The object pointer
288 @param cr: the current row, from the database cursor,
289 @param uid: the current user’s ID for security checks,
290 @param ids: List of Survey IDs
291 @param context: A standard dictionary for contextual values
292 @return : Dictionary value for print survey form.
296 record = self.browse(cr, uid, ids, context=context)
297 record = record and record[0]
298 context.update({'survey_id': record.survey.id, 'response_id' : [record.response], 'response_no':0, })
299 value = self.pool.get("survey").action_print_survey(cr, uid, ids, context)
302 def message_new(self, cr, uid, msg, context=None):
304 Automatically calls when new email message arrives
306 @param self: The object pointer
307 @param cr: the current row, from the database cursor,
308 @param uid: the current user’s ID for security checks
310 mailgate_pool = self.pool.get('email.server.tools')
311 attach_obj = self.pool.get('ir.attachment')
315 subject = msg.get('subject')
316 body = msg.get('body')
317 msg_from = msg.get('from')
318 priority = msg.get('priority')
322 'email_from': msg_from,
323 'email_cc': msg.get('cc'),
327 if msg.get('priority', False):
328 vals['priority'] = priority
330 res = mailgate_pool.get_partner(cr, uid, msg.get('from'))
333 res = self.create(cr, uid, vals, context=context)
335 message = _('A Job Request created') + " '" + subject + "' " + _("from Mailgate.")
336 self.log(cr, uid, res, message)
338 attachents = msg.get('attachments', [])
339 for attactment in attachents or []:
342 'datas':binascii.b2a_base64(str(attachents.get(attactment))),
343 'datas_fname': attactment,
344 'description': 'Mail attachment',
345 'res_model': self._name,
348 attach_obj.create(cr, uid, data_attach, context=context)
352 def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context=None):
354 @param self: The object pointer
355 @param cr: the current row, from the database cursor,
356 @param uid: the current user’s ID for security checks,
357 @param ids: List of update mail’s IDs
362 if isinstance(ids, (str, int, long)):
365 msg_from = msg['from']
367 'description': msg['body']
369 if msg.get('priority', False):
370 vals['priority'] = msg.get('priority')
373 'cost':'planned_cost',
374 'revenue': 'planned_revenue',
375 'probability':'probability'
378 for line in msg['body'].split('\n'):
380 res = tools.misc.command_re.match(line)
381 if res and maps.get(res.group(1).lower(), False):
382 key = maps.get(res.group(1).lower())
383 vls[key] = res.group(2).lower()
386 res = self.write(cr, uid, ids, vals, context=context)
389 def msg_send(self, cr, uid, id, *args, **argv):
391 @param self: The object pointer
392 @param cr: the current row, from the database cursor,
393 @param uid: the current user’s ID for security checks,
394 @param ids: List of email’s IDs
395 @param *args: Return Tuple Value
396 @param **args: Return Dictionary of Keyword Value
400 def case_open(self, cr, uid, ids, *args):
402 @param self: The object pointer
403 @param cr: the current row, from the database cursor,
404 @param uid: the current user’s ID for security checks,
405 @param ids: List of case's Ids
406 @param *args: Give Tuple Value
408 res = super(hr_applicant, self).case_open(cr, uid, ids, *args)
409 date = self.read(cr, uid, ids, ['date_open'])[0]
410 if not date['date_open']:
411 self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'),})
412 for (id, name) in self.name_get(cr, uid, ids):
413 message = _('Job request for') + " '" + name + "' "+ _("is Open.")
414 self.log(cr, uid, id, message)
417 def case_close(self, cr, uid, ids, *args):
419 @param self: The object pointer
420 @param cr: the current row, from the database cursor,
421 @param uid: the current user’s ID for security checks,
422 @param ids: List of case's Ids
423 @param *args: Give Tuple Value
425 employee_obj = self.pool.get('hr.employee')
426 job_obj = self.pool.get('hr.job')
427 res = super(hr_applicant, self).case_close(cr, uid, ids, *args)
428 for (id, name) in self.name_get(cr, uid, ids):
429 message = _('Applicant ') + " '" + name + "' "+ _("is Hired.")
430 self.log(cr, uid, id, message)
432 stage_id = self.pool.get('hr.recruitment.stage').search(cr, uid, [('name','=','Contract Signed')])
433 self.write(cr, uid, ids,{'stage_id':stage_id[0]})
435 applicant = self.browse(cr, uid, ids)[0]
436 if applicant.job_id :
437 emp_id = employee_obj.create(cr,uid,{'name':applicant.name,'job_id':applicant.job_id.id})
438 job_data = job_obj.browse(cr,uid, applicant.job_id.id)
439 expected_emp = job_data['expected_employees'] - 1
440 job_obj.write(cr,uid, [applicant.job_id.id],{'expected_employees':expected_emp})
444 def case_reset(self, cr, uid, ids, *args):
445 """Resets case as draft
446 @param self: The object pointer
447 @param cr: the current row, from the database cursor,
448 @param uid: the current user’s ID for security checks,
449 @param ids: List of case Ids
450 @param *args: Tuple Value for additional Params
452 res = super(hr_applicant, self).case_reset(cr, uid, ids, *args)
453 self.write(cr, uid, ids, {'date_open': False, 'date_closed':False})
459 class hr_job(osv.osv):
463 'survey_id': fields.many2one('survey', 'Survey'),
467 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: