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
#
##############################################################################
import pooler
import netsvc
import datetime
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
2008-08-30 11:45:40 +00:00
class hr_holidays_status ( osv . osv ) :
_name = " hr.holidays.status "
2009-09-24 10:46:21 +00:00
_description = " Leave Types "
def get_days ( self , cr , uid , ids , employee_id , return_false , context = { } ) :
res = { }
for record in self . browse ( cr , uid , ids , context ) :
res [ record . id ] = { }
max_leaves = leaves_taken = 0
if not return_false :
cr . execute ( """ SELECT type, sum(number_of_days) FROM hr_holidays WHERE employee_id = %s AND state= ' validate ' AND holiday_status_id = %s GROUP BY type """ , ( str ( employee_id ) , str ( record . id ) ) )
for line in cr . fetchall ( ) :
if line [ 0 ] == ' remove ' :
2010-03-17 17:09:26 +00:00
leaves_taken = - line [ 1 ]
2009-09-24 10:46:21 +00:00
if line [ 0 ] == ' add ' :
2010-03-17 17:09:26 +00:00
max_leaves = line [ 1 ]
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
2009-09-24 10:46:21 +00:00
def _user_left_days ( self , cr , uid , ids , name , args , context = { } ) :
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 :
employee_ids = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
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-17 04:23:28 +00:00
else :
res = dict . fromkeys ( ids , { name : 0 } )
2009-09-24 10:46:21 +00:00
return res
2009-03-13 06:25:53 +00:00
_columns = {
2009-09-24 10:46:21 +00:00
' name ' : fields . char ( ' Name ' , size = 64 , required = True , translate = True ) ,
2010-03-17 17:09:26 +00:00
' categ_id ' : fields . many2one ( ' crm.case.categ ' , ' Meeting Category ' , domain = " [( ' object_id.model ' , ' = ' , ' crm.meeting ' )] " , help = ' If you link this type of leave with a category in the CRM, it will synchronize each leave asked with a case in this category, to display it in the company shared calendar for example. ' ) ,
2010-03-22 11:24:34 +00:00
' color_name ' : fields . selection ( [ ( ' red ' , ' Red ' ) , ( ' 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 Departement ' ) ,
2010-05-12 17:09:20 +00:00
' limit ' : fields . boolean ( ' Allow to Override Limit ' , help = ' If you thick this checkbox, the system will allow, for this team, the employees to take more leaves than the available ones. ' ) ,
2010-03-17 17:09:26 +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. " ) ,
2010-01-12 05:32:48 +00:00
' max_leaves ' : fields . function ( _user_left_days , method = True , string = ' Maximum Leaves 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 , method = True , string = ' Leaves Already Taken ' , help = ' This value is given by the sum of all holidays requests with a negative value. ' , multi = ' user_left_days ' ) ,
2010-03-17 17:09:26 +00:00
' remaining_leaves ' : fields . function ( _user_left_days , method = True , string = ' Remaining Leaves ' , help = ' Maximum Leaves Allowed - Leaves Already Taken ' , multi = ' user_left_days ' ) ,
2009-09-24 10:46:21 +00:00
2009-03-13 06:25:53 +00:00
}
_defaults = {
2009-09-24 10:46:21 +00:00
' color_name ' : lambda * args : ' red ' ,
2009-03-13 06:25:53 +00:00
' active ' : lambda * a : True ,
}
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 "
_description = " Holidays "
2009-09-24 10:46:21 +00:00
_order = " type desc, date_from asc "
def _employee_get ( obj , cr , uid , context = { } ) :
ids = obj . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
if ids :
return ids [ 0 ]
return False
2008-11-20 17:21:19 +00:00
2008-08-24 14:45:43 +00:00
_columns = {
' name ' : fields . char ( ' Description ' , required = True , readonly = True , size = 64 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2009-11-25 10:03:47 +00:00
' state ' : fields . selection ( [ ( ' draft ' , ' Draft ' ) , ( ' confirm ' , ' Waiting Validation ' ) , ( ' refuse ' , ' Refused ' ) , ( ' validate ' , ' Validated ' ) , ( ' cancel ' , ' Cancelled ' ) ] , ' State ' , readonly = True , help = ' When the holiday request is created the state is \' Draft \' . \n It is confirmed by the user and request is sent to admin, the state is \' Waiting Validation \' . \
2009-11-23 13:52:38 +00:00
If the admin accepts it , the state is \' Validated \' . If it is refused, the state is \' Refused \' . ' ) ,
2009-09-24 10:46:21 +00:00
' date_from ' : fields . datetime ( ' Start Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
' user_id ' : fields . many2one ( ' res.users ' , ' User ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , select = True , readonly = True ) ,
' date_to ' : fields . datetime ( ' End Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
' holiday_status_id ' : fields . many2one ( " hr.holidays.status " , " Leave Type " , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-04-07 10:41:20 +00:00
' employee_id ' : fields . many2one ( ' hr.employee ' , " Employee " , select = True , invisible = False , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , help = ' Leave Manager can let this field empty if this leave request/allocation is for every employee ' ) ,
2009-09-24 10:46:21 +00:00
' manager_id ' : fields . many2one ( ' hr.employee ' , ' Leave Manager ' , invisible = False , readonly = True , help = ' This area is automaticly filled by the user who validate the leave ' ) ,
2008-08-24 14:45:43 +00:00
' notes ' : fields . text ( ' Notes ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2009-09-24 10:46:21 +00:00
' number_of_days ' : fields . float ( ' Number of Days ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
' number_of_days_temp ' : fields . float ( ' Number of Days ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-03-17 17:09:26 +00:00
' case_id ' : fields . many2one ( ' crm.meeting ' , ' Case ' ) ,
2009-09-24 10:46:21 +00:00
' type ' : fields . selection ( [ ( ' remove ' , ' Leave Request ' ) , ( ' add ' , ' Allocation Request ' ) ] , ' Request Type ' , required = True , readonly = True , states = { ' draft ' : [ ( ' 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 " ) ,
' allocation_type ' : fields . selection ( [ ( ' employee ' , ' Employee Request ' ) , ( ' company ' , ' Company Allocation ' ) ] , ' Allocation Type ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , help = ' This field is only for informative purposes, to depict if the leave request/allocation comes from an employee or from the company ' ) ,
' 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 ) ,
2008-08-24 14:45:43 +00:00
}
2008-11-20 17:21:19 +00:00
2008-08-24 14:45:43 +00:00
_defaults = {
' employee_id ' : _employee_get ,
' state ' : lambda * a : ' draft ' ,
2009-09-24 10:46:21 +00:00
' type ' : lambda * a : ' remove ' ,
' allocation_type ' : lambda * a : ' employee ' ,
2008-11-20 17:21:19 +00:00
' user_id ' : lambda obj , cr , uid , context : uid ,
2008-08-24 14:45:43 +00:00
}
_order = ' date_from desc '
2008-11-20 17:21:19 +00:00
2010-03-17 17:09:26 +00:00
def create ( self , cr , uid , vals , context = { } ) :
if context :
if context . has_key ( ' type ' ) :
vals [ ' type ' ] = context [ ' type ' ]
if context . has_key ( ' allocation_type ' ) :
vals [ ' allocation_type ' ] = context [ ' allocation_type ' ]
return super ( osv . osv , self ) . create ( cr , uid , vals , context )
2010-05-17 04:23:28 +00:00
def _get_number_of_days ( date_from , date_to ) :
""" 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
diff_day = timedelta . days + float ( timedelata . seconds ) / 86400
return diff_day
2008-12-31 09:54:58 +00:00
2010-01-05 08:07:22 +00:00
def _update_user_holidays ( self , cr , uid , ids ) :
for record in self . browse ( cr , uid , ids ) :
if record . state == ' validate ' :
if record . case_id :
2010-03-17 17:09:26 +00:00
self . pool . get ( ' crm.meeting ' ) . unlink ( cr , uid , [ record . case_id . id ] )
if record . linked_request_ids :
list_ids = [ ]
for id in record . linked_request_ids :
list_ids . append ( id . id )
self . holidays_cancel ( cr , uid , list_ids )
self . unlink ( cr , uid , list_ids )
2010-02-17 08:49:38 +00:00
2009-03-16 13:10:32 +00:00
def _check_date ( self , cr , uid , ids ) :
2010-05-11 10:32:48 +00:00
for rec in self . read ( cr , uid , ids , [ ' number_of_days ' , ' date_from ' , ' date_to ' ] ) :
if rec [ ' number_of_days ' ] < 0 :
return False
date_from = time . strptime ( rec [ ' date_from ' ] , ' % Y- % m- %d % H: % M: % S ' )
date_to = time . strptime ( rec [ ' date_to ' ] , ' % Y- % m- %d % H: % M: % S ' )
if date_from > date_to :
2009-03-16 13:10:32 +00:00
return False
return True
2010-05-11 10:32:48 +00:00
_constraints = [ ( _check_date , ' Start date should not be larger than end date! \n Number of Days should be greater than 1! ' , [ ' number_of_days ' ] ) ]
2009-03-16 13:10:32 +00:00
2010-02-17 08:49:38 +00:00
2010-01-05 08:07:22 +00:00
def unlink ( self , cr , uid , ids , context = { } ) :
self . _update_user_holidays ( cr , uid , ids )
return super ( hr_holidays , self ) . unlink ( cr , uid , ids , context )
2008-12-31 09:54:58 +00:00
2010-05-17 04:23:28 +00:00
def onchange_date_from ( self , cr , uid , ids , date_to , date_from ) :
2008-11-20 17:21:19 +00:00
result = { }
2010-05-17 04:23:28 +00:00
if date_to and date_from :
diff_day = self . _get_number_of_days ( date_from , date_to )
2009-09-24 10:46:21 +00:00
result [ ' value ' ] = {
' number_of_days_temp ' : round ( diff_day ) + 1
}
return result
2008-11-20 17:21:19 +00:00
result [ ' value ' ] = {
2010-05-17 04:23:28 +00:00
' number_of_days_temp ' : 0 ,
2008-11-20 17:21:19 +00:00
}
return result
2010-05-17 04:23:28 +00:00
def onchange_date_to ( self , cr , uid , ids , date_from , date_to ) :
return onchange_date_from ( cr , uid , ids , date_to , date_from )
2009-09-24 10:46:21 +00:00
def onchange_sec_id ( self , cr , uid , ids , status , context = { } ) :
warning = { }
if status :
brows_obj = self . pool . get ( ' hr.holidays.status ' ) . browse ( cr , uid , [ status ] ) [ 0 ]
2010-03-17 17:09:26 +00:00
if brows_obj . categ_id and brows_obj . categ_id . section_id and not brows_obj . categ_id . section_id . allow_unlink :
2009-09-24 10:46:21 +00:00
warning = {
' title ' : " Warning for " ,
2010-05-12 17:09:20 +00:00
' message ' : " You won \' t be able to cancel this leave request because the CRM Sales Team of the leave type disallows. "
2009-09-24 10:46:21 +00:00
}
return { ' warning ' : warning }
2008-08-24 14:45:43 +00:00
def set_to_draft ( self , cr , uid , ids , * args ) :
self . write ( cr , uid , ids , {
' state ' : ' draft ' ,
2009-09-24 10:46:21 +00:00
' manager_id ' : False ,
' number_of_days ' : 0 ,
2008-08-24 14:45:43 +00:00
} )
2009-09-24 10:46:21 +00:00
wf_service = netsvc . LocalService ( " workflow " )
for holiday_id in ids :
wf_service . trg_create ( uid , ' hr.holidays ' , holiday_id , cr )
2008-08-24 14:45:43 +00:00
return True
def holidays_validate ( self , cr , uid , ids , * args ) :
self . check_holidays ( cr , uid , ids )
vals = {
' state ' : ' validate ' ,
}
ids2 = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
if ids2 :
vals [ ' manager_id ' ] = ids2 [ 0 ]
2009-09-16 15:07:35 +00:00
else :
2010-04-07 10:41:20 +00:00
raise osv . except_osv ( _ ( ' Warning ! ' ) , _ ( ' No user related to the selected employee. ' ) )
2008-08-24 14:45:43 +00:00
self . write ( cr , uid , ids , vals )
2010-04-07 10:41:20 +00:00
for record in self . browse ( cr , uid , ids ) :
if record . type == ' remove ' :
vals = {
' name ' : record . name ,
' date_from ' : record . date_from ,
' date_to ' : record . date_to ,
' calendar_id ' : record . employee_id . calendar_id . id ,
' company_id ' : record . employee_id . company_id . id ,
' resource_id ' : record . employee_id . resource_id . id
}
self . pool . get ( ' resource.calendar.leaves ' ) . create ( cr , uid , vals )
2008-08-24 14:45:43 +00:00
return True
def holidays_confirm ( self , cr , uid , ids , * args ) :
2009-09-24 10:46:21 +00:00
for record in self . browse ( cr , uid , ids ) :
2010-03-17 17:09:26 +00:00
user_id = False
2009-09-24 10:46:21 +00:00
leave_asked = record . number_of_days_temp
if record . type == ' remove ' :
if record . employee_id and not record . holiday_status_id . limit :
leaves_rest = self . pool . get ( ' hr.holidays.status ' ) . get_days ( cr , uid , [ record . holiday_status_id . id ] , record . employee_id . id , False ) [ record . holiday_status_id . id ] [ ' remaining_leaves ' ]
if leaves_rest < leave_asked :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' You cannot validate leaves for %s while available leaves are less than asked leaves. ' % ( record . employee_id . name ) ) )
nb = - ( record . number_of_days_temp )
else :
nb = record . number_of_days_temp
if record . employee_id :
user_id = record . employee_id . user_id and record . employee_id . user_id . id or uid
self . write ( cr , uid , [ record . id ] , {
' state ' : ' confirm ' ,
' number_of_days ' : nb ,
' user_id ' : user_id
} )
2010-04-07 09:54:57 +00:00
return True
2008-08-24 14:45:43 +00:00
def holidays_refuse ( self , cr , uid , ids , * args ) :
2009-09-24 10:46:21 +00:00
vals = {
2008-08-24 14:45:43 +00:00
' state ' : ' refuse ' ,
2009-09-24 10:46:21 +00:00
}
ids2 = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
if ids2 :
vals [ ' manager_id ' ] = ids2 [ 0 ]
self . write ( cr , uid , ids , vals )
2008-08-24 14:45:43 +00:00
return True
def holidays_cancel ( self , cr , uid , ids , * args ) :
2010-01-05 08:07:22 +00:00
self . _update_user_holidays ( cr , uid , ids )
2008-08-24 14:45:43 +00:00
self . write ( cr , uid , ids , {
' state ' : ' cancel '
} )
return True
def holidays_draft ( self , cr , uid , ids , * args ) :
self . write ( cr , uid , ids , {
' state ' : ' draft '
} )
return True
def check_holidays ( self , cr , uid , ids ) :
for record in self . browse ( cr , uid , ids ) :
2009-09-24 10:46:21 +00:00
if not record . number_of_days :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' Wrong leave definition. ' ) )
if record . employee_id :
leave_asked = record . number_of_days
if leave_asked < 0.00 :
if not record . holiday_status_id . limit :
leaves_rest = self . pool . get ( ' hr.holidays.status ' ) . get_days ( cr , uid , [ record . holiday_status_id . id ] , record . employee_id . id , False ) [ record . holiday_status_id . id ] [ ' remaining_leaves ' ]
if leaves_rest < - ( leave_asked ) :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' You Cannot Validate leaves while available leaves are less than asked leaves. ' ) )
2008-08-24 14:45:43 +00:00
else :
2009-09-24 10:46:21 +00:00
holiday_ids = [ ]
vals = {
' name ' : record . name ,
' holiday_status_id ' : record . holiday_status_id . id ,
' state ' : ' draft ' ,
' date_from ' : record . date_from ,
' date_to ' : record . date_to ,
' notes ' : record . notes ,
' number_of_days ' : record . number_of_days ,
2010-01-12 05:32:48 +00:00
' number_of_days_temp ' : record . number_of_days_temp ,
2009-09-24 10:46:21 +00:00
' type ' : record . type ,
' allocation_type ' : record . allocation_type ,
' parent_id ' : record . id ,
}
employee_ids = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ] )
for employee in employee_ids :
vals [ ' employee_id ' ] = employee
2010-03-17 17:09:26 +00:00
user_id = self . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] )
if user_id :
vals [ ' user_id ' ] = user_id [ 0 ]
2009-09-24 10:46:21 +00:00
holiday_ids . append ( self . create ( cr , uid , vals , context = { } ) )
self . holidays_confirm ( cr , uid , holiday_ids )
self . holidays_validate ( cr , uid , holiday_ids )
2008-08-24 14:45:43 +00:00
2010-03-17 17:09:26 +00:00
if record . holiday_status_id . categ_id and record . date_from and record . date_to and record . employee_id :
2010-05-17 04:23:28 +00:00
diff_day = self . _get_number_of_days ( record . date_from , record . date_to )
vals = {
' name ' : record . name ,
' categ_id ' : record . holiday_status_id . categ_id . id ,
' duration ' : ( diff_day ) * 8 ,
' note ' : record . notes ,
' user_id ' : record . user_id . id ,
' date ' : record . date_from ,
}
2010-03-17 17:09:26 +00:00
case_id = self . pool . get ( ' crm.meeting ' ) . create ( cr , uid , vals )
2009-09-24 10:46:21 +00:00
self . write ( cr , uid , ids , { ' case_id ' : case_id } )
2008-08-24 14:45:43 +00:00
return True
hr_holidays ( )