2010-01-12 10:25:29 +00:00
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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.
#
# 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.
#
# 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/>.
#
##############################################################################
2010-08-18 07:11:15 +00:00
2013-03-19 10:31:26 +00:00
import pytz
2010-08-12 07:31:45 +00:00
from datetime import datetime , timedelta
2013-03-19 10:31:26 +00:00
from dateutil import rrule
2010-01-12 10:25:29 +00:00
import math
2010-09-24 09:26:14 +00:00
from faces import *
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
2013-05-08 14:21:04 +00:00
from openerp . tools . float_utils import float_compare
2012-12-06 14:56:32 +00:00
from openerp . tools . translate import _
2010-09-27 13:44:03 +00:00
2010-09-29 12:13:40 +00:00
from itertools import groupby
from operator import itemgetter
2010-01-12 10:25:29 +00:00
class resource_calendar ( osv . osv ) :
_name = " resource.calendar "
_description = " Resource Calendar "
_columns = {
' name ' : fields . char ( " Name " , size = 64 , required = True ) ,
2010-05-14 09:15:02 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = False ) ,
2010-07-19 09:46:40 +00:00
' attendance_ids ' : fields . one2many ( ' resource.calendar.attendance ' , ' calendar_id ' , ' Working Time ' ) ,
2012-04-24 06:05:32 +00:00
' manager ' : fields . many2one ( ' res.users ' , ' Workgroup Manager ' ) ,
2010-01-12 10:25:29 +00:00
}
_defaults = {
2010-06-01 12:06:40 +00:00
' company_id ' : lambda self , cr , uid , context : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' resource.calendar ' , context = context )
2010-01-12 10:25:29 +00:00
}
2010-08-18 07:11:15 +00:00
2011-04-06 12:28:45 +00:00
def working_hours_on_day ( self , cr , uid , resource_calendar_id , day , context = None ) :
2011-11-29 06:30:28 +00:00
""" Calculates the Working Total Hours based on Resource Calendar and
given working day ( datetime object ) .
2012-09-24 16:26:45 +00:00
2011-04-06 12:28:45 +00:00
@param resource_calendar_id : resource . calendar browse record
@param day : datetime object
2012-09-24 16:26:45 +00:00
2011-04-06 12:28:45 +00:00
@return : returns the working hours ( as float ) men should work on the given day if is in the attendance_ids of the resource_calendar_id ( i . e if that day is a working day ) , returns 0.0 otherwise
"""
res = 0.0
for working_day in resource_calendar_id . attendance_ids :
if ( int ( working_day . dayofweek ) + 1 ) == day . isoweekday ( ) :
res + = working_day . hour_to - working_day . hour_from
2012-09-24 16:26:45 +00:00
return res
2011-04-06 12:28:45 +00:00
2010-06-04 10:49:47 +00:00
def _get_leaves ( self , cr , uid , id , resource ) :
2012-09-24 16:26:45 +00:00
""" Private Method to Calculate resource Leaves days
2011-11-29 06:30:28 +00:00
@param id : resource calendar id
2012-09-24 16:26:45 +00:00
@param resource : resource id for which leaves will ew calculated
2011-11-29 06:30:28 +00:00
@return : returns the list of dates , where resource on leave in
resource . calendar . leaves object ( e . g . [ ' % Y- % m- %d ' , ' % Y- % m- %d ' ] )
"""
2010-02-25 10:11:23 +00:00
resource_cal_leaves = self . pool . get ( ' resource.calendar.leaves ' )
2010-02-19 10:26:24 +00:00
dt_leave = [ ]
2010-03-02 13:27:02 +00:00
resource_leave_ids = resource_cal_leaves . search ( cr , uid , [ ( ' calendar_id ' , ' = ' , id ) , ' | ' , ( ' resource_id ' , ' = ' , False ) , ( ' resource_id ' , ' = ' , resource ) ] )
2010-09-29 12:13:40 +00:00
#res_leaves = resource_cal_leaves.read(cr, uid, resource_leave_ids, ['date_from', 'date_to'])
res_leaves = resource_cal_leaves . browse ( cr , uid , resource_leave_ids )
2010-08-18 07:11:15 +00:00
2010-02-19 10:26:24 +00:00
for leave in res_leaves :
2010-09-29 12:13:40 +00:00
dtf = datetime . strptime ( leave . date_from , ' % Y- % m- %d % H: % M: % S ' )
dtt = datetime . strptime ( leave . date_to , ' % Y- % m- %d % H: % M: % S ' )
2010-02-19 10:26:24 +00:00
no = dtt - dtf
2010-08-12 07:31:45 +00:00
[ dt_leave . append ( ( dtf + timedelta ( days = x ) ) . strftime ( ' % Y- % m- %d ' ) ) for x in range ( int ( no . days + 1 ) ) ]
2010-02-19 10:26:24 +00:00
dt_leave . sort ( )
2010-08-18 07:11:15 +00:00
2010-06-04 10:49:47 +00:00
return dt_leave
2010-08-18 07:11:15 +00:00
2010-06-04 10:49:47 +00:00
def interval_min_get ( self , cr , uid , id , dt_from , hours , resource = False ) :
2011-11-29 06:30:28 +00:00
"""
Calculates the working Schedule from supplied from date to till hours
will be satisfied based or resource calendar id . If resource is also
2012-09-24 16:26:45 +00:00
given then it will consider the resource leave also and than will
2011-11-29 06:30:28 +00:00
calculates resource working schedule
2012-09-24 16:26:45 +00:00
2011-11-29 06:30:28 +00:00
@param dt_from : datetime object , start of working scheduled
@param hours : float , total number working hours needed scheduled from
start date
@param resource : Optional Resource id , if supplied than resource leaves
will also taken into consideration for calculating working
schedule .
@return : List datetime object of working schedule based on supplies
params
"""
2010-06-04 10:49:47 +00:00
if not id :
2010-08-12 07:31:45 +00:00
td = int ( hours ) * 3
return [ ( dt_from - timedelta ( hours = td ) , dt_from ) ]
2010-06-04 10:49:47 +00:00
dt_leave = self . _get_leaves ( cr , uid , id , resource )
dt_leave . reverse ( )
2010-01-12 10:25:29 +00:00
todo = hours
result = [ ]
maxrecur = 100
current_hour = dt_from . hour
2013-05-10 08:23:38 +00:00
while float_compare ( todo , 0 , 4 ) and maxrecur :
2010-08-12 07:31:45 +00:00
cr . execute ( " select hour_from,hour_to from resource_calendar_attendance where dayofweek= ' %s ' and calendar_id= %s order by hour_from desc " , ( dt_from . weekday ( ) , id ) )
2010-01-12 10:25:29 +00:00
for ( hour_from , hour_to ) in cr . fetchall ( ) :
2010-02-19 10:26:24 +00:00
leave_flag = False
2013-05-10 08:23:38 +00:00
if ( hour_from < current_hour ) and float_compare ( todo , 0 , 4 ) :
2010-02-18 10:07:31 +00:00
m = min ( hour_to , current_hour )
if ( m - hour_from ) > todo :
hour_from = m - todo
2010-02-19 10:26:24 +00:00
dt_check = dt_from . strftime ( ' % Y- % m- %d ' )
for leave in dt_leave :
if dt_check == leave :
2010-08-12 07:31:45 +00:00
dt_check = datetime . strptime ( dt_check , ' % Y- % m- %d ' ) + timedelta ( days = 1 )
2010-02-19 10:26:24 +00:00
leave_flag = True
if leave_flag :
break
else :
2010-08-12 07:31:45 +00:00
d1 = datetime ( dt_from . year , dt_from . month , dt_from . day , int ( math . floor ( hour_from ) ) , int ( ( hour_from % 1 ) * 60 ) )
d2 = datetime ( dt_from . year , dt_from . month , dt_from . day , int ( math . floor ( m ) ) , int ( ( m % 1 ) * 60 ) )
2010-02-19 10:26:24 +00:00
result . append ( ( d1 , d2 ) )
current_hour = hour_from
2013-05-10 08:18:03 +00:00
todo - = ( m - hour_from )
2010-08-12 07:31:45 +00:00
dt_from - = timedelta ( days = 1 )
2010-02-18 10:07:31 +00:00
current_hour = 24
2010-01-12 10:25:29 +00:00
maxrecur - = 1
2010-02-18 10:07:31 +00:00
result . reverse ( )
2010-01-12 10:25:29 +00:00
return result
2010-09-29 12:13:40 +00:00
# def interval_get(self, cr, uid, id, dt_from, hours, resource=False, byday=True):
def interval_get_multi ( self , cr , uid , date_and_hours_by_cal , resource = False , byday = True ) :
def group ( lst , key ) :
lst . sort ( key = itemgetter ( key ) )
grouped = groupby ( lst , itemgetter ( key ) )
return dict ( [ ( k , [ v for v in itr ] ) for k , itr in grouped ] )
# END group
cr . execute ( " select calendar_id, dayofweek, hour_from, hour_to from resource_calendar_attendance order by hour_from " )
hour_res = cr . dictfetchall ( )
hours_by_cal = group ( hour_res , ' calendar_id ' )
results = { }
for d , hours , id in date_and_hours_by_cal :
2010-10-15 14:01:53 +00:00
dt_from = datetime . strptime ( d , ' % Y- % m- %d % H: % M: % S ' )
2010-09-29 12:13:40 +00:00
if not id :
td = int ( hours ) * 3
results [ ( d , hours , id ) ] = [ ( dt_from , dt_from + timedelta ( hours = td ) ) ]
continue
dt_leave = self . _get_leaves ( cr , uid , id , resource )
todo = hours
result = [ ]
maxrecur = 100
current_hour = dt_from . hour
2013-05-10 08:23:38 +00:00
while float_compare ( todo , 0 , 4 ) and maxrecur :
2010-09-29 12:13:40 +00:00
for ( hour_from , hour_to ) in [ ( item [ ' hour_from ' ] , item [ ' hour_to ' ] ) for item in hours_by_cal [ id ] if item [ ' dayofweek ' ] == str ( dt_from . weekday ( ) ) ] :
leave_flag = False
2013-05-10 08:23:38 +00:00
if ( hour_to > current_hour ) and float_compare ( todo , 0 , 4 ) :
2010-09-29 12:13:40 +00:00
m = max ( hour_from , current_hour )
if ( hour_to - m ) > todo :
hour_to = m + todo
dt_check = dt_from . strftime ( ' % Y- % m- %d ' )
for leave in dt_leave :
if dt_check == leave :
dt_check = datetime . strptime ( dt_check , ' % Y- % m- %d ' ) + timedelta ( days = 1 )
leave_flag = True
if leave_flag :
break
else :
2013-11-14 17:52:44 +00:00
d1 = datetime ( dt_from . year , dt_from . month , dt_from . day ) + timedelta ( hours = int ( math . floor ( m ) ) , minutes = int ( ( m % 1 ) * 60 ) )
d2 = datetime ( dt_from . year , dt_from . month , dt_from . day ) + timedelta ( hours = int ( math . floor ( hour_to ) ) , minutes = int ( ( hour_to % 1 ) * 60 ) )
2010-09-29 12:13:40 +00:00
result . append ( ( d1 , d2 ) )
current_hour = hour_to
2013-05-10 08:26:54 +00:00
todo - = ( hour_to - m )
2010-09-29 12:13:40 +00:00
dt_from + = timedelta ( days = 1 )
current_hour = 0
maxrecur - = 1
results [ ( d , hours , id ) ] = result
return results
2010-02-25 10:11:23 +00:00
def interval_get ( self , cr , uid , id , dt_from , hours , resource = False , byday = True ) :
2011-11-29 06:30:28 +00:00
""" Calculates Resource Working Internal Timing Based on Resource Calendar.
2012-09-24 16:26:45 +00:00
2011-11-29 06:30:28 +00:00
@param dt_from : start resource schedule calculation .
@param hours : total number of working hours to be scheduled .
2012-09-24 16:26:45 +00:00
@param resource : optional resource id , If supplied it will take care of
2011-11-29 06:30:28 +00:00
resource leave while scheduling .
@param byday : boolean flag bit enforce day wise scheduling
2012-09-24 16:26:45 +00:00
2011-11-29 06:30:28 +00:00
@return : list of scheduled working timing based on resource calendar .
"""
2010-09-29 12:13:40 +00:00
res = self . interval_get_multi ( cr , uid , [ ( dt_from . strftime ( ' % Y- % m- %d % H: % M: % S ' ) , hours , id ) ] , resource , byday ) [ ( dt_from . strftime ( ' % Y- % m- %d % H: % M: % S ' ) , hours , id ) ]
return res
2010-08-18 07:11:15 +00:00
2010-06-04 10:49:47 +00:00
def interval_hours_get ( self , cr , uid , id , dt_from , dt_to , resource = False ) :
2012-09-24 16:26:45 +00:00
""" Calculates the Total Working hours based on given start_date to
end_date , If resource id is supplied that it will consider the source
2011-11-29 06:30:28 +00:00
leaves also in calculating the hours .
2012-09-24 16:26:45 +00:00
2011-11-29 06:30:28 +00:00
@param dt_from : date start to calculate hours
@param dt_end : date end to calculate hours
@param resource : optional resource id , If given resource leave will be
2012-09-24 16:26:45 +00:00
considered .
@return : Total number of working hours based dt_from and dt_end and
2011-11-29 06:30:28 +00:00
resource if supplied .
"""
2013-03-19 10:31:26 +00:00
return self . _interval_hours_get ( cr , uid , id , dt_from , dt_to , resource_id = resource )
2010-08-18 07:11:15 +00:00
2013-03-19 10:31:26 +00:00
def _interval_hours_get ( self , cr , uid , id , dt_from , dt_to , resource_id = False , timezone_from_uid = None , exclude_leaves = True , context = None ) :
""" Calculates the Total Working hours based on given start_date to
end_date , If resource id is supplied that it will consider the source
leaves also in calculating the hours .
2010-08-18 07:11:15 +00:00
2013-03-19 10:31:26 +00:00
@param dt_from : date start to calculate hours
@param dt_end : date end to calculate hours
@param resource_id : optional resource id , If given resource leave will be
considered .
@param timezone_from_uid : optional uid , if given we will considerer
working hours in that user timezone
@param exclude_leaves : optionnal , if set to True ( default ) we will exclude
resource leaves from working hours
@param context : current request context
@return : Total number of working hours based dt_from and dt_end and
resource if supplied .
"""
utc_tz = pytz . timezone ( ' UTC ' )
local_tz = utc_tz
if timezone_from_uid :
users_obj = self . pool . get ( ' res.users ' )
user_timezone = users_obj . browse ( cr , uid , timezone_from_uid , context = context ) . partner_id . tz
if user_timezone :
try :
local_tz = pytz . timezone ( user_timezone )
except pytz . UnknownTimeZoneError :
pass # fallback to UTC as local timezone
def utc_to_local_zone ( naive_datetime ) :
utc_dt = utc_tz . localize ( naive_datetime , is_dst = False )
return utc_dt . astimezone ( local_tz )
def float_time_convert ( float_val ) :
factor = float_val < 0 and - 1 or 1
val = abs ( float_val )
return ( factor * int ( math . floor ( val ) ) , int ( round ( ( val % 1 ) * 60 ) ) )
# Get slots hours per day
# {day_of_week: [(8, 12), (13, 17), ...], ...}
hours_range_per_weekday = { }
if id :
cr . execute ( " select dayofweek, hour_from,hour_to from resource_calendar_attendance where calendar_id= %s order by hour_from " , ( id , ) )
for weekday , hour_from , hour_to in cr . fetchall ( ) :
weekday = int ( weekday )
hours_range_per_weekday . setdefault ( weekday , [ ] )
hours_range_per_weekday [ weekday ] . append ( ( hour_from , hour_to ) )
else :
# considering default working hours (Monday -> Friday, 8 -> 12, 13 -> 17)
for weekday in range ( 5 ) :
hours_range_per_weekday [ weekday ] = [ ( 8 , 12 ) , ( 13 , 17 ) ]
## Interval between dt_from - dt_to
##
## dt_from dt_to
## =============|==================|============
## [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ]
##
## [ : start of range
## ] : end of range
##
## case 1: range end before interval start (skip)
## case 2: range overlap interval start (fit start to internal)
## case 3: range within interval
## case 4: range overlap interval end (fit end to interval)
## case 5: range start after interval end (skip)
interval_start = utc_to_local_zone ( dt_from )
interval_end = utc_to_local_zone ( dt_to )
hours_timedelta = timedelta ( )
# Get leaves for requested resource
dt_leaves = set ( [ ] )
if exclude_leaves and id :
dt_leaves = set ( self . _get_leaves ( cr , uid , id , resource = resource_id ) )
for day in rrule . rrule ( rrule . DAILY , dtstart = interval_start ,
until = interval_end + timedelta ( days = 1 ) ,
byweekday = hours_range_per_weekday . keys ( ) ) :
if exclude_leaves and day . strftime ( ' % Y- % m- %d ' ) in dt_leaves :
# XXX: futher improve leave management to allow for partial day leave
continue
for ( range_from , range_to ) in hours_range_per_weekday . get ( day . weekday ( ) , [ ] ) :
range_from_hour , range_from_min = float_time_convert ( range_from )
range_to_hour , range_to_min = float_time_convert ( range_to )
daytime_start = local_tz . localize ( day . replace ( hour = range_from_hour , minute = range_from_min , second = 0 , tzinfo = None ) )
daytime_end = local_tz . localize ( day . replace ( hour = range_to_hour , minute = range_to_min , second = 0 , tzinfo = None ) )
# case 1 & 5: time range out of interval
if daytime_end < interval_start or daytime_start > interval_end :
continue
# case 2 & 4: adjust start, end to fit within interval
daytime_start = max ( daytime_start , interval_start )
daytime_end = min ( daytime_end , interval_end )
# case 2+, 4+, 3
hours_timedelta + = ( daytime_end - daytime_start )
2013-03-19 10:39:27 +00:00
2013-03-19 10:31:26 +00:00
# return timedelta converted to hours
return ( hours_timedelta . days * 24.0 + hours_timedelta . seconds / 3600.0 )
2010-08-18 07:11:15 +00:00
2010-01-12 10:25:29 +00:00
resource_calendar ( )
2010-07-19 09:46:40 +00:00
class resource_calendar_attendance ( osv . osv ) :
_name = " resource.calendar.attendance "
2010-01-12 10:25:29 +00:00
_description = " Work Detail "
2012-09-24 16:26:45 +00:00
2010-01-12 10:25:29 +00:00
_columns = {
' name ' : fields . char ( " Name " , size = 64 , required = True ) ,
2012-04-24 06:05:32 +00:00
' dayofweek ' : fields . selection ( [ ( ' 0 ' , ' Monday ' ) , ( ' 1 ' , ' Tuesday ' ) , ( ' 2 ' , ' Wednesday ' ) , ( ' 3 ' , ' Thursday ' ) , ( ' 4 ' , ' Friday ' ) , ( ' 5 ' , ' Saturday ' ) , ( ' 6 ' , ' Sunday ' ) ] , ' Day of Week ' , required = True , select = True ) ,
' date_from ' : fields . date ( ' Starting Date ' ) ,
2012-07-12 14:46:00 +00:00
' hour_from ' : fields . float ( ' Work from ' , required = True , help = " Start and End time of working. " , select = True ) ,
' hour_to ' : fields . float ( " Work to " , required = True ) ,
2010-01-12 10:25:29 +00:00
' calendar_id ' : fields . many2one ( " resource.calendar " , " Resource ' s Calendar " , required = True ) ,
}
2012-09-24 16:26:45 +00:00
2010-01-12 10:25:29 +00:00
_order = ' dayofweek, hour_from '
2012-09-24 16:26:45 +00:00
2011-10-26 21:23:39 +00:00
_defaults = {
' dayofweek ' : ' 0 '
}
2010-07-19 09:46:40 +00:00
resource_calendar_attendance ( )
2010-01-12 10:25:29 +00:00
2012-12-10 09:05:54 +00:00
def hours_time_string ( hours ) :
""" convert a number of hours (float) into a string with format ' % H: % M ' """
minutes = int ( round ( hours * 60 ) )
return " %02d : %02d " % divmod ( minutes , 60 )
2010-09-24 09:26:14 +00:00
2010-01-12 10:25:29 +00:00
class resource_resource ( osv . osv ) :
_name = " resource.resource "
_description = " Resource Detail "
_columns = {
2010-05-14 09:50:39 +00:00
' name ' : fields . char ( " Name " , size = 64 , required = True ) ,
2010-01-12 10:25:29 +00:00
' code ' : fields . char ( ' Code ' , size = 16 ) ,
2010-11-15 11:12:22 +00:00
' active ' : fields . boolean ( ' Active ' , help = " If the active field is set to False, it will allow you to hide the resource record without removing it. " ) ,
2010-05-14 09:50:39 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' ) ,
2010-01-12 10:25:29 +00:00
' resource_type ' : fields . selection ( [ ( ' user ' , ' Human ' ) , ( ' material ' , ' Material ' ) ] , ' Resource Type ' , required = True ) ,
2010-03-17 07:15:53 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' User ' , help = ' Related user name for the resource to manage its access. ' ) ,
2012-07-13 10:17:51 +00:00
' time_efficiency ' : fields . float ( ' Efficiency Factor ' , size = 8 , required = True , help = " This field depict the efficiency of the resource to complete tasks. e.g resource put alone on a phase of 5 days with 5 tasks assigned to him, will show a load of 100 % f or this phase by default, but if we put a efficiency of 200 % , then his load will only be 50 % . " ) ,
2011-08-17 08:57:12 +00:00
' calendar_id ' : fields . many2one ( " resource.calendar " , " Working Time " , help = " Define the schedule of resource " ) ,
2010-01-12 10:25:29 +00:00
}
_defaults = {
2010-05-14 09:15:02 +00:00
' resource_type ' : ' user ' ,
' time_efficiency ' : 1 ,
' active ' : True ,
2010-05-17 10:20:35 +00:00
' company_id ' : lambda self , cr , uid , context : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' resource.resource ' , context = context )
2010-01-12 10:25:29 +00:00
}
2010-02-25 10:11:23 +00:00
2012-09-24 16:26:45 +00:00
2010-09-18 05:52:11 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
if default is None :
default = { }
if not default . get ( ' name ' , False ) :
2012-09-24 16:26:45 +00:00
default . update ( name = _ ( ' %s (copy) ' ) % ( self . browse ( cr , uid , id , context = context ) . name ) )
2010-09-18 05:52:11 +00:00
return super ( resource_resource , self ) . copy ( cr , uid , id , default , context )
2010-09-24 09:26:14 +00:00
def generate_resources ( self , cr , uid , user_ids , calendar_id , context = None ) :
"""
Return a list of Resource Class objects for the resources allocated to the phase .
"""
2011-01-04 13:15:11 +00:00
resource_objs = { }
2010-09-24 09:26:14 +00:00
user_pool = self . pool . get ( ' res.users ' )
for user in user_pool . browse ( cr , uid , user_ids , context = context ) :
2011-10-25 23:31:41 +00:00
resource_objs [ user . id ] = {
' name ' : user . name ,
' vacation ' : [ ] ,
' efficiency ' : 1.0 ,
}
2010-09-24 09:26:14 +00:00
resource_ids = self . search ( cr , uid , [ ( ' user_id ' , ' = ' , user . id ) ] , context = context )
if resource_ids :
2011-03-21 13:06:45 +00:00
for resource in self . browse ( cr , uid , resource_ids , context = context ) :
2011-10-25 23:31:41 +00:00
resource_objs [ user . id ] [ ' efficiency ' ] = resource . time_efficiency
2011-03-21 13:06:45 +00:00
resource_cal = resource . calendar_id . id
if resource_cal :
leaves = self . compute_vacation ( cr , uid , calendar_id , resource . id , resource_cal , context = context )
2011-10-25 23:31:41 +00:00
resource_objs [ user . id ] [ ' vacation ' ] + = list ( leaves )
2010-09-24 09:26:14 +00:00
return resource_objs
def compute_vacation ( self , cr , uid , calendar_id , resource_id = False , resource_calendar = False , context = None ) :
"""
Compute the vacation from the working calendar of the resource .
2011-11-29 06:30:28 +00:00
2010-09-24 09:26:14 +00:00
@param calendar_id : working calendar of the project
@param resource_id : resource working on phase / task
@param resource_calendar : working calendar of the resource
"""
resource_calendar_leaves_pool = self . pool . get ( ' resource.calendar.leaves ' )
leave_list = [ ]
if resource_id :
leave_ids = resource_calendar_leaves_pool . search ( cr , uid , [ ' | ' , ( ' calendar_id ' , ' = ' , calendar_id ) ,
( ' calendar_id ' , ' = ' , resource_calendar ) ,
( ' resource_id ' , ' = ' , resource_id )
] , context = context )
else :
leave_ids = resource_calendar_leaves_pool . search ( cr , uid , [ ( ' calendar_id ' , ' = ' , calendar_id ) ,
( ' resource_id ' , ' = ' , False )
] , context = context )
leaves = resource_calendar_leaves_pool . read ( cr , uid , leave_ids , [ ' date_from ' , ' date_to ' ] , context = context )
for i in range ( len ( leaves ) ) :
2010-09-28 06:39:28 +00:00
dt_start = datetime . strptime ( leaves [ i ] [ ' date_from ' ] , ' % Y- % m- %d % H: % M: % S ' )
dt_end = datetime . strptime ( leaves [ i ] [ ' date_to ' ] , ' % Y- % m- %d % H: % M: % S ' )
2010-09-24 09:26:14 +00:00
no = dt_end - dt_start
2010-09-28 06:39:28 +00:00
[ leave_list . append ( ( dt_start + timedelta ( days = x ) ) . strftime ( ' % Y- % m- %d ' ) ) for x in range ( int ( no . days + 1 ) ) ]
2010-09-24 09:26:14 +00:00
leave_list . sort ( )
return leave_list
2010-12-30 10:37:23 +00:00
def compute_working_calendar ( self , cr , uid , calendar_id = False , context = None ) :
2010-09-24 09:26:14 +00:00
"""
Change the format of working calendar from ' Openerp ' format to bring it into ' Faces ' format .
@param calendar_id : working calendar of the project
"""
2010-12-30 10:37:23 +00:00
if not calendar_id :
# Calendar is not specified: working days: 24/7
2012-09-24 16:26:45 +00:00
return [ ( ' fri ' , ' 8:0-12:0 ' , ' 13:0-17:0 ' ) , ( ' thu ' , ' 8:0-12:0 ' , ' 13:0-17:0 ' ) , ( ' wed ' , ' 8:0-12:0 ' , ' 13:0-17:0 ' ) ,
2011-10-25 23:31:41 +00:00
( ' mon ' , ' 8:0-12:0 ' , ' 13:0-17:0 ' ) , ( ' tue ' , ' 8:0-12:0 ' , ' 13:0-17:0 ' ) ]
2010-09-24 09:26:14 +00:00
resource_attendance_pool = self . pool . get ( ' resource.calendar.attendance ' )
time_range = " 8:00-8:00 "
non_working = " "
week_days = { " 0 " : " mon " , " 1 " : " tue " , " 2 " : " wed " , " 3 " : " thu " , " 4 " : " fri " , " 5 " : " sat " , " 6 " : " sun " }
wk_days = { }
wk_time = { }
wktime_list = [ ]
wktime_cal = [ ]
week_ids = resource_attendance_pool . search ( cr , uid , [ ( ' calendar_id ' , ' = ' , calendar_id ) ] , context = context )
weeks = resource_attendance_pool . read ( cr , uid , week_ids , [ ' dayofweek ' , ' hour_from ' , ' hour_to ' ] , context = context )
# Convert time formats into appropriate format required
# and create a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
for week in weeks :
res_str = " "
2011-01-06 11:08:34 +00:00
day = None
2011-10-26 21:09:02 +00:00
if week_days . get ( week [ ' dayofweek ' ] , False ) :
2010-09-24 09:26:14 +00:00
day = week_days [ week [ ' dayofweek ' ] ]
wk_days [ week [ ' dayofweek ' ] ] = week_days [ week [ ' dayofweek ' ] ]
2011-10-26 21:09:02 +00:00
else :
raise osv . except_osv ( _ ( ' Configuration Error! ' ) , _ ( ' Make sure the Working time has been configured with proper week days! ' ) )
2012-12-10 09:05:54 +00:00
hour_from_str = hours_time_string ( week [ ' hour_from ' ] )
hour_to_str = hours_time_string ( week [ ' hour_to ' ] )
2010-09-24 09:26:14 +00:00
res_str = hour_from_str + ' - ' + hour_to_str
wktime_list . append ( ( day , res_str ) )
# Convert into format like [('mon', '8:00-12:00', '13:00-18:00')]
for item in wktime_list :
if wk_time . has_key ( item [ 0 ] ) :
wk_time [ item [ 0 ] ] . append ( item [ 1 ] )
else :
wk_time [ item [ 0 ] ] = [ item [ 0 ] ]
wk_time [ item [ 0 ] ] . append ( item [ 1 ] )
for k , v in wk_time . items ( ) :
wktime_cal . append ( tuple ( v ) )
# Add for the non-working days like: [('sat, sun', '8:00-8:00')]
for k , v in wk_days . items ( ) :
if week_days . has_key ( k ) :
week_days . pop ( k )
for v in week_days . itervalues ( ) :
non_working + = v + ' , '
if non_working :
wktime_cal . append ( ( non_working [ : - 1 ] , time_range ) )
return wktime_cal
2010-01-12 10:25:29 +00:00
resource_resource ( )
class resource_calendar_leaves ( osv . osv ) :
_name = " resource.calendar.leaves "
_description = " Leave Detail "
_columns = {
' name ' : fields . char ( " Name " , size = 64 ) ,
2011-01-06 11:32:21 +00:00
' company_id ' : fields . related ( ' calendar_id ' , ' company_id ' , type = ' many2one ' , relation = ' res.company ' , string = " Company " , store = True , readonly = True ) ,
2012-04-24 06:05:32 +00:00
' calendar_id ' : fields . many2one ( " resource.calendar " , " Working Time " ) ,
2010-01-12 10:25:29 +00:00
' date_from ' : fields . datetime ( ' Start Date ' , required = True ) ,
' date_to ' : fields . datetime ( ' End Date ' , required = True ) ,
' resource_id ' : fields . many2one ( " resource.resource " , " Resource " , help = " If empty, this is a generic holiday for the company. If a resource is set, the holiday/leave is only for this resource " ) ,
}
2010-08-18 07:11:15 +00:00
2010-11-22 10:37:53 +00:00
def check_dates ( self , cr , uid , ids , context = None ) :
2010-03-02 13:27:02 +00:00
leave = self . read ( cr , uid , ids [ 0 ] , [ ' date_from ' , ' date_to ' ] )
2010-01-18 13:44:53 +00:00
if leave [ ' date_from ' ] and leave [ ' date_to ' ] :
if leave [ ' date_from ' ] > leave [ ' date_to ' ] :
return False
return True
_constraints = [
( check_dates , ' Error! leave start-date must be lower then leave end-date. ' , [ ' date_from ' , ' date_to ' ] )
]
2010-02-25 10:11:23 +00:00
2012-03-05 18:40:03 +00:00
def onchange_resource ( self , cr , uid , ids , resource , context = None ) :
2010-02-25 10:11:23 +00:00
result = { }
if resource :
resource_pool = self . pool . get ( ' resource.resource ' )
2010-11-22 10:37:53 +00:00
result [ ' calendar_id ' ] = resource_pool . browse ( cr , uid , resource , context = context ) . calendar_id . id
2010-03-02 13:27:02 +00:00
return { ' value ' : result }
return { ' value ' : { ' calendar_id ' : [ ] } }
2010-02-25 10:11:23 +00:00
2010-01-12 10:25:29 +00:00
resource_calendar_leaves ( )
2010-08-18 07:11:15 +00:00
2010-09-24 09:26:14 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: