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):
189 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': False}}
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 attachents = msg.get('attachments', [])
336 for attactment in attachents or []:
339 'datas':binascii.b2a_base64(str(attachents.get(attactment))),
340 'datas_fname': attactment,
341 'description': 'Mail attachment',
342 'res_model': self._name,
345 attach_obj.create(cr, uid, data_attach, context=context)
349 def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context=None):
351 @param self: The object pointer
352 @param cr: the current row, from the database cursor,
353 @param uid: the current user’s ID for security checks,
354 @param ids: List of update mail’s IDs
359 if isinstance(ids, (str, int, long)):
362 msg_from = msg['from']
364 'description': msg['body']
366 if msg.get('priority', False):
367 vals['priority'] = msg.get('priority')
370 'cost':'planned_cost',
371 'revenue': 'planned_revenue',
372 'probability':'probability'
375 for line in msg['body'].split('\n'):
377 res = tools.misc.command_re.match(line)
378 if res and maps.get(res.group(1).lower(), False):
379 key = maps.get(res.group(1).lower())
380 vls[key] = res.group(2).lower()
383 res = self.write(cr, uid, ids, vals, context=context)
386 def msg_send(self, cr, uid, id, *args, **argv):
388 @param self: The object pointer
389 @param cr: the current row, from the database cursor,
390 @param uid: the current user’s ID for security checks,
391 @param ids: List of email’s IDs
392 @param *args: Return Tuple Value
393 @param **args: Return Dictionary of Keyword Value
397 def case_open(self, cr, uid, ids, *args):
399 @param self: The object pointer
400 @param cr: the current row, from the database cursor,
401 @param uid: the current user’s ID for security checks,
402 @param ids: List of case's Ids
403 @param *args: Give Tuple Value
405 res = super(hr_applicant, self).case_open(cr, uid, ids, *args)
406 date = self.read(cr, uid, ids, ['date_open'])[0]
407 if not date['date_open']:
408 self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'),})
409 for (id, name) in self.name_get(cr, uid, ids):
410 message = _("The job request '%s' has been set 'in progress'.") % name
411 self.log(cr, uid, id, message)
414 def case_close(self, cr, uid, ids, *args):
416 @param self: The object pointer
417 @param cr: the current row, from the database cursor,
418 @param uid: the current user’s ID for security checks,
419 @param ids: List of case's Ids
420 @param *args: Give Tuple Value
422 employee_obj = self.pool.get('hr.employee')
423 job_obj = self.pool.get('hr.job')
424 res = super(hr_applicant, self).case_close(cr, uid, ids, *args)
425 for (id, name) in self.name_get(cr, uid, ids):
426 message = _("Applicant '%s' is being hired.") % name
427 self.log(cr, uid, id, message)
429 applicant = self.browse(cr, uid, ids)[0]
431 emp_id = employee_obj.create(cr,uid,{'name': applicant.name,'job_id': applicant.job_id.id})
434 def case_reset(self, cr, uid, ids, *args):
435 """Resets case as draft
436 @param self: The object pointer
437 @param cr: the current row, from the database cursor,
438 @param uid: the current user’s ID for security checks,
439 @param ids: List of case Ids
440 @param *args: Tuple Value for additional Params
443 res = super(hr_applicant, self).case_reset(cr, uid, ids, *args)
444 self.write(cr, uid, ids, {'date_open': False, 'date_closed': False})
450 class hr_job(osv.osv):
454 'survey_id': fields.many2one('survey', 'Survey'),
458 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: