improve_hr_evaluation
[odoo/odoo.git] / addons / hr_evaluation / hr_evaluation.py
1 # -*- encoding: 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 import time
23 from osv import fields, osv
24 from mx import DateTime as dt
25 import tools
26 from tools.translate import _
27
28 class hr_evaluation_plan(osv.osv):
29     _name = "hr_evaluation.plan"
30     _description = "Evaluation Plan"
31     _columns = {
32         'name': fields.char("Evaluation Plan", size=64, required=True),
33         'company_id': fields.many2one('res.company', 'Company', required=True),
34         'phase_ids' : fields.one2many('hr_evaluation.plan.phase', 'plan_id', 'Evaluation Phases'),
35         'month_first': fields.integer('First Evaluation After'),
36         'month_next': fields.integer('Next Evaluation After'),
37         'active': fields.boolean('Active')
38     }
39     _defaults = {
40         'active' : lambda *a: True,
41     }
42 hr_evaluation_plan()
43
44 class hr_evaluation_plan_phase(osv.osv):
45     _name = "hr_evaluation.plan.phase"
46     _description = "Evaluation Plan Phase"
47     _order = "sequence"
48     _columns = {
49         'name': fields.char("Phase", size=64, required=True),
50         'sequence': fields.integer("Sequence"),
51         'company_id': fields.related('plan_id','company_id',type='many2one',relation='res.company',string='Company',store=True),
52         'plan_id': fields.many2one('hr_evaluation.plan','Evaluation Plan', required=True, ondelete='cascade'),
53         'action': fields.selection([
54             ('top-down','Top-Down Appraisal Requests'),
55             ('bottom-up','Bottom-Up Appraisal Requests'),
56             ('self','Self Appraisal Requests'),
57             ('final','Final Interview')], 'Action', required=True),
58         'survey_id': fields.many2one('survey','Appraisal Form',required=True),
59         'send_answer_manager': fields.boolean('All Answers',
60             help="Send all answers to the manager"),
61         'send_answer_employee': fields.boolean('All Answers',
62             help="Send all answers to the employee"),
63         'send_anonymous_manager': fields.boolean('Anonymous Summary',
64             help="Send an anonymous summary to the manager"),
65         'send_anonymous_employee': fields.boolean('Anonymous Summary',
66             help="Send an anonymous summary to the employee"),
67         'wait': fields.boolean('Wait Previous Phases',
68             help="Check this box if you want to wait that all preceeding phases " +
69               "are finished before launching this phase.")
70
71     }
72     _defaults = {
73         'sequence' : lambda *a: 1,
74     }
75 hr_evaluation_plan_phase()
76
77 class hr_employee(osv.osv):
78     _inherit="hr.employee"
79     _columns = {
80         'evaluation_plan_id': fields.many2one('hr_evaluation.plan', 'Evaluation Plan'),
81         'evaluation_date': fields.date('Next Evaluation', help="Date of the next evaluation"),
82     }
83
84     def onchange_evaluation_plan_id(self,cr,uid,ids,evaluation_plan_id,context={}):
85         evaluation_date = self.browse(cr, uid, ids)[0].evaluation_date or ''
86         evaluation_plan_obj=self.pool.get('hr_evaluation.plan')
87         if evaluation_plan_id:
88             for evaluation_plan in evaluation_plan_obj.browse(cr,uid,[evaluation_plan_id]):
89                 if not evaluation_date:
90                    evaluation_date=(dt.ISO.ParseAny(dt.now().strftime('%Y-%m-%d'))+ dt.RelativeDateTime(months=+evaluation_plan.month_first)).strftime('%Y-%m-%d')
91                 else:
92                    evaluation_date=(dt.ISO.ParseAny(evaluation_date)+ dt.RelativeDateTime(months=+evaluation_plan.month_next)).strftime('%Y-%m-%d')
93         return {'value': {'evaluation_date':evaluation_date}}
94 hr_employee()
95
96 class hr_evaluation(osv.osv):
97     _name = "hr_evaluation.evaluation"
98     _description = "Employee Evaluation"
99     _rec_name = 'employee_id'
100     _columns = {
101         'date': fields.date("Evaluation Deadline", required=True),
102         'employee_id': fields.many2one('hr.employee', "Employee", required=True),
103         'note_summary': fields.text('Evaluation Summary'),
104         'note_action': fields.text('Action Plan',
105             help="If the evaluation does not meet the expectations, you can propose"+
106               "an action plan"),
107         'rating': fields.selection([
108             ('0','Significantly bellow expectations'),
109             ('1','Did not meet expectations'),
110             ('2','Meet expectations'),
111             ('3','Exceeds expectations'),
112             ('4','Significantly exceeds expectations'),
113         ], "Overall Rating", help="This is the overall rating on that summarize the evaluation"),
114         'survey_request_ids': fields.one2many('hr.evaluation.interview','evaluation_id','Appraisal Forms'),
115         'plan_id': fields.many2one('hr_evaluation.plan', 'Plan', required=True),
116         'state': fields.selection([
117             ('draft','Draft'),
118             ('wait','Plan In Progress'),
119             ('progress','Final Validation'),
120             ('done','Done'),
121             ('cancel','Cancelled'),
122         ], 'State', required=True,readonly=True),
123         'date_close': fields.date('Ending Date'),
124         'progress' : fields.float("Progress"),
125     }
126     _defaults = {
127         'date' : lambda *a: (dt.ISO.ParseAny(dt.now().strftime('%Y-%m-%d')) + dt.RelativeDateTime(months =+ 1)).strftime('%Y-%m-%d'),
128         'state' : lambda *a: 'draft',
129     }
130
131     def onchange_employee_id(self,cr,uid,ids,employee_id,context={}):
132         employee_obj=self.pool.get('hr.employee')
133         evaluation_plan_id=''
134         if employee_id:
135             for employee in employee_obj.browse(cr,uid,[employee_id]):
136                 if employee and employee.evaluation_plan_id and employee.evaluation_plan_id.id:
137                     evaluation_plan_id=employee.evaluation_plan_id.id
138                 employee_ids=employee_obj.search(cr,uid,[('parent_id','=',employee.id)])
139         return {'value': {'plan_id':evaluation_plan_id}}
140
141     def button_plan_in_progress(self,cr, uid, ids, context):
142         employee_obj = self.pool.get('hr.employee')
143         hr_eval_inter_obj = self.pool.get('hr.evaluation.interview')
144         survey_request_obj = self.pool.get('survey.request')
145         curr_employee=self.browse(cr,uid, ids)[0].employee_id
146         child_employees=employee_obj.browse(cr,uid, employee_obj.search(cr,uid,[('parent_id','=',curr_employee.id)]))
147         manager_employee=curr_employee.parent_id
148         for evaluation in self.browse(cr,uid,ids):
149             if evaluation and evaluation.plan_id:
150                 apprai_id = []
151                 for phase in evaluation.plan_id.phase_ids:
152                     if phase.action == "bottom-up":
153                         for child in child_employees:
154                             if child.user_id:
155                                 user = child.user_id.id
156                             id = hr_eval_inter_obj.create(cr, uid, {'evaluation_id':evaluation.id ,'user_id' : user,'survey_id' : phase.survey_id.id, 'user_to_review_id' : child.id, 'date_deadline' :(dt.ISO.ParseAny(dt.now().strftime('%Y-%m-%d')) + dt.RelativeDateTime(months =+ 1)).strftime('%Y-%m-%d')})
157                             if not phase.wait:
158                                 hr_eval_inter_obj.survey_req_waiting_answer(cr, uid, [id], context)
159                             apprai_id.append(id)
160                     elif phase.action == "top-down":
161                         if manager_employee:
162                             user = False
163                             if manager_employee.user_id:
164                                 user = manager_employee.user_id.id
165                             id = hr_eval_inter_obj.create(cr, uid, {'evaluation_id':evaluation.id,'user_id': user ,'survey_id' : phase.survey_id.id, 'user_to_review_id' :manager_employee.id, 'date_deadline' :(dt.ISO.ParseAny(dt.now().strftime('%Y-%m-%d')) + dt.RelativeDateTime(months =+ 1)).strftime('%Y-%m-%d')})
166                             if not phase.wait:
167                                 hr_eval_inter_obj.survey_req_waiting_answer(cr, uid, [id], context)
168                             apprai_id.append(id)
169                     elif phase.action == "self":
170                         if curr_employee:
171                             user = False
172                             if curr_employee.user_id:
173                                 user = curr_employee.user_id.id
174                             id = hr_eval_inter_obj.create(cr, uid, {'evaluation_id':evaluation.id,'user_id' : user, 'survey_id' : phase.survey_id.id, 'user_to_review_id' :curr_employee.id, 'date_deadline' :(dt.ISO.ParseAny(dt.now().strftime('%Y-%m-%d')) + dt.RelativeDateTime(months =+ 1)).strftime('%Y-%m-%d')})
175                             if not phase.wait:
176                                 hr_eval_inter_obj.survey_req_waiting_answer(cr, uid, [id], context)
177                             apprai_id.append(id)
178                     elif phase.action == "final":
179                         if manager_employee:
180                             user = False
181                             if manager_employee.user_id:
182                                 user = manager_employee.user_id.id
183                             id = hr_eval_inter_obj.create(cr, uid, {'evaluation_id':evaluation.id,'user_id' : user, 'survey_id' : phase.survey_id.id, 'user_to_review_id' :manager_employee.id, 'date_deadline' :(dt.ISO.ParseAny(dt.now().strftime('%Y-%m-%d')) + dt.RelativeDateTime(months =+ 1)).strftime('%Y-%m-%d')})
184                             if not phase.wait:
185                                 hr_eval_inter_obj.survey_req_waiting_answer(cr, uid, [id], context)
186                             apprai_id.append(id)
187                 self.write(cr, uid, evaluation.id, {'survey_request_ids':[[6, 0, apprai_id]]})
188         self.write(cr,uid,ids,{'state':'wait'})
189         return True
190
191     def button_final_validation(self,cr, uid, ids, context):
192         self.write(cr,uid,ids,{'state':'progress'})
193         request_obj = self.pool.get('hr.evaluation.interview')
194         for id in self.browse(cr, uid ,ids):
195             if len(id.survey_request_ids) != len(request_obj.search(cr, uid, [('evaluation_id', '=', id.id),('state', '=', 'done')])):
196                 raise osv.except_osv(_('Warning !'),_("You cannot change state, because some appraisal in waiting answer or draft state"))
197         return True
198
199     def button_done(self,cr, uid, ids, context):
200         self.write(cr,uid,ids,{'state':'done', 'date_close': time.strftime('%Y-%m-%d')})
201         return True
202
203     def button_cancel(self,cr, uid, ids, context):
204         self.write(cr,uid,ids,{'state':'cancel'})
205         return True
206
207 hr_evaluation()
208
209 class survey_request(osv.osv):
210     _inherit="survey.request"
211     _columns = {
212         'is_evaluation':fields.boolean('Is Evaluation?'),
213     }
214 survey_request()
215
216 class hr_evaluation_interview(osv.osv):
217     _name='hr.evaluation.interview'
218     _inherits={'survey.request':'request_id'}
219     _description='Evaluation Interview'
220     _columns = {
221
222         'request_id': fields.many2one('survey.request','Request_id', ondelete='cascade'),
223         'user_to_review_id': fields.many2one('hr.employee', 'Employee'),
224         'evaluation_id' : fields.many2one('hr_evaluation.evaluation', 'Evaluation'),
225         }
226     _defaults = {
227         'is_evaluation': lambda *a: True,
228         }
229
230     def survey_req_waiting_answer(self, cr, uid, ids, context):
231         self.write(cr, uid, ids, { 'state' : 'waiting_answer'})
232 #        for id in self.browse(cr, uid, ids):
233 #            if id.user_id and id.user_id.address_id and id.user_id.address_id and id.user_id.address_id.email:
234 #                msg = " Hello %s, \n\n We are inviting you for %s survey. \n\n Thanks,"  %(id.user_id.name, id.survey_id.title)
235 #                tools.email_send(tools.config['email_from'], [id.user_id.address_id.email],\
236 #                                              'Invite to fill up Survey', msg)
237         return True
238
239     def survey_req_done(self, cr, uid, ids, context):
240         self.write(cr, uid, ids, { 'state' : 'done'})
241         hr_eval_obj = self.pool.get('hr_evaluation.evaluation')
242         for id in self.browse(cr, uid, ids):
243             flag = False
244             wating_id = 0
245             tot_done_req = 0
246             records = self.pool.get("hr_evaluation.evaluation").browse(cr, uid, [id.evaluation_id.id])[0].survey_request_ids
247             for child in records:
248                 if child.state == "draft" :
249                     wating_id = child.id
250                     continue
251                 if child.state != "done":
252                     flag = True
253                 else :
254                     tot_done_req += 1
255             if not flag and wating_id:
256                 self.survey_req_waiting_answer(cr, uid, [wating_id], context)
257             hr_eval_obj.write(cr, uid, [id.evaluation_id.id], {'progress' :tot_done_req * 100 / len(records)})
258
259         return True
260     def survey_req_draft(self, cr, uid, ids, arg):
261         self.write(cr, uid, ids, { 'state' : 'draft'})
262         return True
263
264     def survey_req_cancel(self, cr, uid, ids, context):
265         self.write(cr, uid, ids, { 'state' : 'cancel'})
266         return True
267
268 hr_evaluation_interview()