2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2008-08-24 14:45:43 +00:00
##################################################################################
#
2010-02-17 08:49:38 +00:00
# Copyright (c) 2005-2006 Axelor SARL. (http://www.axelor.com)
2010-01-12 09:18:39 +00:00
# and 2004-2010 Tiny SPRL (<http://tiny.be>).
2008-08-24 14:45:43 +00:00
#
# $Id: hr.py 4656 2006-11-24 09:58:42Z Cyp $
#
2009-10-14 11:15:34 +00:00
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2008-08-24 14:45:43 +00:00
#
2009-10-14 11:15:34 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
2008-08-24 14:45:43 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2008-08-24 14:45:43 +00:00
#
##############################################################################
2010-07-03 10:21:52 +00:00
2011-12-22 14:24:02 +00:00
import datetime , time
2010-09-22 08:23:53 +00:00
from itertools import groupby
from operator import itemgetter
2010-05-04 11:19:18 +00:00
2012-07-31 09:02:41 +00:00
import math
2008-08-24 14:45:43 +00:00
import netsvc
2012-11-05 17:03:18 +00:00
import tools
2008-08-24 14:45:43 +00:00
from osv import fields , osv
2009-03-06 22:18:24 +00:00
from tools . translate import _
2008-08-24 14:45:43 +00:00
2010-09-22 08:23:53 +00:00
2008-08-30 11:45:40 +00:00
class hr_holidays_status ( osv . osv ) :
_name = " hr.holidays.status "
2010-05-19 18:32:32 +00:00
_description = " Leave Type "
2010-05-04 11:19:18 +00:00
2010-05-26 10:19:25 +00:00
def get_days ( self , cr , uid , ids , employee_id , return_false , context = None ) :
2010-09-22 08:23:53 +00:00
cr . execute ( """ SELECT id, type, number_of_days, holiday_status_id FROM hr_holidays WHERE employee_id = %s AND state= ' validate ' AND holiday_status_id in %s """ ,
[ employee_id , tuple ( ids ) ] )
result = sorted ( cr . dictfetchall ( ) , key = lambda x : x [ ' holiday_status_id ' ] )
grouped_lines = dict ( ( k , [ v for v in itr ] ) for k , itr in groupby ( result , itemgetter ( ' holiday_status_id ' ) ) )
2009-09-24 10:46:21 +00:00
res = { }
2010-05-21 06:46:54 +00:00
for record in self . browse ( cr , uid , ids , context = context ) :
2009-09-24 10:46:21 +00:00
res [ record . id ] = { }
max_leaves = leaves_taken = 0
if not return_false :
2010-09-22 08:23:53 +00:00
if record . id in grouped_lines :
leaves_taken = - sum ( [ item [ ' number_of_days ' ] for item in grouped_lines [ record . id ] if item [ ' type ' ] == ' remove ' ] )
max_leaves = sum ( [ item [ ' number_of_days ' ] for item in grouped_lines [ record . id ] if item [ ' type ' ] == ' add ' ] )
2009-09-24 10:46:21 +00:00
res [ record . id ] [ ' max_leaves ' ] = max_leaves
res [ record . id ] [ ' leaves_taken ' ] = leaves_taken
res [ record . id ] [ ' remaining_leaves ' ] = max_leaves - leaves_taken
return res
2009-03-13 06:25:53 +00:00
2010-05-26 10:19:25 +00:00
def _user_left_days ( self , cr , uid , ids , name , args , context = None ) :
2009-09-24 10:46:21 +00:00
return_false = False
2010-04-16 13:05:03 +00:00
employee_id = False
res = { }
2009-09-24 10:46:21 +00:00
if context and context . has_key ( ' employee_id ' ) :
if not context [ ' employee_id ' ] :
2010-01-12 05:32:48 +00:00
return_false = True
2009-09-24 10:46:21 +00:00
employee_id = context [ ' employee_id ' ]
else :
2010-07-27 07:11:45 +00:00
employee_ids = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] , context = context )
2009-09-24 10:46:21 +00:00
if employee_ids :
employee_id = employee_ids [ 0 ]
else :
return_false = True
2010-03-17 17:09:26 +00:00
if employee_id :
res = self . get_days ( cr , uid , ids , employee_id , return_false , context = context )
2010-05-14 14:46:47 +00:00
else :
2010-08-02 10:31:53 +00:00
res = dict . fromkeys ( ids , { ' leaves_taken ' : 0 , ' remaining_leaves ' : 0 , ' max_leaves ' : 0 } )
2009-09-24 10:46:21 +00:00
return res
2009-03-13 06:25:53 +00:00
_columns = {
2010-10-12 21:59:40 +00:00
' name ' : fields . char ( ' Leave Type ' , size = 64 , required = True , translate = True ) ,
2012-07-05 08:06:59 +00:00
' categ_id ' : fields . many2one ( ' crm.meeting.type ' , ' Meeting Type ' ,
help = ' Once a leave is validated, OpenERP will create a corresponding meeting of this type in the calendar. ' ) ,
2012-07-13 10:17:51 +00:00
' color_name ' : fields . selection ( [ ( ' red ' , ' Red ' ) , ( ' blue ' , ' Blue ' ) , ( ' lightgreen ' , ' Light Green ' ) , ( ' lightblue ' , ' Light Blue ' ) , ( ' lightyellow ' , ' Light Yellow ' ) , ( ' magenta ' , ' Magenta ' ) , ( ' lightcyan ' , ' Light Cyan ' ) , ( ' black ' , ' Black ' ) , ( ' lightpink ' , ' Light Pink ' ) , ( ' brown ' , ' Brown ' ) , ( ' violet ' , ' Violet ' ) , ( ' lightcoral ' , ' Light Coral ' ) , ( ' lightsalmon ' , ' Light Salmon ' ) , ( ' lavender ' , ' Lavender ' ) , ( ' wheat ' , ' Wheat ' ) , ( ' ivory ' , ' Ivory ' ) ] , ' Color in Report ' , required = True , help = ' This color will be used in the leaves summary located in Reporting \ Leaves by Department. ' ) ,
2012-06-13 14:26:05 +00:00
' limit ' : fields . boolean ( ' Allow to Override Limit ' , help = ' If you select this checkbox, the system allows the employees to take more leaves than the available ones for this type. ' ) ,
2010-05-04 11:19:18 +00:00
' active ' : fields . boolean ( ' Active ' , help = " If the active field is set to false, it will allow you to hide the leave type without removing it. " ) ,
2011-07-01 23:41:24 +00:00
' max_leaves ' : fields . function ( _user_left_days , string = ' Maximum Allowed ' , help = ' This value is given by the sum of all holidays requests with a positive value. ' , multi = ' user_left_days ' ) ,
' leaves_taken ' : fields . function ( _user_left_days , string = ' Leaves Already Taken ' , help = ' This value is given by the sum of all holidays requests with a negative value. ' , multi = ' user_left_days ' ) ,
' remaining_leaves ' : fields . function ( _user_left_days , string = ' Remaining Leaves ' , help = ' Maximum Leaves Allowed - Leaves Already Taken ' , multi = ' user_left_days ' ) ,
2012-06-13 14:26:05 +00:00
' double_validation ' : fields . boolean ( ' Apply Double Validation ' , help = " When selected, the Allocation/Leave Requests for this type require a second validation to be approved. " ) ,
2009-03-13 06:25:53 +00:00
}
_defaults = {
2010-05-04 11:19:18 +00:00
' color_name ' : ' red ' ,
' active ' : True ,
2010-08-26 04:52:04 +00:00
}
2009-09-24 10:46:21 +00:00
hr_holidays_status ( )
2009-03-13 06:25:53 +00:00
2008-08-24 14:45:43 +00:00
class hr_holidays ( osv . osv ) :
_name = " hr.holidays "
2010-05-19 18:32:32 +00:00
_description = " Leave "
2009-09-24 10:46:21 +00:00
_order = " type desc, date_from asc "
2012-08-22 15:31:45 +00:00
_inherit = [ ' mail.thread ' , ' ir.needaction_mixin ' ]
2009-09-24 10:46:21 +00:00
2011-06-20 06:04:34 +00:00
def _employee_get ( self , cr , uid , context = None ) :
ids = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] , context = context )
2010-05-10 04:56:49 +00:00
if ids :
return ids [ 0 ]
return False
2008-11-20 17:21:19 +00:00
2010-12-29 12:41:23 +00:00
def _compute_number_of_days ( self , cr , uid , ids , name , args , context = None ) :
result = { }
for hol in self . browse ( cr , uid , ids , context = context ) :
if hol . type == ' remove ' :
result [ hol . id ] = - hol . number_of_days_temp
else :
result [ hol . id ] = hol . number_of_days_temp
return result
2012-11-06 13:55:15 +00:00
def _check_date ( self , cr , uid , ids ) :
for holiday in self . browse ( cr , uid , ids ) :
holiday_ids = self . search ( cr , uid , [ ( ' date_from ' , ' <= ' , holiday . date_to ) , ( ' date_to ' , ' >= ' , holiday . date_from ) , ( ' employee_id ' , ' = ' , holiday . employee_id . id ) , ( ' id ' , ' <> ' , holiday . id ) ] )
if holiday_ids :
return False
return True
2008-08-24 14:45:43 +00:00
_columns = {
2012-08-01 12:40:44 +00:00
' name ' : fields . char ( ' Description ' , size = 64 ) ,
2012-05-23 06:53:42 +00:00
' state ' : fields . selection ( [ ( ' draft ' , ' To Submit ' ) , ( ' cancel ' , ' Cancelled ' ) , ( ' confirm ' , ' To Approve ' ) , ( ' refuse ' , ' Refused ' ) , ( ' validate1 ' , ' Second Approval ' ) , ( ' validate ' , ' Approved ' ) ] ,
2012-10-12 11:42:58 +00:00
' Status ' , readonly = True , help = ' The status is set to \' To Submit \' , when a holiday request is created. \
\nThe status is \' To Approve \' , when holiday request is confirmed by user. \
\nThe status is \' Refused \' , when holiday request is refused by manager. \
\nThe status is \' Approved \' , when holiday request is approved by manager. ' ) ,
2010-12-29 12:41:23 +00:00
' user_id ' : fields . related ( ' employee_id ' , ' user_id ' , type = ' many2one ' , relation = ' res.users ' , string = ' User ' , store = True ) ,
2012-02-22 13:06:38 +00:00
' date_from ' : fields . datetime ( ' Start Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } , select = True ) ,
' date_to ' : fields . datetime ( ' End Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } ) ,
' holiday_status_id ' : fields . many2one ( " hr.holidays.status " , " Leave Type " , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } ) ,
' employee_id ' : fields . many2one ( ' hr.employee ' , " Employee " , select = True , invisible = False , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } , help = ' Leave Manager can let this field empty if this leave request/allocation is for every employee ' ) ,
2011-04-19 05:44:51 +00:00
' manager_id ' : fields . many2one ( ' hr.employee ' , ' First Approval ' , invisible = False , readonly = True , help = ' This area is automatically filled by the user who validate the leave ' ) ,
2012-02-22 13:06:38 +00:00
' notes ' : fields . text ( ' Reasons ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } ) ,
' number_of_days_temp ' : fields . float ( ' Number of Days ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } ) ,
2011-07-01 23:41:24 +00:00
' number_of_days ' : fields . function ( _compute_number_of_days , string = ' Number of Days ' , store = True ) ,
2012-07-05 08:06:59 +00:00
' meeting_id ' : fields . many2one ( ' crm.meeting ' , ' Meeting ' ) ,
2012-02-22 13:06:38 +00:00
' type ' : fields . selection ( [ ( ' remove ' , ' Leave Request ' ) , ( ' add ' , ' Allocation Request ' ) ] , ' Request Type ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } , help = " Choose ' Leave Request ' if someone wants to take an off-day. \n Choose ' Allocation Request ' if you want to increase the number of leaves available for someone " , select = True ) ,
2009-09-24 10:46:21 +00:00
' parent_id ' : fields . many2one ( ' hr.holidays ' , ' Parent ' ) ,
' linked_request_ids ' : fields . one2many ( ' hr.holidays ' , ' parent_id ' , ' Linked Requests ' , ) ,
2010-04-07 10:41:20 +00:00
' department_id ' : fields . related ( ' employee_id ' , ' department_id ' , string = ' Department ' , type = ' many2one ' , relation = ' hr.department ' , readonly = True , store = True ) ,
2012-08-14 12:20:50 +00:00
' category_id ' : fields . many2one ( ' hr.employee.category ' , " Category " , help = ' Category of Employee ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } ) ,
' holiday_type ' : fields . selection ( [ ( ' employee ' , ' By Employee ' ) , ( ' category ' , ' By Employee Category ' ) ] , ' Allocation Mode ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirm ' : [ ( ' readonly ' , False ) ] } , help = ' By Employee: Allocation/Request for individual Employee, By Employee Category: Allocation/Request for group of employees in category ' , required = True ) ,
2011-06-01 05:19:41 +00:00
' manager_id2 ' : fields . many2one ( ' hr.employee ' , ' Second Approval ' , readonly = True , help = ' This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation) ' ) ,
' double_validation ' : fields . related ( ' holiday_status_id ' , ' double_validation ' , type = ' boolean ' , relation = ' hr.holidays.status ' , string = ' Apply Double Validation ' ) ,
2010-08-26 04:52:04 +00:00
}
2008-08-24 14:45:43 +00:00
_defaults = {
2010-10-27 12:49:59 +00:00
' employee_id ' : _employee_get ,
2010-07-03 10:21:52 +00:00
' state ' : ' draft ' ,
2010-05-04 11:19:18 +00:00
' type ' : ' remove ' ,
2008-11-20 17:21:19 +00:00
' user_id ' : lambda obj , cr , uid , context : uid ,
2010-05-05 12:18:58 +00:00
' holiday_type ' : ' employee '
2010-08-26 04:52:04 +00:00
}
2012-11-06 13:55:15 +00:00
_constraints = [
2012-11-08 09:24:51 +00:00
( _check_date , ' You can not have 2 leaves that overlaps on same day! ' , [ ' date_from ' , ' date_to ' ] ) ,
2012-11-06 13:55:15 +00:00
]
2010-12-29 12:41:23 +00:00
_sql_constraints = [
2012-08-31 14:42:44 +00:00
( ' type_value ' , " CHECK( (holiday_type= ' employee ' AND employee_id IS NOT NULL) or (holiday_type= ' category ' AND category_id IS NOT NULL)) " , " The employee or employee category of this request is missing. " ) ,
2012-10-31 18:00:53 +00:00
( ' date_check2 ' , " CHECK ( (type= ' add ' ) OR (date_from <= date_to)) " , " The start date must be anterior to the end date. " ) ,
( ' date_check ' , " CHECK ( number_of_days_temp >= 0 ) " , " The number of days must be greater than 0. " ) ,
2010-12-29 12:41:23 +00:00
]
2012-10-31 17:32:55 +00:00
2011-11-14 12:22:44 +00:00
def _create_resource_leave ( self , cr , uid , leaves , context = None ) :
2010-05-26 10:19:25 +00:00
''' This method will create entry in resource calendar leave object at the time of holidays validated '''
2010-05-26 09:54:56 +00:00
obj_res_leave = self . pool . get ( ' resource.calendar.leaves ' )
2011-11-14 12:22:44 +00:00
for leave in leaves :
vals = {
' name ' : leave . name ,
' date_from ' : leave . date_from ,
' holiday_id ' : leave . id ,
' date_to ' : leave . date_to ,
' resource_id ' : leave . employee_id . resource_id . id ,
' calendar_id ' : leave . employee_id . resource_id . calendar_id . id
}
obj_res_leave . create ( cr , uid , vals , context = context )
return True
2010-05-26 09:54:56 +00:00
2011-11-14 12:22:44 +00:00
def _remove_resource_leave ( self , cr , uid , ids , context = None ) :
2010-05-26 10:19:25 +00:00
''' This method will create entry in resource calendar leave object at the time of holidays cancel/removed '''
2010-05-26 09:54:56 +00:00
obj_res_leave = self . pool . get ( ' resource.calendar.leaves ' )
2010-07-27 07:11:45 +00:00
leave_ids = obj_res_leave . search ( cr , uid , [ ( ' holiday_id ' , ' in ' , ids ) ] , context = context )
2011-11-14 12:22:44 +00:00
return obj_res_leave . unlink ( cr , uid , leave_ids , context = context )
2010-05-26 09:54:56 +00:00
2010-05-10 04:56:49 +00:00
def onchange_type ( self , cr , uid , ids , holiday_type ) :
2011-04-26 06:41:16 +00:00
result = { ' value ' : { ' employee_id ' : False } }
2010-10-27 13:10:19 +00:00
if holiday_type == ' employee ' :
2010-05-10 04:56:49 +00:00
ids_employee = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
if ids_employee :
result [ ' value ' ] = {
' employee_id ' : ids_employee [ 0 ]
2010-12-29 12:41:23 +00:00
}
2010-05-10 04:56:49 +00:00
return result
2012-10-29 07:14:09 +00:00
def onchange_employee ( self , cr , uid , ids , employee_id ) :
result = { ' value ' : { ' department_id ' : False } }
if employee_id :
employee = self . pool . get ( ' hr.employee ' ) . browse ( cr , uid , employee_id )
result [ ' value ' ] = { ' department_id ' : employee . department_id . id }
return result
2010-12-29 12:41:23 +00:00
# TODO: can be improved using resource calendar method
2010-05-18 06:26:16 +00:00
def _get_number_of_days ( self , date_from , date_to ) :
2010-05-14 15:18:57 +00:00
""" Returns a float equals to the timedelta between two dates given as string. """
DATETIME_FORMAT = " % Y- % m- %d % H: % M: % S "
from_dt = datetime . datetime . strptime ( date_from , DATETIME_FORMAT )
to_dt = datetime . datetime . strptime ( date_to , DATETIME_FORMAT )
timedelta = to_dt - from_dt
2010-05-18 06:26:16 +00:00
diff_day = timedelta . days + float ( timedelta . seconds ) / 86400
2010-05-14 15:18:57 +00:00
return diff_day
2008-12-31 09:54:58 +00:00
2010-05-26 09:54:56 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2010-12-29 12:41:23 +00:00
for rec in self . browse ( cr , uid , ids , context = context ) :
2012-07-30 10:31:39 +00:00
if rec . state not in [ ' draft ' , ' cancel ' , ' confirm ' ] :
2012-10-31 18:00:53 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' You cannot delete a leave which is in %s state. ' ) % ( rec . state ) )
2010-01-05 08:07:22 +00:00
return super ( hr_holidays , self ) . unlink ( cr , uid , ids , context )
2008-12-31 09:54:58 +00:00
2012-10-31 18:00:53 +00:00
def onchange_date_from ( self , cr , uid , ids , date_to , date_from ) :
2012-11-05 13:32:29 +00:00
"""
If there are no date set for date_to , automatically set one 8 hours later than
the date_from .
Also update the number_of_days .
"""
# date_to has to be greater than date_from
if ( date_from and date_to ) and ( date_from > date_to ) :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' The start date must be anterior to the end date. ' ) )
result = { ' value ' : { } }
2012-10-31 18:00:53 +00:00
# No date_to set so far: automatically compute one 8 hours later
if date_from and not date_to :
2012-11-05 17:03:18 +00:00
date_to_with_delta = datetime . datetime . strptime ( date_from , tools . DEFAULT_SERVER_DATETIME_FORMAT ) + datetime . timedelta ( hours = 8 )
2012-11-05 13:32:29 +00:00
result [ ' value ' ] [ ' date_to ' ] = str ( date_to_with_delta )
# Compute and update the number of days
if ( date_to and date_from ) and ( date_from < = date_to ) :
diff_day = self . _get_number_of_days ( date_from , date_to )
result [ ' value ' ] [ ' number_of_days_temp ' ] = round ( math . floor ( diff_day ) ) + 1
else :
result [ ' value ' ] [ ' number_of_days_temp ' ] = 0
2012-10-31 18:00:53 +00:00
return result
2012-10-29 08:34:14 +00:00
def onchange_date_to ( self , cr , uid , ids , date_to , date_from ) :
2012-11-05 13:32:29 +00:00
"""
Update the number_of_days .
"""
# date_to has to be greater than date_from
if ( date_from and date_to ) and ( date_from > date_to ) :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' The start date must be anterior to the end date. ' ) )
result = { ' value ' : { } }
# Compute and update the number of days
if ( date_to and date_from ) and ( date_from < = date_to ) :
2010-05-14 15:18:57 +00:00
diff_day = self . _get_number_of_days ( date_from , date_to )
2012-11-05 13:32:29 +00:00
result [ ' value ' ] [ ' number_of_days_temp ' ] = round ( math . floor ( diff_day ) ) + 1
2012-10-31 18:00:53 +00:00
else :
2012-11-05 13:32:29 +00:00
result [ ' value ' ] [ ' number_of_days_temp ' ] = 0
2012-10-31 18:00:53 +00:00
2008-11-20 17:21:19 +00:00
return result
2012-11-06 13:20:25 +00:00
2012-11-06 15:26:44 +00:00
def write ( self , cr , uid , ids , vals , context = None ) :
2012-11-08 09:24:51 +00:00
check_fnct = self . pool . get ( ' hr.holidays.status ' ) . check_access_rights
2012-11-06 15:26:44 +00:00
for holiday in self . browse ( cr , uid , ids , context = context ) :
2012-11-08 09:24:51 +00:00
if holiday . state in ( ' validate ' , ' validate1 ' ) and not check_fnct ( cr , uid , ' write ' , raise_exception = False ) :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' You cannot modify a leave request that has been approved. Contact a human resource manager. ' ) )
return super ( hr_holidays , self ) . write ( cr , uid , ids , vals , context = context )
2008-11-20 17:21:19 +00:00
2011-07-05 07:11:51 +00:00
def set_to_draft ( self , cr , uid , ids , context = None ) :
2008-08-24 14:45:43 +00:00
self . write ( cr , uid , ids , {
2010-07-03 10:21:52 +00:00
' state ' : ' draft ' ,
2009-09-24 10:46:21 +00:00
' manager_id ' : False ,
2011-03-22 10:04:47 +00:00
' manager_id2 ' : False ,
2008-08-24 14:45:43 +00:00
} )
2010-12-29 12:41:23 +00:00
wf_service = netsvc . LocalService ( " workflow " )
2010-05-26 10:19:25 +00:00
for id in ids :
2011-04-18 09:20:07 +00:00
wf_service . trg_delete ( uid , ' hr.holidays ' , id , cr )
2010-05-26 10:19:25 +00:00
wf_service . trg_create ( uid , ' hr.holidays ' , id , cr )
2011-12-30 12:28:11 +00:00
to_unlink = [ ]
for record in self . browse ( cr , uid , ids , context = context ) :
for record2 in record . linked_request_ids :
self . set_to_draft ( cr , uid , [ record2 . id ] , context = context )
to_unlink . append ( record2 . id )
if to_unlink :
self . unlink ( cr , uid , to_unlink , context = context )
2008-08-24 14:45:43 +00:00
return True
2012-08-14 12:20:50 +00:00
def holidays_first_validate ( self , cr , uid , ids , context = None ) :
2011-06-28 11:46:33 +00:00
self . check_holidays ( cr , uid , ids , context = context )
2010-12-29 12:41:23 +00:00
obj_emp = self . pool . get ( ' hr.employee ' )
2010-12-09 05:50:40 +00:00
ids2 = obj_emp . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
2010-12-29 12:41:23 +00:00
manager = ids2 and ids2 [ 0 ] or False
2012-08-14 12:20:50 +00:00
self . holidays_first_validate_notificate ( cr , uid , ids , context = context )
2010-12-29 12:41:23 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' validate1 ' , ' manager_id ' : manager } )
2010-05-14 09:13:31 +00:00
2012-08-14 12:20:50 +00:00
def holidays_validate ( self , cr , uid , ids , context = None ) :
2011-06-28 11:46:33 +00:00
self . check_holidays ( cr , uid , ids , context = context )
2010-12-29 12:41:23 +00:00
obj_emp = self . pool . get ( ' hr.employee ' )
2010-07-03 10:21:52 +00:00
ids2 = obj_emp . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
2010-12-29 12:41:23 +00:00
manager = ids2 and ids2 [ 0 ] or False
2011-03-22 10:04:47 +00:00
self . write ( cr , uid , ids , { ' state ' : ' validate ' } )
2010-12-29 12:41:23 +00:00
data_holiday = self . browse ( cr , uid , ids )
2010-05-10 10:58:32 +00:00
for record in data_holiday :
2012-08-14 12:20:50 +00:00
if record . double_validation :
self . write ( cr , uid , [ record . id ] , { ' manager_id2 ' : manager } )
else :
self . write ( cr , uid , [ record . id ] , { ' manager_id ' : manager } )
2010-07-03 10:21:52 +00:00
if record . holiday_type == ' employee ' and record . type == ' remove ' :
2010-12-29 12:41:23 +00:00
meeting_obj = self . pool . get ( ' crm.meeting ' )
2012-07-05 08:06:59 +00:00
meeting_vals = {
2012-08-14 05:44:25 +00:00
' name ' : record . name or _ ( ' Leave Request ' ) ,
2012-07-14 16:04:03 +00:00
' categ_ids ' : record . holiday_status_id . categ_id and [ ( 6 , 0 , [ record . holiday_status_id . categ_id . id ] ) ] or [ ] ,
2010-12-29 12:41:23 +00:00
' duration ' : record . number_of_days_temp * 8 ,
2011-12-05 15:55:10 +00:00
' description ' : record . notes ,
2010-12-29 12:41:23 +00:00
' user_id ' : record . user_id . id ,
' date ' : record . date_from ,
' end_date ' : record . date_to ,
' date_deadline ' : record . date_to ,
2012-08-22 09:21:49 +00:00
' state ' : ' open ' , # to block that meeting date in the calendar
2010-12-29 12:41:23 +00:00
}
2012-07-05 08:06:59 +00:00
meeting_id = meeting_obj . create ( cr , uid , meeting_vals )
2011-11-14 12:22:44 +00:00
self . _create_resource_leave ( cr , uid , [ record ] , context = context )
2012-07-05 08:06:59 +00:00
self . write ( cr , uid , ids , { ' meeting_id ' : meeting_id } )
2010-12-20 09:45:13 +00:00
elif record . holiday_type == ' category ' :
2010-12-29 12:41:23 +00:00
emp_ids = obj_emp . search ( cr , uid , [ ( ' category_ids ' , ' child_of ' , [ record . category_id . id ] ) ] )
2010-12-20 09:45:13 +00:00
leave_ids = [ ]
2010-05-18 10:40:30 +00:00
for emp in obj_emp . browse ( cr , uid , emp_ids ) :
vals = {
2010-12-29 12:41:23 +00:00
' name ' : record . name ,
' type ' : record . type ,
' holiday_type ' : ' employee ' ,
' holiday_status_id ' : record . holiday_status_id . id ,
' date_from ' : record . date_from ,
' date_to ' : record . date_to ,
' notes ' : record . notes ,
' number_of_days_temp ' : record . number_of_days_temp ,
' parent_id ' : record . id ,
' employee_id ' : emp . id
2010-12-20 09:45:13 +00:00
}
leave_ids . append ( self . create ( cr , uid , vals , context = None ) )
2010-12-29 12:41:23 +00:00
wf_service = netsvc . LocalService ( " workflow " )
for leave_id in leave_ids :
wf_service . trg_validate ( uid , ' hr.holidays ' , leave_id , ' confirm ' , cr )
wf_service . trg_validate ( uid , ' hr.holidays ' , leave_id , ' validate ' , cr )
wf_service . trg_validate ( uid , ' hr.holidays ' , leave_id , ' second_validate ' , cr )
2012-08-14 12:20:50 +00:00
self . holidays_validate_notificate ( cr , uid , ids , context = context )
2008-08-24 14:45:43 +00:00
return True
2011-07-05 07:11:51 +00:00
def holidays_confirm ( self , cr , uid , ids , context = None ) :
2011-06-28 11:46:33 +00:00
self . check_holidays ( cr , uid , ids , context = context )
2012-08-28 13:28:20 +00:00
for record in self . browse ( cr , uid , ids , context = context ) :
if record . employee_id and record . employee_id . parent_id and record . employee_id . parent_id . user_id :
2012-09-25 17:33:20 +00:00
self . message_subscribe_users ( cr , uid , [ record . id ] , user_ids = [ record . employee_id . parent_id . user_id . id ] , context = context )
2012-02-08 15:25:21 +00:00
self . holidays_confirm_notificate ( cr , uid , ids , context = context )
2010-12-29 12:41:23 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' confirm ' } )
2008-08-24 14:45:43 +00:00
2012-08-14 12:20:50 +00:00
def holidays_refuse ( self , cr , uid , ids , context = None ) :
2010-12-09 05:50:40 +00:00
obj_emp = self . pool . get ( ' hr.employee ' )
2010-12-29 12:41:23 +00:00
ids2 = obj_emp . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
manager = ids2 and ids2 [ 0 ] or False
2012-08-14 12:20:50 +00:00
for holiday in self . browse ( cr , uid , ids , context = context ) :
if holiday . state == ' validate1 ' :
self . write ( cr , uid , [ holiday . id ] , { ' state ' : ' refuse ' , ' manager_id ' : manager } )
else :
self . write ( cr , uid , [ holiday . id ] , { ' state ' : ' refuse ' , ' manager_id2 ' : manager } )
self . holidays_refuse_notificate ( cr , uid , ids , context = context )
2011-07-05 07:11:51 +00:00
self . holidays_cancel ( cr , uid , ids , context = context )
2008-08-24 14:45:43 +00:00
return True
2011-07-05 07:11:51 +00:00
def holidays_cancel ( self , cr , uid , ids , context = None ) :
2012-07-05 08:06:59 +00:00
meeting_obj = self . pool . get ( ' crm.meeting ' )
2010-12-29 12:41:23 +00:00
for record in self . browse ( cr , uid , ids ) :
# Delete the meeting
2012-07-05 08:06:59 +00:00
if record . meeting_id :
meeting_obj . unlink ( cr , uid , [ record . meeting_id . id ] )
2008-08-24 14:45:43 +00:00
2010-12-29 12:41:23 +00:00
# If a category that created several holidays, cancel all related
wf_service = netsvc . LocalService ( " workflow " )
2011-03-10 09:54:32 +00:00
for request in record . linked_request_ids or [ ] :
2012-08-14 12:20:50 +00:00
wf_service . trg_validate ( uid , ' hr.holidays ' , request . id , ' refuse ' , cr )
2010-12-29 12:41:23 +00:00
2011-11-14 12:22:44 +00:00
self . _remove_resource_leave ( cr , uid , ids , context = context )
2010-12-29 12:41:23 +00:00
return True
2008-08-24 14:45:43 +00:00
2011-06-28 11:46:33 +00:00
def check_holidays ( self , cr , uid , ids , context = None ) :
2010-07-27 07:11:45 +00:00
holi_status_obj = self . pool . get ( ' hr.holidays.status ' )
2008-08-24 14:45:43 +00:00
for record in self . browse ( cr , uid , ids ) :
2010-12-29 12:41:23 +00:00
if record . holiday_type == ' employee ' and record . type == ' remove ' :
if record . employee_id and not record . holiday_status_id . limit :
leaves_rest = holi_status_obj . get_days ( cr , uid , [ record . holiday_status_id . id ] , record . employee_id . id , False ) [ record . holiday_status_id . id ] [ ' remaining_leaves ' ]
if leaves_rest < record . number_of_days_temp :
2012-04-27 07:29:13 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' There are not enough %s allocated for employee %s ; please create an allocation request for this leave type. ' ) % ( record . holiday_status_id . name , record . employee_id . name ) )
2008-08-24 14:45:43 +00:00
return True
2012-08-15 10:29:19 +00:00
2012-02-20 17:23:23 +00:00
# -----------------------------
# OpenChatter and notifications
# -----------------------------
2012-08-15 10:29:19 +00:00
def needaction_domain_get ( self , cr , uid , ids , context = None ) :
emp_obj = self . pool . get ( ' hr.employee ' )
2012-09-19 13:12:40 +00:00
empids = emp_obj . search ( cr , uid , [ ( ' parent_id.user_id ' , ' = ' , uid ) ] , context = context )
dom = [ ' & ' , ( ' state ' , ' = ' , ' confirm ' ) , ( ' employee_id ' , ' in ' , empids ) ]
2012-08-15 10:29:19 +00:00
# if this user is a hr.manager, he should do second validations
if self . pool . get ( ' res.users ' ) . has_group ( cr , uid , ' base.group_hr_manager ' ) :
2012-09-19 13:12:40 +00:00
dom = [ ' | ' ] + dom + [ ( ' state ' , ' = ' , ' validate1 ' ) ]
2012-08-15 10:29:19 +00:00
return dom
2012-06-05 12:22:21 +00:00
2012-02-28 14:07:30 +00:00
def create_notificate ( self , cr , uid , ids , context = None ) :
for obj in self . browse ( cr , uid , ids , context = context ) :
2012-09-19 13:12:40 +00:00
self . message_post ( cr , uid , ids ,
2012-10-02 20:40:23 +00:00
_ ( " Request <b>created</b>, waiting confirmation. " ) , context = context )
2012-02-20 17:23:23 +00:00
return True
2012-09-19 13:12:40 +00:00
2012-02-20 17:23:23 +00:00
def holidays_confirm_notificate ( self , cr , uid , ids , context = None ) :
for obj in self . browse ( cr , uid , ids ) :
2012-09-03 09:18:18 +00:00
self . message_post ( cr , uid , [ obj . id ] ,
2012-10-02 20:40:23 +00:00
_ ( " Request <b>submitted</b>, waiting for validation by the manager. " ) , context = context )
2012-09-19 13:12:40 +00:00
2012-08-14 12:20:50 +00:00
def holidays_first_validate_notificate ( self , cr , uid , ids , context = None ) :
2012-08-31 14:42:44 +00:00
for obj in self . browse ( cr , uid , ids , context = context ) :
2012-09-03 09:18:18 +00:00
self . message_post ( cr , uid , [ obj . id ] ,
2012-10-02 20:40:23 +00:00
_ ( " Request <b>approved</b>, waiting second validation. " ) , context = context )
2012-09-19 13:12:40 +00:00
2012-02-20 17:23:23 +00:00
def holidays_validate_notificate ( self , cr , uid , ids , context = None ) :
for obj in self . browse ( cr , uid , ids ) :
2012-09-03 09:55:26 +00:00
if obj . double_validation :
2012-09-19 13:12:40 +00:00
self . message_post ( cr , uid , [ obj . id ] ,
2012-10-02 20:40:23 +00:00
_ ( " Request <b>validated</b>. " ) , context = context )
2012-02-20 17:23:23 +00:00
else :
2012-09-03 09:18:18 +00:00
self . message_post ( cr , uid , [ obj . id ] ,
2012-10-02 20:40:23 +00:00
_ ( " The request has been <b>approved</b>. " ) , context = context )
2012-09-19 13:12:40 +00:00
2012-08-14 12:20:50 +00:00
def holidays_refuse_notificate ( self , cr , uid , ids , context = None ) :
2012-02-20 17:23:23 +00:00
for obj in self . browse ( cr , uid , ids ) :
2012-09-03 09:18:18 +00:00
self . message_post ( cr , uid , [ obj . id ] ,
2012-10-02 20:40:23 +00:00
_ ( " Request <b>refused</b> " ) , context = context )
2008-08-24 14:45:43 +00:00
2012-09-03 09:55:26 +00:00
2010-05-11 12:28:51 +00:00
class resource_calendar_leaves ( osv . osv ) :
_inherit = " resource.calendar.leaves "
_description = " Leave Detail "
_columns = {
2012-06-26 06:20:15 +00:00
' holiday_id ' : fields . many2one ( " hr.holidays " , " Leave Request " ) ,
2010-08-26 04:52:04 +00:00
}
2010-05-11 12:28:51 +00:00
resource_calendar_leaves ( )
2010-05-26 10:19:25 +00:00
2011-05-12 11:26:29 +00:00
class hr_employee ( osv . osv ) :
2012-01-03 13:52:24 +00:00
_inherit = " hr.employee "
2011-05-12 11:26:29 +00:00
2012-01-03 13:52:24 +00:00
def create ( self , cr , uid , vals , context = None ) :
# don't pass the value of remaining leave if it's 0 at the creation time, otherwise it will trigger the inverse
# function _set_remaining_days and the system may not be configured for. Note that we don't have this problem on
# the write because the clients only send the fields that have been modified.
if ' remaining_leaves ' in vals and not vals [ ' remaining_leaves ' ] :
del ( vals [ ' remaining_leaves ' ] )
return super ( hr_employee , self ) . create ( cr , uid , vals , context = context )
def _set_remaining_days ( self , cr , uid , empl_id , name , value , arg , context = None ) :
2011-05-12 12:39:20 +00:00
employee = self . browse ( cr , uid , empl_id , context = context )
diff = value - employee . remaining_leaves
2011-05-12 11:26:29 +00:00
type_obj = self . pool . get ( ' hr.holidays.status ' )
holiday_obj = self . pool . get ( ' hr.holidays ' )
2011-05-12 12:39:20 +00:00
# Find for holidays status
status_ids = type_obj . search ( cr , uid , [ ( ' limit ' , ' = ' , False ) ] , context = context )
2011-05-27 12:26:56 +00:00
if len ( status_ids ) != 1 :
2012-08-07 11:34:14 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( " The feature behind the field ' Remaining Legal Leaves ' can only be used when there is only one leave type with the option ' Allow to Override Limit ' unchecked. ( %s Found). Otherwise, the update is ambiguous as we cannot decide on which leave type the update has to be done. \n You may prefer to use the classic menus ' Leave Requests ' and ' Allocation Requests ' located in ' Human Resources \ Leaves ' to manage the leave days of the employees if the configuration does not allow to use this field. " ) % ( len ( status_ids ) ) )
2011-05-12 12:39:20 +00:00
status_id = status_ids and status_ids [ 0 ] or False
2011-05-27 13:09:04 +00:00
if not status_id :
return False
if diff > 0 :
leave_id = holiday_obj . create ( cr , uid , { ' name ' : _ ( ' Allocation for %s ' ) % employee . name , ' employee_id ' : employee . id , ' holiday_status_id ' : status_id , ' type ' : ' add ' , ' holiday_type ' : ' employee ' , ' number_of_days_temp ' : diff } , context = context )
elif diff < 0 :
leave_id = holiday_obj . create ( cr , uid , { ' name ' : _ ( ' Leave Request for %s ' ) % employee . name , ' employee_id ' : employee . id , ' holiday_status_id ' : status_id , ' type ' : ' remove ' , ' holiday_type ' : ' employee ' , ' number_of_days_temp ' : abs ( diff ) } , context = context )
else :
2011-05-12 12:39:20 +00:00
return False
2011-10-01 22:59:58 +00:00
wf_service = netsvc . LocalService ( " workflow " )
wf_service . trg_validate ( uid , ' hr.holidays ' , leave_id , ' confirm ' , cr )
wf_service . trg_validate ( uid , ' hr.holidays ' , leave_id , ' validate ' , cr )
wf_service . trg_validate ( uid , ' hr.holidays ' , leave_id , ' second_validate ' , cr )
2011-05-12 12:39:20 +00:00
return True
2012-01-03 13:52:24 +00:00
def _get_remaining_days ( self , cr , uid , ids , name , args , context = None ) :
2011-10-01 22:59:58 +00:00
cr . execute ( """ SELECT
sum ( h . number_of_days ) as days ,
2012-10-31 17:32:55 +00:00
h . employee_id
2011-10-01 22:59:58 +00:00
from
hr_holidays h
2012-10-31 17:32:55 +00:00
join hr_holidays_status s on ( s . id = h . holiday_status_id )
2011-10-01 22:59:58 +00:00
where
h . state = ' validate ' and
s . limit = False and
h . employee_id in ( % s )
2011-10-01 23:01:38 +00:00
group by h . employee_id """ % ( ' , ' .join(map(str,ids)),) )
2011-05-12 12:39:20 +00:00
res = cr . dictfetchall ( )
remaining = { }
for r in res :
remaining [ r [ ' employee_id ' ] ] = r [ ' days ' ]
for employee_id in ids :
if not remaining . get ( employee_id ) :
remaining [ employee_id ] = 0.0
return remaining
2012-10-31 17:32:55 +00:00
def _get_leave_status ( self , cr , uid , ids , name , args , context = None ) :
2012-05-17 10:59:02 +00:00
holidays_obj = self . pool . get ( ' hr.holidays ' )
2012-10-31 17:32:55 +00:00
holidays_id = holidays_obj . search ( cr , uid ,
2012-05-22 14:37:59 +00:00
[ ( ' employee_id ' , ' in ' , ids ) , ( ' date_from ' , ' <= ' , time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) ,
( ' date_to ' , ' >= ' , time . strftime ( ' % Y- % m- %d 23:59:59 ' ) ) , ( ' type ' , ' = ' , ' remove ' ) , ( ' state ' , ' not in ' , ( ' cancel ' , ' refuse ' ) ) ] ,
2011-12-22 14:24:02 +00:00
context = context )
result = { }
for id in ids :
result [ id ] = {
' current_leave_state ' : False ,
2011-12-23 09:02:10 +00:00
' current_leave_id ' : False ,
2012-05-22 14:37:59 +00:00
' leave_date_from ' : False ,
' leave_date_to ' : False ,
2011-12-22 14:24:02 +00:00
}
for holiday in self . pool . get ( ' hr.holidays ' ) . browse ( cr , uid , holidays_id , context = context ) :
2012-05-22 14:37:59 +00:00
result [ holiday . employee_id . id ] [ ' leave_date_from ' ] = holiday . date_from
result [ holiday . employee_id . id ] [ ' leave_date_to ' ] = holiday . date_to
2011-12-22 14:24:02 +00:00
result [ holiday . employee_id . id ] [ ' current_leave_state ' ] = holiday . state
result [ holiday . employee_id . id ] [ ' current_leave_id ' ] = holiday . holiday_status_id . id
return result
2012-01-03 13:52:24 +00:00
_columns = {
2011-10-01 22:59:58 +00:00
' remaining_leaves ' : fields . function ( _get_remaining_days , string = ' Remaining Legal Leaves ' , fnct_inv = _set_remaining_days , type = " float " , help = ' Total number of legal leaves allocated to this employee, change this value to create allocation/leave requests. ' ) ,
2011-12-22 14:24:02 +00:00
' current_leave_state ' : fields . function ( _get_leave_status , multi = " leave_status " , string = " Current Leave Status " , type = " selection " ,
selection = [ ( ' draft ' , ' New ' ) , ( ' confirm ' , ' Waiting Approval ' ) , ( ' refuse ' , ' Refused ' ) ,
( ' validate1 ' , ' Waiting Second Approval ' ) , ( ' validate ' , ' Approved ' ) , ( ' cancel ' , ' Cancelled ' ) ] ) ,
2011-12-22 22:10:31 +00:00
' current_leave_id ' : fields . function ( _get_leave_status , multi = " leave_status " , string = " Current Leave Type " , type = ' many2one ' , relation = ' hr.holidays.status ' ) ,
2012-05-22 14:37:59 +00:00
' leave_date_from ' : fields . function ( _get_leave_status , multi = ' leave_status ' , type = ' date ' , string = ' From Date ' ) ,
2012-10-31 17:32:55 +00:00
' leave_date_to ' : fields . function ( _get_leave_status , multi = ' leave_status ' , type = ' date ' , string = ' To Date ' ) ,
2011-05-12 11:26:29 +00:00
}
hr_employee ( )
2011-10-01 22:59:58 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: