2010-01-12 12:45:02 +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/>.
#
##############################################################################
from lxml import etree
2010-02-18 10:07:31 +00:00
import mx . DateTime
2010-01-12 12:45:02 +00:00
import time
2010-03-11 07:10:06 +00:00
2010-01-12 12:45:02 +00:00
from tools . translate import _
from osv import fields , osv
2010-02-18 10:07:31 +00:00
2010-01-12 12:45:02 +00:00
class project_phase ( osv . osv ) :
_name = " project.phase "
_description = " Project Phase "
2010-03-11 07:10:06 +00:00
def _check_recursion ( self , cr , uid , ids , context = { } ) :
data_phase = self . browse ( cr , uid , ids [ 0 ] , context = context )
prev_ids = data_phase . previous_phase_ids
next_ids = data_phase . next_phase_ids
2010-03-09 11:52:35 +00:00
# it should nither be in prev_ids nor in next_ids
2010-03-11 07:10:06 +00:00
if ( data_phase in prev_ids ) or ( data_phase in next_ids ) :
2010-01-18 13:44:53 +00:00
return False
ids = [ id for id in prev_ids if id in next_ids ]
2010-03-09 11:52:35 +00:00
# both prev_ids and next_ids must be unique
2010-01-18 13:44:53 +00:00
if ids :
return False
2010-03-09 11:52:35 +00:00
# unrelated project
2010-01-18 13:44:53 +00:00
prev_ids = [ rec . id for rec in prev_ids ]
next_ids = [ rec . id for rec in next_ids ]
2010-03-09 11:52:35 +00:00
# iter prev_ids
2010-01-18 13:44:53 +00:00
while prev_ids :
2010-02-26 11:18:14 +00:00
cr . execute ( ' select distinct prv_phase_id from project_phase_rel where next_phase_id in ( ' + ' , ' . join ( map ( str , prev_ids ) ) + ' ) ' )
2010-01-18 13:44:53 +00:00
prv_phase_ids = filter ( None , map ( lambda x : x [ 0 ] , cr . fetchall ( ) ) )
2010-03-11 07:10:06 +00:00
if data_phase . id in prv_phase_ids :
2010-01-18 13:44:53 +00:00
return False
ids = [ id for id in prv_phase_ids if id in next_ids ]
if ids :
return False
prev_ids = prv_phase_ids
2010-03-09 11:52:35 +00:00
# iter next_ids
2010-01-18 13:44:53 +00:00
while next_ids :
2010-02-26 11:18:14 +00:00
cr . execute ( ' select distinct next_phase_id from project_phase_rel where prv_phase_id in ( ' + ' , ' . join ( map ( str , next_ids ) ) + ' ) ' )
2010-01-18 13:44:53 +00:00
next_phase_ids = filter ( None , map ( lambda x : x [ 0 ] , cr . fetchall ( ) ) )
2010-03-11 07:10:06 +00:00
if data_phase . id in next_phase_ids :
2010-01-18 13:44:53 +00:00
return False
ids = [ id for id in next_phase_ids if id in prev_ids ]
if ids :
return False
next_ids = next_phase_ids
return True
2010-01-12 12:45:02 +00:00
2010-03-11 07:10:06 +00:00
def _check_dates ( self , cr , uid , ids , context = { } ) :
phase = self . read ( cr , uid , ids [ 0 ] , [ ' date_start ' , ' date_end ' ] , context = context )
if phase [ ' date_start ' ] and phase [ ' date_end ' ] and phase [ ' date_start ' ] > phase [ ' date_end ' ] :
return False
2010-02-26 11:18:14 +00:00
return True
2010-03-11 07:10:06 +00:00
def _check_constraint_start ( self , cr , uid , ids , context = { } ) :
phase = self . read ( cr , uid , ids [ 0 ] , [ ' date_start ' , ' constraint_date_start ' ] , context = context )
if phase [ ' date_start ' ] and phase [ ' constraint_date_start ' ] and phase [ ' date_start ' ] < phase [ ' constraint_date_start ' ] :
return False
2010-02-26 14:00:28 +00:00
return True
2010-03-11 07:10:06 +00:00
def _check_constraint_end ( self , cr , uid , ids , context = { } ) :
phase = self . read ( cr , uid , ids [ 0 ] , [ ' date_end ' , ' constraint_date_end ' ] , context = context )
if phase [ ' date_end ' ] and phase [ ' constraint_date_end ' ] and phase [ ' date_end ' ] > phase [ ' constraint_date_end ' ] :
return False
2010-02-26 14:00:28 +00:00
return True
2010-02-18 10:07:31 +00:00
2010-01-12 12:45:02 +00:00
_columns = {
' name ' : fields . char ( " Phase Name " , size = 64 , required = True ) ,
' date_start ' : fields . datetime ( ' Starting Date ' ) ,
' date_end ' : fields . datetime ( ' End Date ' ) ,
2010-03-11 11:17:29 +00:00
' constraint_date_start ' : fields . datetime ( ' Start Date ' , help = ' force the phase to start after this date ' ) ,
' constraint_date_end ' : fields . datetime ( ' End Date ' , help = ' force the phase to finish before this date ' ) ,
2010-01-12 12:45:02 +00:00
' project_id ' : fields . many2one ( ' project.project ' , ' Project ' , required = True ) ,
2010-02-25 06:01:27 +00:00
' next_phase_ids ' : fields . many2many ( ' project.phase ' , ' project_phase_rel ' , ' prv_phase_id ' , ' next_phase_id ' , ' Next Phases ' ) ,
' previous_phase_ids ' : fields . many2many ( ' project.phase ' , ' project_phase_rel ' , ' next_phase_id ' , ' prv_phase_id ' , ' Previous Phases ' ) ,
' sequence ' : fields . integer ( ' Sequence ' , help = " Gives the sequence order when displaying a list of phases. " ) ,
2010-03-09 11:52:35 +00:00
' duration ' : fields . float ( ' Duration ' , required = True ) ,
' product_uom ' : fields . many2one ( ' product.uom ' , ' Duration UoM ' , required = True , help = " UoM (Unit of Measure) is the unit of measurement for Duration " ) ,
2010-01-12 12:45:02 +00:00
' task_ids ' : fields . one2many ( ' project.task ' , ' phase_id ' , " Project Tasks " ) ,
' resource_ids ' : fields . one2many ( ' project.resource.allocation ' , ' phase_id ' , " Project Resources " ) ,
2010-02-25 06:01:27 +00:00
' responsible_id ' : fields . many2one ( ' res.users ' , ' Responsible ' ) ,
2010-03-09 11:52:35 +00:00
' state ' : fields . selection ( [ ( ' draft ' , ' Draft ' ) , ( ' open ' , ' In Progress ' ) , ( ' pending ' , ' Pending ' ) , ( ' cancelled ' , ' Cancelled ' ) , ( ' done ' , ' Done ' ) ] , ' State ' , readonly = True , required = True ,
2010-02-25 06:01:27 +00:00
help = ' If the phase is created the state \' Draft \' . \n If the phase is started, the state becomes \' In Progress \' . \n If review is needed the phase is in \' Pending \' state. \
\n If the phase is over , the states is set to \' Done \' . ' )
2010-01-12 12:45:02 +00:00
}
_defaults = {
2010-02-25 06:01:27 +00:00
' responsible_id ' : lambda obj , cr , uid , context : uid ,
2010-01-12 12:45:02 +00:00
' date_start ' : lambda * a : time . strftime ( ' % Y- % m- %d ' ) ,
2010-02-25 06:01:27 +00:00
' state ' : lambda * a : ' draft ' ,
' sequence ' : lambda * a : 10 ,
2010-01-12 12:45:02 +00:00
}
_order = " name "
2010-02-26 11:18:14 +00:00
_constraints = [
2010-03-09 11:52:35 +00:00
( _check_recursion , ' Error ! Loops In Phases Not Allowed ' , [ ' next_phase_ids ' , ' previous_phase_ids ' ] ) ,
2010-02-26 14:00:28 +00:00
( _check_dates , ' Error! Phase start-date must be lower then Phase end-date. ' , [ ' date_start ' , ' date_end ' ] ) ,
( _check_constraint_start , ' Error! Phase must start-after Constraint Start Date. ' , [ ' date_start ' , ' constraint_date_start ' ] ) ,
( _check_constraint_end , ' Error! Phase must end-before Constraint End Date. ' , [ ' date_end ' , ' constraint_date_end ' ] ) ,
2010-02-26 11:18:14 +00:00
]
2010-03-11 07:10:06 +00:00
def onchange_project ( self , cr , uid , ids , project , context = { } ) :
2010-02-26 11:18:14 +00:00
result = { }
2010-03-15 08:49:13 +00:00
project_obj = self . pool . get ( ' project.project ' )
2010-02-26 11:18:14 +00:00
if project :
2010-03-15 08:49:13 +00:00
project_id = project_obj . browse ( cr , uid , project , context = context )
2010-03-11 07:10:06 +00:00
if project_id . date_start :
result [ ' date_start ' ] = mx . DateTime . strptime ( project_id . date_start , " % Y- % m- %d " ) . strftime ( ' % Y- % m- %d % H: % M: % S ' )
return { ' value ' : result }
2010-03-09 11:52:35 +00:00
return { ' value ' : { ' date_start ' : [ ] } }
2010-03-11 07:10:06 +00:00
def _check_date_start ( self , cr , uid , phase , date_end , context = { } ) :
2010-03-09 11:52:35 +00:00
"""
Check And Compute date_end of phase if change in date_start < older time .
"""
uom_obj = self . pool . get ( ' product.uom ' )
resource_obj = self . pool . get ( ' resource.resource ' )
2010-03-15 08:49:13 +00:00
cal_obj = self . pool . get ( ' resource.calendar ' )
2010-03-11 07:10:06 +00:00
calendar_id = phase . project_id . resource_calendar_id and phase . project_id . resource_calendar_id . id or False
2010-03-09 11:52:35 +00:00
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , phase . responsible_id . id ) ] )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-16 09:30:14 +00:00
# cal_id = resource_obj.browse(cr, uid, resource_id[0], context=context).calendar_id.id
res = resource_obj . read ( cr , uid , resource_id [ 0 ] , [ ' calendar_id ' ] , context = context ) [ 0 ]
cal_id = res . get ( ' calendar_id ' , False ) and res . get ( ' calendar_id ' ) [ 0 ] or False
2010-03-09 11:52:35 +00:00
if cal_id :
calendar_id = cal_id
2010-03-11 07:10:06 +00:00
default_uom_id = uom_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' Hour ' ) ] , context = context ) [ 0 ]
2010-03-09 11:52:35 +00:00
avg_hours = uom_obj . _compute_qty ( cr , uid , phase . product_uom . id , phase . duration , default_uom_id )
2010-03-15 08:49:13 +00:00
work_times = cal_obj . interval_min_get ( cr , uid , calendar_id , date_end , avg_hours or 0.0 , resource_id and resource_id [ 0 ] or False )
2010-03-09 11:52:35 +00:00
dt_start = work_times [ 0 ] [ 0 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-11 07:10:06 +00:00
self . write ( cr , uid , [ phase . id ] , { ' date_start ' : dt_start , ' date_end ' : date_end . strftime ( ' % Y- % m- %d % H: % M: % S ' ) } , context = context )
2010-03-09 11:52:35 +00:00
2010-03-11 07:10:06 +00:00
def _check_date_end ( self , cr , uid , phase , date_start , context = { } ) :
2010-03-09 11:52:35 +00:00
"""
Check And Compute date_end of phase if change in date_end > older time .
"""
uom_obj = self . pool . get ( ' product.uom ' )
resource_obj = self . pool . get ( ' resource.resource ' )
2010-03-15 08:49:13 +00:00
cal_obj = self . pool . get ( ' resource.calendar ' )
2010-03-11 07:10:06 +00:00
calendar_id = phase . project_id . resource_calendar_id and phase . project_id . resource_calendar_id . id or False
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , phase . responsible_id . id ) ] , context = context )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-16 09:30:14 +00:00
# cal_id = resource_obj.browse(cr, uid, resource_id[0], context=context).calendar_id.id
res = resource_obj . read ( cr , uid , resource_id [ 0 ] , [ ' calendar_id ' ] , context = context ) [ 0 ]
cal_id = res . get ( ' calendar_id ' , False ) and res . get ( ' calendar_id ' ) [ 0 ] or False
2010-03-09 11:52:35 +00:00
if cal_id :
calendar_id = cal_id
2010-03-11 07:10:06 +00:00
default_uom_id = uom_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' Hour ' ) ] , context = context ) [ 0 ]
2010-03-09 11:52:35 +00:00
avg_hours = uom_obj . _compute_qty ( cr , uid , phase . product_uom . id , phase . duration , default_uom_id )
2010-03-15 08:49:13 +00:00
work_times = cal_obj . interval_get ( cr , uid , calendar_id , date_start , avg_hours or 0.0 , resource_id and resource_id [ 0 ] or False )
2010-03-09 11:52:35 +00:00
dt_end = work_times [ - 1 ] [ 1 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-11 07:10:06 +00:00
self . write ( cr , uid , [ phase . id ] , { ' date_start ' : date_start . strftime ( ' % Y- % m- %d % H: % M: % S ' ) , ' date_end ' : dt_end } , context = context )
2010-02-26 11:18:14 +00:00
2010-03-11 07:10:06 +00:00
def write ( self , cr , uid , ids , vals , context = { } ) :
2010-03-15 08:49:13 +00:00
resource_calendar_obj = self . pool . get ( ' resource.calendar ' )
resource_obj = self . pool . get ( ' resource.resource ' )
uom_obj = self . pool . get ( ' product.uom ' )
2010-02-26 11:18:14 +00:00
if not context :
context = { }
if context . get ( ' scheduler ' , False ) :
return super ( project_phase , self ) . write ( cr , uid , ids , vals , context = context )
2010-03-09 11:52:35 +00:00
# Consider calendar and efficiency if the phase is performed by a resource
# otherwise consider the project's working calendar
2010-03-11 07:10:06 +00:00
phase = self . browse ( cr , uid , ids [ 0 ] , context = context )
2010-03-16 09:41:40 +00:00
calendar_id = phase . project_id . resource_calendar_id and phase . project_id . resource_calendar_id . id or False
2010-03-11 07:10:06 +00:00
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , phase . responsible_id . id ) ] , context = context )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-11 07:10:06 +00:00
cal_id = resource_obj . browse ( cr , uid , resource_id [ 0 ] , context = context ) . calendar_id . id
2010-03-09 11:52:35 +00:00
if cal_id :
calendar_id = cal_id
default_uom_id = uom_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' Hour ' ) ] ) [ 0 ]
avg_hours = uom_obj . _compute_qty ( cr , uid , phase . product_uom . id , phase . duration , default_uom_id )
# Change the date_start and date_end
# for previous and next phases respectively based on valid condition
2010-03-11 07:10:06 +00:00
if vals . get ( ' date_start ' , False ) and vals [ ' date_start ' ] < phase . date_start :
2010-02-26 11:18:14 +00:00
dt_start = mx . DateTime . strptime ( vals [ ' date_start ' ] , ' % Y- % m- %d % H: % M: % S ' )
2010-03-16 09:41:40 +00:00
work_times = resource_calendar_obj . interval_get ( cr , uid , calendar_id , dt_start , avg_hours or 0.0 , resource_id and resource_id [ 0 ] or False )
2010-03-22 13:28:36 +00:00
if work_times :
vals [ ' date_end ' ] = work_times [ - 1 ] [ 1 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-02-26 11:18:14 +00:00
for prv_phase in phase . previous_phase_ids :
2010-03-11 07:10:06 +00:00
self . _check_date_start ( cr , uid , prv_phase , dt_start , context = context )
if vals . get ( ' date_end ' , False ) and vals [ ' date_end ' ] > phase . date_end :
2010-02-26 11:18:14 +00:00
dt_end = mx . DateTime . strptime ( vals [ ' date_end ' ] , ' % Y- % m- %d % H: % M: % S ' )
2010-03-16 09:41:40 +00:00
work_times = resource_calendar_obj . interval_min_get ( cr , uid , calendar_id , dt_end , avg_hours or 0.0 , resource_id and resource_id [ 0 ] or False )
2010-03-22 13:28:36 +00:00
if work_times :
vals [ ' date_start ' ] = work_times [ 0 ] [ 0 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-02-26 11:18:14 +00:00
for next_phase in phase . next_phase_ids :
2010-03-11 07:10:06 +00:00
self . _check_date_end ( cr , uid , next_phase , dt_end , context = context )
2010-02-26 11:18:14 +00:00
return super ( project_phase , self ) . write ( cr , uid , ids , vals , context = context )
2010-02-25 06:01:27 +00:00
2010-03-09 11:52:35 +00:00
def set_draft ( self , cr , uid , ids , * args ) :
2010-02-25 06:01:27 +00:00
self . write ( cr , uid , ids , { ' state ' : ' draft ' } )
return True
2010-03-09 11:52:35 +00:00
def set_open ( self , cr , uid , ids , * args ) :
2010-02-25 06:01:27 +00:00
self . write ( cr , uid , ids , { ' state ' : ' open ' } )
return True
2010-03-09 11:52:35 +00:00
def set_pending ( self , cr , uid , ids , * args ) :
2010-02-25 06:01:27 +00:00
self . write ( cr , uid , ids , { ' state ' : ' pending ' } )
return True
2010-03-09 11:52:35 +00:00
def set_cancel ( self , cr , uid , ids , * args ) :
2010-02-25 06:01:27 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancelled ' } )
return True
2010-03-09 11:52:35 +00:00
def set_done ( self , cr , uid , ids , * args ) :
2010-02-25 06:01:27 +00:00
self . write ( cr , uid , ids , { ' state ' : ' done ' } )
return True
2010-02-18 10:07:31 +00:00
2010-01-12 12:45:02 +00:00
project_phase ( )
class project_resource_allocation ( osv . osv ) :
_name = ' project.resource.allocation '
_description = ' Project Resource Allocation '
2010-02-10 06:14:22 +00:00
_rec_name = ' resource_id '
2010-01-12 12:45:02 +00:00
_columns = {
' resource_id ' : fields . many2one ( ' resource.resource ' , ' Resource ' , required = True ) ,
2010-03-09 11:52:35 +00:00
' phase_id ' : fields . many2one ( ' project.phase ' , ' Project Phase ' , required = True ) ,
2010-01-12 12:45:02 +00:00
' useability ' : fields . float ( ' Useability ' , help = " Useability of this ressource for this project phase in percentage (=50 % ) " ) ,
}
_defaults = {
' useability ' : lambda * a : 100 ,
}
2010-02-10 06:14:22 +00:00
2010-01-12 12:45:02 +00:00
project_resource_allocation ( )
class project ( osv . osv ) :
_inherit = " project.project "
2010-03-09 11:52:35 +00:00
_description = " Project "
2010-01-12 12:45:02 +00:00
_columns = {
2010-03-03 07:53:14 +00:00
' phase_ids ' : fields . one2many ( ' project.phase ' , ' project_id ' , " Project Phases " ) ,
' resource_calendar_id ' : fields . many2one ( ' resource.calendar ' , ' Working Time ' , help = " Timetable working hours to adjust the gantt diagram report " ) ,
2010-01-12 12:45:02 +00:00
}
project ( )
class task ( osv . osv ) :
_inherit = " project.task "
2010-03-09 11:52:35 +00:00
_description = " Task "
2010-01-12 12:45:02 +00:00
_columns = {
2010-03-02 13:27:02 +00:00
' phase_id ' : fields . many2one ( ' project.phase ' , ' Project Phase ' ) ,
' occupation_rate ' : fields . float ( ' Occupation Rate ' , help = ' The occupation rate fields indicates how much of his time a user is working on a task. A 100 % o ccupation rate means the user works full time on the tasks. The ending date of a task is computed like this: Starting Date + Duration / Occupation Rate. ' ) ,
' planned_hours ' : fields . float ( ' Planned Hours ' , required = True , help = ' Estimated time to do the task, usually set by the project manager when the task is in draft state. ' ) ,
2010-01-12 12:45:02 +00:00
}
2010-03-02 13:27:02 +00:00
_defaults = {
' occupation_rate ' : lambda * a : ' 1 '
}
def onchange_planned ( self , cr , uid , ids , project , user_id = False , planned = 0.0 , effective = 0.0 , date_start = None , occupation_rate = 0.0 ) :
result = { }
2010-03-17 07:15:53 +00:00
resource = False
2010-03-15 08:49:13 +00:00
resource_obj = self . pool . get ( ' resource.resource ' )
project_pool = self . pool . get ( ' project.project ' )
resource_calendar = self . pool . get ( ' resource.calendar ' )
2010-03-17 07:15:53 +00:00
if not project :
return { ' value ' : result }
2010-03-02 13:27:02 +00:00
if date_start :
2010-03-09 11:52:35 +00:00
hrs = float ( planned / float ( occupation_rate ) )
calendar_id = project_pool . browse ( cr , uid , project ) . resource_calendar_id . id
2010-03-02 13:27:02 +00:00
dt_start = mx . DateTime . strptime ( date_start , ' % Y- % m- %d % H: % M: % S ' )
2010-03-09 11:52:35 +00:00
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , user_id ) ] )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-17 07:15:53 +00:00
resource_data = resource_obj . browse ( cr , uid , resource_id ) [ 0 ]
resource = resource_data . id
hrs = planned / ( float ( occupation_rate ) * resource_data . time_efficiency )
if resource_data . calendar_id . id :
calendar_id = resource_data . calendar_id . id
work_times = resource_calendar . interval_get ( cr , uid , calendar_id , dt_start , hrs or 0.0 , resource or False )
2010-03-22 13:28:36 +00:00
if work_times :
result [ ' date_end ' ] = work_times [ - 1 ] [ 1 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-02 13:27:02 +00:00
result [ ' remaining_hours ' ] = planned - effective
return { ' value ' : result }
2010-03-11 07:10:06 +00:00
def _check_date_start ( self , cr , uid , task , date_end , context = { } ) :
2010-03-09 11:52:35 +00:00
"""
Check And Compute date_end of task if change in date_start < older time .
"""
resource_calendar_obj = self . pool . get ( ' resource.calendar ' )
resource_obj = self . pool . get ( ' resource.resource ' )
2010-03-16 09:41:40 +00:00
calendar_id = task . project_id . resource_calendar_id and task . project_id . resource_calendar_id . id or False
2010-03-09 11:52:35 +00:00
hours = task . planned_hours / task . occupation_rate
2010-03-11 07:10:06 +00:00
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , task . user_id . id ) ] , context = context )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-11 07:10:06 +00:00
resource = resource_obj . browse ( cr , uid , resource_id [ 0 ] , context = context )
2010-03-09 11:52:35 +00:00
if resource . calendar_id . id :
2010-03-16 09:41:40 +00:00
calendar_id = resource . calendar_id and resource . calendar_id . id or False
2010-03-09 11:52:35 +00:00
hours = task . planned_hours / ( float ( task . occupation_rate ) * resource . time_efficiency )
2010-03-22 13:16:12 +00:00
work_times = resource_calendar_obj . interval_min_get ( cr , uid , calendar_id , date_end , hours or 0.0 , resource_id and resource_id [ 0 ] or False )
2010-03-09 11:52:35 +00:00
dt_start = work_times [ 0 ] [ 0 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-02 13:27:02 +00:00
self . write ( cr , uid , [ task . id ] , { ' date_start ' : dt_start , ' date_end ' : date_end . strftime ( ' % Y- % m- %d % H: % M: % S ' ) } )
2010-03-11 07:10:06 +00:00
def _check_date_end ( self , cr , uid , task , date_start , context = { } ) :
2010-03-09 11:52:35 +00:00
"""
Check And Compute date_end of task if change in date_end > older time .
"""
resource_calendar_obj = self . pool . get ( ' resource.calendar ' )
resource_obj = self . pool . get ( ' resource.resource ' )
2010-03-16 09:41:40 +00:00
calendar_id = task . project_id . resource_calendar_id and task . project_id . resource_calendar_id . id or False
2010-03-09 11:52:35 +00:00
hours = task . planned_hours / task . occupation_rate
2010-03-11 07:10:06 +00:00
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , task . user_id . id ) ] , context = context )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-11 07:10:06 +00:00
resource = resource_obj . browse ( cr , uid , resource_id [ 0 ] , context = context )
2010-03-09 11:52:35 +00:00
if resource . calendar_id . id :
2010-03-16 09:41:40 +00:00
calendar_id = resource . calendar_id and resource . calendar_id . id or False
2010-03-09 11:52:35 +00:00
hours = task . planned_hours / ( float ( task . occupation_rate ) * resource . time_efficiency )
2010-03-22 13:16:12 +00:00
work_times = resource_calendar_obj . interval_get ( cr , uid , calendar_id , date_start , hours or 0.0 , resource_id and resource_id [ 0 ] or False )
2010-03-09 11:52:35 +00:00
dt_end = work_times [ - 1 ] [ 1 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-11 07:10:06 +00:00
self . write ( cr , uid , [ task . id ] , { ' date_start ' : date_start . strftime ( ' % Y- % m- %d % H: % M: % S ' ) , ' date_end ' : dt_end } , context = context )
2010-03-02 13:27:02 +00:00
2010-03-11 07:10:06 +00:00
def write ( self , cr , uid , ids , vals , context = { } ) :
2010-03-15 08:49:13 +00:00
resource_calendar_obj = self . pool . get ( ' resource.calendar ' )
resource_obj = self . pool . get ( ' resource.resource ' )
2010-03-02 13:27:02 +00:00
if not context :
context = { }
if context . get ( ' scheduler ' , False ) :
return super ( task , self ) . write ( cr , uid , ids , vals , context = context )
2010-03-09 11:52:35 +00:00
# Consider calendar and efficiency if the task is performed by a resource
# otherwise consider the project's working calendar
2010-03-05 14:26:23 +00:00
task_id = ids
if isinstance ( ids , list ) :
task_id = ids [ 0 ]
2010-03-09 11:52:35 +00:00
task_rec = self . browse ( cr , uid , task_id , context = context )
2010-03-16 09:41:40 +00:00
calendar_id = task_rec . project_id . resource_calendar_id and task_rec . project_id . resource_calendar_id . id or False
2010-03-09 11:52:35 +00:00
hrs = task_rec . planned_hours / task_rec . occupation_rate
2010-03-11 07:10:06 +00:00
resource_id = resource_obj . search ( cr , uid , [ ( ' user_id ' , ' = ' , task_rec . user_id . id ) ] , context = context )
2010-03-02 13:27:02 +00:00
if resource_id :
2010-03-11 07:10:06 +00:00
resource = resource_obj . browse ( cr , uid , resource_id [ 0 ] , context = context )
2010-03-09 11:52:35 +00:00
if resource . calendar_id . id :
2010-03-16 09:41:40 +00:00
calendar_id = resource . calendar_id and resource . calendar_id . id or False
2010-03-09 11:52:35 +00:00
hrs = task_rec . planned_hours / ( float ( task_rec . occupation_rate ) * resource . time_efficiency )
2010-03-02 13:27:02 +00:00
2010-03-09 11:52:35 +00:00
# Change the date_start and date_end
# for previous and next tasks respectively based on valid condition
2010-03-11 07:10:06 +00:00
if vals . get ( ' date_start ' , False ) and vals [ ' date_start ' ] < task_rec . date_start :
dt_start = mx . DateTime . strptime ( vals [ ' date_start ' ] , ' % Y- % m- %d % H: % M: % S ' )
2010-03-16 09:41:40 +00:00
work_times = resource_calendar_obj . interval_get ( cr , uid , calendar_id , dt_start , hrs or 0.0 , resource . id or False )
2010-03-22 13:28:36 +00:00
if work_times :
vals [ ' date_end ' ] = work_times [ - 1 ] [ 1 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-11 07:10:06 +00:00
for prv_task in task_rec . parent_ids :
self . _check_date_start ( cr , uid , prv_task , dt_start )
if vals . get ( ' date_end ' , False ) and vals [ ' date_end ' ] > task_rec . date_end :
dt_end = mx . DateTime . strptime ( vals [ ' date_end ' ] , ' % Y- % m- %d % H: % M: % S ' )
2010-03-16 09:41:40 +00:00
work_times = resource_calendar_obj . interval_min_get ( cr , uid , calendar_id , dt_end , hrs or 0.0 , resource . id or False )
2010-03-22 13:28:36 +00:00
if work_times :
vals [ ' date_start ' ] = work_times [ 0 ] [ 0 ] . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2010-03-11 07:10:06 +00:00
for next_task in task_rec . child_ids :
self . _check_date_end ( cr , uid , next_task , dt_end )
2010-03-02 13:41:19 +00:00
2010-03-02 13:27:02 +00:00
return super ( task , self ) . write ( cr , uid , ids , vals , context = context )
2010-01-12 12:45:02 +00:00
task ( )
2010-03-11 07:10:06 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: