[FIX] Mail alias unlink suport for the inheriting mdoels
[odoo/odoo.git] / addons / hr_recruitment / hr_recruitment.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
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.
11 #
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.
16 #
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/>.
19 #
20 ##############################################################################
21
22 from base_status.base_stage import base_stage
23 import time
24 from datetime import datetime, timedelta
25 from lxml import etree
26 from osv import fields, osv
27 from crm import crm
28 import tools
29 import collections
30 import binascii
31 import tools
32 from tools.translate import _
33 from crm import wizard
34
35 wizard.mail_compose_message.SUPPORTED_MODELS.append('hr.applicant')
36
37 AVAILABLE_STATES = [
38     ('draft', 'New'),
39     ('cancel', 'Refused'),
40     ('open', 'In Progress'),
41     ('pending', 'Pending'),
42     ('done', 'Hired')
43 ]
44
45 AVAILABLE_PRIORITIES = [
46     ('', ''),
47     ('5', 'Not Good'),
48     ('4', 'On Average'),
49     ('3', 'Good'),
50     ('2', 'Very Good'),
51     ('1', 'Excellent')
52 ]
53
54 class hr_recruitment_source(osv.osv):
55     """ Sources of HR Recruitment """
56     _name = "hr.recruitment.source"
57     _description = "Source of Applicants"
58     _columns = {
59         'name': fields.char('Source Name', size=64, required=True, translate=True),
60     }
61
62 class hr_recruitment_stage(osv.osv):
63     """ Stage of HR Recruitment """
64     _name = "hr.recruitment.stage"
65     _description = "Stage of Recruitment"
66     _order = 'sequence'
67     _columns = {
68         'name': fields.char('Name', size=64, required=True, translate=True),
69         'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."),
70         '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 tempy this field."),
71         'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."),
72         '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."),
73         'requirements': fields.text('Requirements'),
74     }
75     _defaults = {
76         'sequence': 1,
77         'state': 'draft',
78         'fold': False,
79     }
80
81 class hr_recruitment_degree(osv.osv):
82     """ Degree of HR Recruitment """
83     _name = "hr.recruitment.degree"
84     _description = "Degree of Recruitment"
85     _columns = {
86         'name': fields.char('Name', size=64, required=True, translate=True),
87         'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of degrees."),
88     }
89     _defaults = {
90         'sequence': 1,
91     }
92     _sql_constraints = [
93         ('name_uniq', 'unique (name)', 'The name of the Degree of Recruitment must be unique!')
94     ]
95
96 class hr_applicant(base_stage, osv.Model):
97     _name = "hr.applicant"
98     _description = "Applicant"
99     _order = "id desc"
100     _inherit = ['ir.needaction_mixin', 'mail.thread']
101
102     def _get_default_department_id(self, cr, uid, context=None):
103         """ Gives default department by checking if present in the context """
104         return (self._resolve_department_id_from_context(cr, uid, context=context) or False)
105
106     def _get_default_stage_id(self, cr, uid, context=None):
107         """ Gives default stage_id """
108         department_id = self._get_default_department_id(cr, uid, context=context)
109         return self.stage_find(cr, uid, [], department_id, [('state', '=', 'draft')], context=context)
110
111     def _resolve_department_id_from_context(self, cr, uid, context=None):
112         """ Returns ID of department based on the value of 'default_department_id'
113             context key, or None if it cannot be resolved to a single
114             department.
115         """
116         if context is None:
117             context = {}
118         if type(context.get('default_department_id')) in (int, long):
119             return context.get('default_department_id')
120         if isinstance(context.get('default_department_id'), basestring):
121             department_name = context['default_department_id']
122             department_ids = self.pool.get('hr.department').name_search(cr, uid, name=department_name, context=context)
123             if len(department_ids) == 1:
124                 return int(department_ids[0][0])
125         return None
126
127     def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
128         access_rights_uid = access_rights_uid or uid
129         stage_obj = self.pool.get('hr.recruitment.stage')
130         order = stage_obj._order
131         # lame hack to allow reverting search, should just work in the trivial case
132         if read_group_order == 'stage_id desc':
133             order = "%s desc" % order
134         # retrieve section_id from the context and write the domain
135         # - ('id', 'in', 'ids'): add columns that should be present
136         # - OR ('department_id', '=', False), ('fold', '=', False): add default columns that are not folded
137         # - OR ('department_id', 'in', department_id), ('fold', '=', False) if department_id: add department columns that are not folded
138         department_id = self._resolve_department_id_from_context(cr, uid, context=context)
139         search_domain = []
140         if department_id:
141             search_domain += ['|', '&', ('department_id', '=', department_id), ('fold', '=', False)]
142         search_domain += ['|', ('id', 'in', ids), '&', ('department_id', '=', False), ('fold', '=', False)]
143         stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
144         result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
145         # restore order of the search
146         result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
147         return result
148
149     def _compute_day(self, cr, uid, ids, fields, args, context=None):
150         """
151         @param cr: the current row, from the database cursor,
152         @param uid: the current user’s ID for security checks,
153         @param ids: List of Openday’s IDs
154         @return: difference between current date and log date
155         @param context: A standard dictionary for contextual values
156         """
157         res = {}
158         for issue in self.browse(cr, uid, ids, context=context):
159             for field in fields:
160                 res[issue.id] = {}
161                 duration = 0
162                 ans = False
163                 hours = 0
164
165                 if field in ['day_open']:
166                     if issue.date_open:
167                         date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
168                         date_open = datetime.strptime(issue.date_open, "%Y-%m-%d %H:%M:%S")
169                         ans = date_open - date_create
170                         date_until = issue.date_open
171
172                 elif field in ['day_close']:
173                     if issue.date_closed:
174                         date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
175                         date_close = datetime.strptime(issue.date_closed, "%Y-%m-%d %H:%M:%S")
176                         date_until = issue.date_closed
177                         ans = date_close - date_create
178                 if ans:
179                     duration = float(ans.days)
180                     res[issue.id][field] = abs(float(duration))
181         return res
182
183     _columns = {
184         'name': fields.char('Name', size=128, required=True),
185         'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the case without removing it."),
186         'description': fields.text('Description'),
187         'email_from': fields.char('Email', size=128, help="These people will receive email."),
188         '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"),
189         'probability': fields.float('Probability'),
190         'partner_id': fields.many2one('res.partner', 'Contact'),
191         'create_date': fields.datetime('Creation Date', readonly=True, select=True),
192         'write_date': fields.datetime('Update Date', readonly=True),
193         'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage',
194                         domain="['|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
195         'state': fields.related('stage_id', 'state', type="selection", store=True,
196                 selection=AVAILABLE_STATES, string="State", readonly=True,
197                 help='The state is set to \'Draft\', when a case is created.\
198                       If the case is in progress the state is set to \'Open\'.\
199                       When the case is over, the state is set to \'Done\'.\
200                       If the case needs to be reviewed then the state is \
201                       set to \'Pending\'.'),
202         'company_id': fields.many2one('res.company', 'Company'),
203         'user_id': fields.many2one('res.users', 'Responsible'),
204         # Applicant Columns
205         'date_closed': fields.datetime('Closed', readonly=True, select=True),
206         'date_open': fields.datetime('Opened', readonly=True, select=True),
207         'date': fields.datetime('Date'),
208         'date_action': fields.date('Next Action Date'),
209         'title_action': fields.char('Next Action', size=64),
210         'priority': fields.selection(AVAILABLE_PRIORITIES, 'Appreciation'),
211         'job_id': fields.many2one('hr.job', 'Applied Job'),
212         'salary_proposed_extra': fields.char('Proposed Salary Extra', size=100, help="Salary Proposed by the Organisation, extra advantages"),
213         'salary_expected_extra': fields.char('Expected Salary Extra', size=100, help="Salary Expected by Applicant, extra advantages"),
214         'salary_proposed': fields.float('Proposed Salary', help="Salary Proposed by the Organisation"),
215         'salary_expected': fields.float('Expected Salary', help="Salary Expected by Applicant"),
216         'availability': fields.integer('Availability (Days)'),
217         'partner_name': fields.char("Applicant's Name", size=64),
218         'partner_phone': fields.char('Phone', size=32),
219         'partner_mobile': fields.char('Mobile', size=32),
220         'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
221         'department_id': fields.many2one('hr.department', 'Department'),
222         'survey': fields.related('job_id', 'survey_id', type='many2one', relation='survey', string='Survey'),
223         'response': fields.integer("Response"),
224         'reference': fields.char('Referred By', size=128),
225         'source_id': fields.many2one('hr.recruitment.source', 'Source'),
226         'day_open': fields.function(_compute_day, string='Days to Open', \
227                                 multi='day_open', type="float", store=True),
228         'day_close': fields.function(_compute_day, string='Days to Close', \
229                                 multi='day_close', type="float", store=True),
230         'color': fields.integer('Color Index'),
231         'emp_id': fields.many2one('hr.employee', 'employee'),
232         'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True),
233     }
234
235     _defaults = {
236         'active': lambda *a: 1,
237         'user_id':  lambda s, cr, uid, c: uid,
238         'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
239         'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
240         'department_id': lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c),
241         'priority': lambda *a: '',
242         'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
243         'color': 0,
244     }
245
246     _group_by_full = {
247         'stage_id': _read_group_stage_ids
248     }
249
250     def onchange_job(self,cr, uid, ids, job, context=None):
251         result = {}
252
253         if job:
254             job_obj = self.pool.get('hr.job')
255             result['department_id'] = job_obj.browse(cr, uid, job, context=context).department_id.id
256             return {'value': result}
257         return {'value': {'department_id': False}}
258
259     def onchange_department_id(self, cr, uid, ids, department_id=False, context=None):
260         if not department_id:
261             return {'value': {'stage_id': False}}
262         obj_recru_stage = self.pool.get('hr.recruitment.stage')
263         stage_ids = obj_recru_stage.search(cr, uid, ['|',('department_id','=',department_id),('department_id','=',False)], context=context)
264         stage_id = stage_ids and stage_ids[0] or False
265         return {'value': {'stage_id': stage_id}}
266
267     def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
268         """ Override of the base.stage method
269             Parameter of the stage search taken from the lead:
270             - department_id: if set, stages must belong to this section or
271               be a default case
272         """
273         if isinstance(cases, (int, long)):
274             cases = self.browse(cr, uid, cases, context=context)
275         # collect all section_ids
276         department_ids = []
277         if section_id:
278             department_ids.append(section_id)
279         for case in cases:
280             if case.department_id:
281                 department_ids.append(case.department_id.id)
282         # OR all section_ids and OR with case_default
283         search_domain = []
284         if department_ids:
285             search_domain += ['|', ('department_id', 'in', department_ids)]
286         search_domain.append(('department_id', '=', False))
287         # AND with the domain in parameter
288         search_domain += list(domain)
289         # perform search, return the first found
290         stage_ids = self.pool.get('hr.recruitment.stage').search(cr, uid, search_domain, order=order, context=context)
291         if stage_ids:
292             return stage_ids[0]
293         return False
294
295     def action_makeMeeting(self, cr, uid, ids, context=None):
296         """
297         This opens Meeting's calendar view to schedule meeting on current Opportunity
298         @param self: The object pointer
299         @param cr: the current row, from the database cursor,
300         @param uid: the current user’s ID for security checks,
301         @param ids: List of Opportunity to Meeting IDs
302         @param context: A standard dictionary for contextual values
303
304         @return: Dictionary value for created Meeting view
305         """
306         data_obj = self.pool.get('ir.model.data')
307         if context is None:
308             context = {}
309         value = {}
310         for opp in self.browse(cr, uid, ids, context=context):
311             # Get meeting views
312             search_view = data_obj.get_object(cr, uid, 'crm', 'view_crm_case_meetings_filter', context)
313             calendar_view = data_obj.get_object(cr, uid, 'crm', 'crm_case_calendar_view_meet', context)
314             form_view = data_obj.get_object(cr, uid, 'crm', 'crm_case_form_view_meet', context)
315             tree_view = data_obj.get_object(cr, uid, 'crm', 'crm_case_tree_view_meet', context)
316             category = data_obj.get_object(cr, uid, 'hr_recruitment', 'categ_meet_interview', context)
317             context.update({
318                 'default_applicant_id': opp.id,
319                 'default_partner_id': opp.partner_id and opp.partner_id.id or False,
320                 'default_email_from': opp.email_from,
321                 'default_state': 'open',
322                 'default_categ_id': category.id,
323                 'default_name': opp.name,
324             })
325             value = {
326                 'name': ('Meetings'),
327                 'domain': "[('user_id','=',%s)]" % (uid),
328                 'context': context,
329                 'view_type': 'form',
330                 'view_mode': 'calendar,form,tree',
331                 'res_model': 'crm.meeting',
332                 'view_id': False,
333                 'views': [(calendar_view.id, 'calendar'), (form_view.id, 'form'), (tree_view.id, 'tree')],
334                 'type': 'ir.actions.act_window',
335                 'search_view_id': search_view.id,
336                 'nodestroy': True,
337             }
338         return value
339
340     def action_print_survey(self, cr, uid, ids, context=None):
341         """
342         If response is available then print this response otherwise print survey form(print template of the survey).
343
344         @param self: The object pointer
345         @param cr: the current row, from the database cursor,
346         @param uid: the current user’s ID for security checks,
347         @param ids: List of Survey IDs
348         @param context: A standard dictionary for contextual values
349         @return: Dictionary value for print survey form.
350         """
351         if context is None:
352             context = {}
353         record = self.browse(cr, uid, ids, context=context)
354         record = record and record[0]
355         context.update({'survey_id': record.survey.id, 'response_id': [record.response], 'response_no': 0, })
356         value = self.pool.get("survey").action_print_survey(cr, uid, ids, context=context)
357         return value
358
359     def message_new(self, cr, uid, msg, custom_values=None, context=None):
360         """ Overrides mail_thread message_new that is called by the mailgateway
361             through message_process.
362             This override updates the document according to the email.
363         """
364         if custom_values is None: custom_values = {}
365         custom_values.update({
366             'name':  msg.get('subject') or _("No Subject"),
367             'description': msg.get('body_text'),
368             'email_from': msg.get('from'),
369             'email_cc': msg.get('cc'),
370             'user_id': False,
371         })
372         if msg.get('priority'):
373             custom_values['priority'] = msg.get('priority')
374         custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
375         return super(hr_applicant,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
376
377     def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
378         """ Override mail_thread message_update that is called by the mailgateway
379             through message_process.
380             This method updates the document according to the email.
381         """
382         if isinstance(ids, (str, int, long)):
383             ids = [ids]
384         if update_vals is None: vals = {}
385         
386         update_vals.update({
387             'description': msg.get('body'),
388             'email_from': msg.get('from'),
389             'email_cc': msg.get('cc'),
390         })
391         if msg.get('priority'):
392             update_vals['priority'] = msg.get('priority')
393
394         maps = {
395             'cost': 'planned_cost',
396             'revenue': 'planned_revenue',
397             'probability': 'probability',
398         }
399         for line in msg.get('body_text', '').split('\n'):
400             line = line.strip()
401             res = tools.misc.command_re.match(line)
402             if res and maps.get(res.group(1).lower(), False):
403                 key = maps.get(res.group(1).lower())
404                 update_vals[key] = res.group(2).lower()
405
406         return super(hr_applicant, self).message_update(cr, uids, ids, update_vals=update_vals, context=context)
407
408     def create(self, cr, uid, vals, context=None):
409         obj_id = super(hr_applicant, self).create(cr, uid, vals, context=context)
410         self.create_send_note(cr, uid, [obj_id], context=context)
411         return obj_id
412
413     def case_open(self, cr, uid, ids, context=None):
414         """
415             open Request of the applicant for the hr_recruitment
416         """
417         res = super(hr_applicant, self).case_open(cr, uid, ids, context)
418         date = self.read(cr, uid, ids, ['date_open'])[0]
419         if not date['date_open']:
420             self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'),})
421         return res
422
423     def case_close(self, cr, uid, ids, context=None):
424         res = super(hr_applicant, self).case_close(cr, uid, ids, context)
425         return res
426
427     def case_close_with_emp(self, cr, uid, ids, context=None):
428         if context is None:
429             context = {}
430         hr_employee = self.pool.get('hr.employee')
431         model_data = self.pool.get('ir.model.data')
432         act_window = self.pool.get('ir.actions.act_window')
433         emp_id = False
434         for applicant in self.browse(cr, uid, ids, context=context):
435             address_id = False
436             if applicant.partner_id:
437                 address_id = applicant.partner_id.address_get(['contact'])['contact']
438             if applicant.job_id:
439                 applicant.job_id.write({'no_of_recruitment': applicant.job_id.no_of_recruitment - 1})
440                 emp_id = hr_employee.create(cr,uid,{'name': applicant.partner_name or applicant.name,
441                                                      'job_id': applicant.job_id.id,
442                                                      'address_home_id': address_id,
443                                                      'department_id': applicant.department_id.id
444                                                      })
445                 self.write(cr, uid, [applicant.id], {'emp_id': emp_id}, context=context)
446                 self.case_close(cr, uid, [applicant.id], context)
447             else:
448                 raise osv.except_osv(_('Warning!'),_('You must define Applied Job for this applicant.'))
449
450         action_model, action_id = model_data.get_object_reference(cr, uid, 'hr', 'open_view_employee_list')
451         dict_act_window = act_window.read(cr, uid, action_id, [])
452         if emp_id:
453             dict_act_window['res_id'] = emp_id
454         dict_act_window['view_mode'] = 'form,tree'
455         return dict_act_window
456
457     def case_cancel(self, cr, uid, ids, context=None):
458         """Overrides cancel for crm_case for setting probability
459         """
460         res = super(hr_applicant, self).case_cancel(cr, uid, ids, context)
461         self.write(cr, uid, ids, {'probability' : 0.0})
462         return res
463
464     def case_pending(self, cr, uid, ids, context=None):
465         """Marks case as pending"""
466         res = super(hr_applicant, self).case_pending(cr, uid, ids, context)
467         self.write(cr, uid, ids, {'probability' : 0.0})
468         return res
469
470     def case_reset(self, cr, uid, ids, context=None):
471         """Resets case as draft
472         """
473         res = super(hr_applicant, self).case_reset(cr, uid, ids, context)
474         self.write(cr, uid, ids, {'date_open': False, 'date_closed': False})
475         return res
476
477     def set_priority(self, cr, uid, ids, priority, *args):
478         """Set applicant priority
479         """
480         return self.write(cr, uid, ids, {'priority' : priority})
481
482     def set_high_priority(self, cr, uid, ids, *args):
483         """Set applicant priority to high
484         """
485         return self.set_priority(cr, uid, ids, '1')
486
487     def set_normal_priority(self, cr, uid, ids, *args):
488         """Set applicant priority to normal
489         """
490         return self.set_priority(cr, uid, ids, '3')
491
492     # -------------------------------------------------------
493     # OpenChatter methods and notifications
494     # -------------------------------------------------------
495
496     def message_get_subscribers(self, cr, uid, ids, context=None):
497         """ Override to add responsible user. """
498         user_ids = super(hr_applicant, self).message_get_subscribers(cr, uid, ids, context=context)
499         for obj in self.browse(cr, uid, ids, context=context):
500             if obj.user_id and not obj.user_id.id in user_ids:
501                 user_ids.append(obj.user_id.id)
502         return user_ids
503
504     def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
505         """ Override of the (void) default notification method. """
506         if not stage_id: return True
507         stage_name = self.pool.get('hr.recruitment.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
508         return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
509
510     def case_get_note_msg_prefix(self, cr, uid, id, context=None):
511                 return 'Applicant'
512
513     def case_open_send_note(self, cr, uid, ids, context=None):
514         message = _("Applicant has been set <b>in progress</b>.")
515         return self.message_append_note(cr, uid, ids, body=message, context=context)
516
517     def case_close_send_note(self, cr, uid, ids, context=None):
518         if context is None:
519             context = {}
520         for applicant in self.browse(cr, uid, ids, context=context):
521             if applicant.emp_id:
522                 message = _("Applicant has been <b>hired</b> and created as an employee.")
523                 self.message_append_note(cr, uid, [applicant.id], body=message, context=context)
524             else:
525                 message = _("Applicant has been <b>hired</b>.")
526                 self.message_append_note(cr, uid, [applicant.id], body=message, context=context)
527         return True
528
529     def case_cancel_send_note(self, cr, uid, ids, context=None):
530         msg = 'Applicant <b>refused</b>.'
531         return self.message_append_note(cr, uid, ids, body=msg, context=context)
532
533     def case_reset_send_note(self,  cr, uid, ids, context=None):
534         message =_("Applicant has been set as <b>new</b>.")
535         return self.message_append_note(cr, uid, ids, body=message, context=context)
536
537     def create_send_note(self, cr, uid, ids, context=None):
538         message = _("Applicant has been <b>created</b>.")
539         return self.message_append_note(cr, uid, ids, body=message, context=context)
540
541
542 class hr_job(osv.osv):
543     _inherit = "hr.job"
544     _name = "hr.job"
545     _inherits = {'mail.alias': 'alias_id'}
546     _columns = {
547         '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"),
548         'alias_id': fields.many2one('mail.alias', 'Mail Alias', ondelete="cascade", required=True, 
549                                     help="This Unique Mail Box Alias of the Job allows to manage the Seamless email communication between Mail Box and OpenERP,"
550                                          "This Alias MailBox also create and Manage the new Email applicant for this job and also manage the existing applicant email communication."),
551     }
552     
553     def create(self, cr, uid, vals, context=None):
554         alias_pool = self.pool.get('mail.alias')
555         if not vals.get('alias_id'):
556             name = vals.get('alias_name') or vals['name']
557             alias_id = alias_pool.create_unique_alias(cr, uid, 
558                     {'alias_name': "job_"+name, 
559                     'alias_model_id': "hr.applicant"}, context=context)
560             alias = alias_pool.read(cr, uid, alias_id, ['alias_name'],context)
561             vals.update({'alias_id': alias_id, 'alias_name': alias['alias_name']})
562         res = super( hr_job, self).create(cr, uid, vals, context)
563         alias_pool.write(cr, uid, [vals['alias_id']], {"alias_defaults": {'job_id': res}}, context)
564         return res
565
566     def unlink(self, cr, uid, ids, context=None):
567         #Will extract the linked Mail Alias 'alias_id' and unlink it explictly.
568         alias_pool = self.pool.get('mail.alias')
569         alias_ids =[record.alias_id.id for record in self.browse(cr, uid, ids, context=context) if record.alias_id]
570         res = super(hr_job, self).unlink(cr, uid, ids, context=context)
571         alias_pool.unlink(cr, uid, alias_ids, context=context)
572         return res
573     
574     def action_print_survey(self, cr, uid, ids, context=None):
575         if context is None:
576             context = {}
577         datas = {}
578         record = self.browse(cr, uid, ids, context=context)[0]
579         if record.survey_id:
580             datas['ids'] = [record.survey_id.id]
581         datas['model'] = 'survey.print'
582         context.update({'response_id': [0], 'response_no': 0,})
583         return {
584                 'type': 'ir.actions.report.xml',
585                 'report_name': 'survey.form',
586                 'datas': datas,
587                 'context' : context,
588                 'nodestroy':True,
589             }
590
591
592 class crm_meeting(osv.osv):
593     _inherit = 'crm.meeting'
594     _columns = {
595         'applicant_id': fields.many2one('hr.applicant','Applicant'),
596     }
597
598 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: