[FIX] Complete refactoring of project_long_term, with following changes:

do not use resources but users on phases:
     - to be consistent with project members and task responsible
     - if the user is linked to a resource, it uses the calendar of the resource (holidays for example)
  better YML tests
  Complete rewrite of the scheduling mechanism:
    - Schedule phases:
        - write project.user.allocation based on scheduling
        - schedule resources based on members on the project
        - new constraint: force some users on a phase
    - Schedule tasks:
        - set user if no user on task
        - set start and end date
  some useability improvements

We still have to work on better Gantt view but I think the scheduling is
working correctly now.

bzr revid: fp@tinyerp.com-20111025233141-cgctwe8spxhko2gn
This commit is contained in:
Fabien Pinckaers 2011-10-26 01:31:41 +02:00
parent 68adb9de7e
commit 0d2ae40a70
22 changed files with 356 additions and 1108 deletions

View File

@ -49,13 +49,11 @@ Features
'test/test_schedule_phases_case2.yml',
'test/project_schedule_consecutive_day.yml',
'test/project_schedule_without_wroking_hour.yml',
'test/schedule_phase_tasks.yml',
'test/phase_constraint.yml',
'test/test_schedule_tasks_case1.yml',
],
"update_xml": [
"security/ir.model.access.csv",
"wizard/project_schedule_tasks_view.xml",
"project_long_term_view.xml",
"project_long_term_workflow.xml",
"wizard/project_compute_phases_view.xml",

View File

@ -22,7 +22,7 @@
from datetime import datetime
from tools.translate import _
from osv import fields, osv
from resource.faces import task as Task
from resource.faces import task as Task
from operator import itemgetter
class project_phase(osv.osv):
@ -74,40 +74,43 @@ class project_phase(osv.osv):
return False
return True
def _check_constraint_start(self, cr, uid, ids, context=None):
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
return True
def _check_constraint_end(self, cr, uid, ids, context=None):
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
return True
def _get_default_uom_id(self, cr, uid):
model_data_obj = self.pool.get('ir.model.data')
model_data_id = model_data_obj._get_id(cr, uid, 'product', 'uom_hour')
return model_data_obj.read(cr, uid, [model_data_id], ['res_id'])[0]['res_id']
def _compute(self, cr, uid, ids, field_name, arg, context=None):
def _compute_progress(self, cr, uid, ids, field_name, arg, context=None):
res = {}
if not ids:
return res
for phase in self.browse(cr, uid, ids, context=context):
tot = 0.0
if phase.state=='done':
res[phase.id] = 100.0
continue
elif phase.state=="cancelled":
res[phase.id] = 0.0
continue
elif not phase.task_ids:
res[phase.id] = 0.0
continue
tot = done = 0.0
for task in phase.task_ids:
tot += task.planned_hours
res[phase.id] = tot
tot += task.total_hours
done += min(task.effective_hours, task.total_hours)
if not tot:
res[phase.id] = 0.0
else:
res[phase.id] = round(100.0 * done / tot, 2)
return res
_columns = {
'name': fields.char("Name", size=64, required=True),
'date_start': fields.date('Start Date', help="It's computed by the scheduler according the project date or the end date of the previous phase.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'date_end': fields.date('End Date', help=" It's computed by the scheduler according to the start date and the duration.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'constraint_date_start': fields.date('Minimum Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'constraint_date_end': fields.date('Deadline', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'date_start': fields.datetime('Start Date', help="It's computed by the scheduler according the project date or the end date of the previous phase.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'date_end': fields.datetime('End Date', help=" It's computed by the scheduler according to the start date and the duration.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'constraint_date_start': fields.datetime('Minimum Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'constraint_date_end': fields.datetime('Deadline', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'project_id': fields.many2one('project.project', 'Project', required=True),
'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases', states={'cancelled':[('readonly',True)]}),
'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases', states={'cancelled':[('readonly',True)]}),
@ -115,74 +118,27 @@ class project_phase(osv.osv):
'duration': fields.float('Duration', required=True, help="By default in days", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'product_uom': fields.many2one('product.uom', 'Duration UoM', required=True, help="UoM (Unit of Measure) is the unit of measurement for Duration", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources",states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'responsible_id': fields.many2one('res.users', 'Responsible', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'user_force_ids': fields.many2many('res.users', string='Force Assigned Users'),
'user_ids': fields.one2many('project.user.allocation', 'phase_id', "Assigned Users",states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]},
help="The ressources on the project can be computed automatically by the scheduler"),
'state': fields.selection([('draft', 'New'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
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\'.'),
'total_hours': fields.function(_compute, string='Total Hours'),
'progress': fields.function(_compute_progress, string='Progress', help="Computed based on related tasks"),
}
_defaults = {
'responsible_id': lambda obj,cr,uid,context: uid,
'state': 'draft',
'sequence': 10,
'product_uom': lambda self,cr,uid,c: self.pool.get('product.uom').search(cr, uid, [('name', '=', _('Day'))], context=c)[0]
}
_order = "project_id, date_start, sequence, name"
_order = "project_id, date_start, sequence"
_constraints = [
(_check_recursion,'Loops in phases not allowed',['next_phase_ids', 'previous_phase_ids']),
(_check_dates, 'Phase start-date must be lower than phase end-date.', ['date_start', 'date_end']),
]
def onchange_project(self, cr, uid, ids, project, context=None):
result = {}
result['date_start'] = False
project_obj = self.pool.get('project.project')
if project:
project_id = project_obj.browse(cr, uid, project, context=context)
result['date_start'] = project_id.date_start
return {'value': result}
def _check_date_start(self, cr, uid, phase, date_end, context=None):
"""
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')
cal_obj = self.pool.get('resource.calendar')
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)])
if resource_id:
res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
if cal_id:
calendar_id = cal_id
default_uom_id = self._get_default_uom_id(cr, uid)
avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
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)
dt_start = work_times[0][0].strftime('%Y-%m-%d')
self.write(cr, uid, [phase.id], {'date_start': dt_start, 'date_end': date_end.strftime('%Y-%m-%d')}, context=context)
def _check_date_end(self, cr, uid, phase, date_start, context=None):
"""
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')
cal_obj = self.pool.get('resource.calendar')
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)
if resource_id:
res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
if cal_id:
calendar_id = cal_id
default_uom_id = self._get_default_uom_id(cr, uid)
avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
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)
dt_end = work_times[-1][1].strftime('%Y-%m-%d')
self.write(cr, uid, [phase.id], {'date_start': date_start.strftime('%Y-%m-%d'), 'date_end': dt_end}, context=context)
return {}
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
@ -211,208 +167,58 @@ class project_phase(osv.osv):
self.write(cr, uid, ids, {'state': 'done'})
return True
def generate_phase(self, cr, uid, ids, f, parent=False, context=None):
if context is None:
context = {}
phase_ids = []
data_pool = self.pool.get('ir.model.data')
uom_pool = self.pool.get('product.uom')
task_pool = self.pool.get('project.task')
data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
for phase in self.browse(cr, uid, ids, context=context):
avg_days = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, day_uom_id)
duration = str(avg_days) + 'd'
# Create a new project for each phase
str_resource = ('%s & '*len(phase.resource_ids))[:-2]
str_vals = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, phase.resource_ids))
def generate_phase(self, cr, uid, phases, context=None):
context = context or {}
result = ""
# Phases Defination for the Project
s = '''
task_pool = self.pool.get('project.task')
for phase in phases:
if phase.state in ('done','cancelled'):
continue
duration_uom = {
'days': 'd', 'day': 'd', 'd':'d',
'months': 'm', 'month':'month', 'm':'m',
'weeks': 'w', 'week': 'w', 'w':'w',
'hours': 'H', 'hour': 'H', 'h':'H',
}.get(phase.product_uom.name.lower(), "h")
duration = str(phase.duration) + duration_uom
result += '''
def Phase_%s():
title = \"%s\"
effort = \'%s\'
resource = %s
'''%(phase.id, phase.name, duration, str_vals or False)
# Recalculate date_start and date_end
# according to constraints on date start and date end on phase
start_date = ''
end_date = ''
effort = \"%s\"''' % (phase.id, phase.name, duration)
start = []
if phase.constraint_date_start:
start_date = datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
s += '''
start = \"%s\"
'''%(datetime.strftime(start_date, "%Y-%m-%d"))
else:
if parent:
start = 'up.Phase_%s.end' % (parent.id)
s += '''
start = %s
'''%(start)
else:
start = phase.project_id.date_start or phase.date_start
s += '''
start = \"%s\"
'''%(start)
if phase.constraint_date_end :
end_date= datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
s += '''
end = \"%s\"
'''%(datetime.strftime(end_date, "%Y-%m-%d"))
start.append('datetime.datetime.strptime("'+str(phase.constraint_date_start)+'", "%Y-%m-%d %H:%M:%S")')
for previous_phase in phase.previous_phase_ids:
start.append("up.Phase_%s.end" % (previous_phase.id,))
if start:
result += '''
start = max(%s)
''' % (','.join(start))
if phase.user_force_ids:
result += '''
resource = %s
''' % '|'.join(map(lambda x: 'User_'+str(x.id), phase.user_force_ids))
#start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
result += task_pool._generate_task(cr, uid, phase.task_ids, ident=8, context=context)
result += "\n"
phase_ids.append(phase.id)
parent = False
task_ids = []
todo_task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
('state', 'in', ['draft', 'open', 'pending'])
], order='sequence')
if todo_task_ids :
for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
s += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=False, context=context)
if not parent:
parent = task
task_ids.append(task.id)
f += s + '\n'
# Recursive call till all the next phases scheduled
for next_phase in phase.next_phase_ids:
if next_phase.state in ['draft', 'open', 'pending']:
rf, rphase_ids = self.generate_phase(cr, uid, [next_phase.id], f = '', parent=phase, context=context)
f += rf +'\n'
phase_ids += rphase_ids
else:
continue
return f, phase_ids
def schedule_tasks(self, cr, uid, ids, context=None):
"""
Schedule tasks base on faces lib
"""
if context is None:
context = {}
if type(ids) in (long, int,):
ids = [ids]
task_pool = self.pool.get('project.task')
resource_pool = self.pool.get('resource.resource')
for phase in self.browse(cr, uid, ids, context=context):
project = phase.project_id
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
start_date = project.date_start
#Creating resources using the member of the Project
u_ids = [i.id for i in project.members]
resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
func_str = ''
start = start_date
minimum_time_unit = 1
# default values
working_hours_per_day = 24
working_days_per_week = 7
working_days_per_month = 30
working_days_per_year = 365
vacation = []
if calendar_id:
working_hours_per_day = 8 #TODO: it should be come from calendars
working_days_per_week = 5
working_days_per_month = 20
working_days_per_year = 200
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
cls_str = ''
# Creating Resources for the Project
for key, vals in resource_objs.items():
cls_str +='''
class Resource_%s(Resource):
title = \"%s\"
vacation = %s
efficiency = %s
'''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
# Create a new project for each phase
func_str += '''
def Phase_%d():
from resource.faces import Resource
title = \"%s\"
start = \'%s\'
minimum_time_unit = %s
working_hours_per_day = %s
working_days_per_week = %s
working_days_per_month = %s
working_days_per_year = %s
vacation = %s
working_days = %s
'''%(phase.id, phase.name, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
parent = False
task_ids = []
todo_task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
('state', 'in', ['draft', 'open', 'pending'])
], order='sequence')
for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True, context=context)
if not parent:
parent = task
task_ids.append(task.id)
func_str += cls_str
phase_id = phase.id
#check known constraints before running Face algorithm in order to have the error translated
if not phase.project_id.date_start:
raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
# Allocating Memory for the required Project and Pahses and Resources
exec(func_str)
Phase = eval('Phase_%d' % phase.id)
phase = None
try:
phase = Task.BalancedProject(Phase)
except Exception, e:
raise osv.except_osv(_('Error !'),e)
for task_id in task_ids:
task = eval("phase.Task_%d" % task_id)
start_date = task.start.to_datetime()
end_date = task.end.to_datetime()
task_pool.write(cr, uid, [task_id], {
'date_start': start_date.strftime('%Y-%m-%d %H:%M:%S'),
'date_end': end_date.strftime('%Y-%m-%d %H:%M:%S')
}, context=context)
return True
return result
project_phase()
class project_resource_allocation(osv.osv):
_name = 'project.resource.allocation'
_description = 'Project Resource Allocation'
_rec_name = 'resource_id'
def get_name(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for allocation in self.browse(cr, uid, ids, context=context):
name = allocation.phase_id.name
name += ' (%s%%)' %(allocation.useability)
res[allocation.id] = name
return res
class project_user_allocation(osv.osv):
_name = 'project.user.allocation'
_description = 'Phase User Allocation'
_rec_name = 'user_id'
_columns = {
'name': fields.function(get_name, type='char', size=256),
'resource_id': fields.many2one('resource.resource', 'Resource', required=True),
'user_id': fields.many2one('res.users', 'User', required=True),
'phase_id': fields.many2one('project.phase', 'Project Phase', ondelete='cascade', required=True),
'project_id': fields.related('phase_id', 'project_id', type='many2one', relation="project.project", string='Project', store=True),
'user_id': fields.related('resource_id', 'user_id', type='many2one', relation="res.users", string='User'),
'date_start': fields.date('Start Date', help="Starting Date"),
'date_end': fields.date('End Date', help="Ending Date"),
'useability': fields.float('Availability', help="Availability of this resource for this project phase in percentage (=50%)"),
'date_start': fields.datetime('Start Date', help="Starting Date"),
'date_end': fields.datetime('End Date', help="Ending Date"),
}
_defaults = {
'useability': 100,
}
project_resource_allocation()
project_user_allocation()
class project(osv.osv):
_inherit = "project.project"
@ -420,161 +226,104 @@ class project(osv.osv):
'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", states={'close':[('readonly',True)]} ),
}
def generate_members(self, cr, uid, ids, context=None):
"""
Return a list of Resource Class objects for the resources allocated to the phase.
"""
res = {}
resource_pool = self.pool.get('resource.resource')
for project in self.browse(cr, uid, ids, context=context):
user_ids = map(lambda x:x.id, project.members)
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
resource_objs = resource_pool.generate_resources(cr, uid, user_ids, calendar_id, context=context)
res[project.id] = resource_objs
return res
def schedule_phases(self, cr, uid, ids, context=None):
"""
Schedule phase base on faces lib
"""
if context is None:
context = {}
def _schedule_header(self, cr, uid, ids, context=None):
context = context or {}
if type(ids) in (long, int,):
ids = [ids]
phase_pool = self.pool.get('project.phase')
task_pool = self.pool.get('project.task')
projects = self.browse(cr, uid, ids, context=context)
for project in projects:
if not project.members:
raise osv.except_osv(_('Warning !'),_("You must assign members on the project '%s' !") % (project.name,))
resource_pool = self.pool.get('resource.resource')
data_pool = self.pool.get('ir.model.data')
resource_allocation_pool = self.pool.get('project.resource.allocation')
data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
#Checking the Valid Phase resource allocation from project member
for project in self.browse(cr, uid, ids, context=context):
flag = False
res_missing = []
members_ids = []
if project.members:
members_ids = [user.id for user in project.members]
for phase in project.phase_ids:
if phase.resource_ids:
res_ids = [ re.id for re in phase.resource_ids]
for res in resource_allocation_pool.browse(cr, uid, res_ids, context=context):
if res.resource_id.user_id.id not in members_ids:
res_missing += [res.resource_id.name]
flag = True
if flag:
raise osv.except_osv(_('Warning !'),_("Resource(s) %s is(are) not member(s) of the project '%s' .") % (",".join(res_missing), project.name))
result = "from resource.faces import *\n"
result += "import datetime\n"
for project in self.browse(cr, uid, ids, context=context):
root_phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
('state', 'in', ['draft', 'open', 'pending']),
('previous_phase_ids', '=', False)
])
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
start_date = project.date_start
#if start_date:
# start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
#Creating resources using the member of the Project
u_ids = [i.id for i in project.members]
for task in project.tasks:
if task.state in ('done','cancelled'):
continue
if task.user_id and (task.user_id.id not in u_ids):
u_ids.append(task.user_id.id)
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
func_str = ''
start = start_date
minimum_time_unit = 1
# default values
working_hours_per_day = 24
working_days_per_week = 7
working_days_per_month = 30
working_days_per_year = 365
vacation = []
if calendar_id:
working_hours_per_day = 8 #TODO: it should be come from calendars
working_days_per_week = 5
working_days_per_month = 20
working_days_per_year = 200
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
cls_str = ''
# Creating Resources for the Project
for key, vals in resource_objs.items():
cls_str +='''
class Resource_%s(Resource):
title = \"%s\"
vacation = %s
efficiency = %s
'''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
# Create a new project for each phase
func_str += '''
def Project_%d():
from resource.faces import Resource
result +='''
class User_%s(Resource):
title = \"%s\"
efficiency = %s
''' % (key, vals.get('name',False), vals.get('efficiency', False))
result += '''
def Project():
'''
return result
def _schedule_project(self, cr, uid, project, context=None):
resource_pool = self.pool.get('resource.resource')
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
# TODO: check if we need working_..., default values are ok.
result = """
def Project_%d():
title = \"%s\"
start = \'%s\'
minimum_time_unit = %s
working_hours_per_day = %s
working_days_per_week = %s
working_days_per_month = %s
working_days_per_year = %s
working_days = %s
resource = %s
""" % (
project.id, project.name,
project.date_start, working_days,
'|'.join(['User_'+str(x.id) for x in project.members])
)
vacation = calendar_id and tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context)) or False
if vacation:
result+= """
vacation = %s
working_days = %s
'''%(project.id, project.name, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
func_str += cls_str
phase_ids = []
for root_phase in phase_pool.browse(cr, uid, root_phase_ids, context=context):
phases, child_phase_ids = phase_pool.generate_phase(cr, uid, [root_phase.id], '', context=context)
func_str += phases
phase_ids += child_phase_ids
project_id = project.id
if not project.date_start:
raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
# Allocating Memory for the required Project and Phases and Resources
exec(func_str)
Project = eval('Project_%d' % project.id)
project = None
try:
project = Task.BalancedProject(Project)
except Exception, e:
raise osv.except_osv(_('Error !'), e)
for phase_id in phase_ids:
act_phase = phase_pool.browse(cr, uid, phase_id, context=context)
resources = act_phase.resource_ids
phase = eval("project.Phase_%d" % phase_id)
start_date = phase.start.to_datetime()
end_date = phase.end.to_datetime()
if resources:
for res in resources:
vals = {}
vals.update({'date_start' : start_date })
vals.update({'date_end' : end_date})
resource_allocation_pool.write(cr, uid, res.id, vals, context=context)
if act_phase.task_ids:
for task in act_phase.task_ids:
vals = {}
#Getting values of the Tasks
temp = eval("phase.Task_%s"%task.id)
if temp.booked_resource:
res_name = temp.booked_resource[0].title
res_id = resource_pool.search(cr, uid,[('name','=',res_name)], context = context)
if res_id:
res = resource_pool.browse(cr, uid, res_id[0], context = context)
vals.update({'user_id' : res.user_id.id})
vals.update({'date_start' : temp.start.strftime('%Y-%m-%d %H:%M:%S')})
vals.update({'date_end' : temp.end.strftime('%Y-%m-%d %H:%M:%S')})
task_pool.write(cr, uid, task.id, vals, context=context)
""" % ( vacation, )
return result
phase_pool.write(cr, uid, [phase_id], {
'date_start': start_date.strftime('%Y-%m-%d'),
'date_end': end_date.strftime('%Y-%m-%d')
}, context=context)
return True
def schedule_phases(self, cr, uid, ids, context=None):
context = context or {}
if type(ids) in (long, int,):
ids = [ids]
projects = self.browse(cr, uid, ids, context=context)
result = self._schedule_header(cr, uid, ids, context=context)
for project in projects:
result += self._schedule_project(cr, uid, project, context=context)
result += self.pool.get('project.phase').generate_phase(cr, uid, project.phase_ids, context=context)
local_dict = {}
exec result in local_dict
projects_gantt = Task.BalancedProject(local_dict['Project'])
for project in projects:
project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,))
for phase in project.phase_ids:
if phase.state in ('done','cancelled'):
continue
# Maybe it's better to update than unlink/create if it already exists ?
p = getattr(project_gantt, 'Phase_%d' % (phase.id,))
self.pool.get('project.user.allocation').unlink(cr, uid,
[x.id for x in phase.user_ids],
context=context
)
for r in p.booked_resource:
self.pool.get('project.user.allocation').create(cr, uid, {
'user_id': int(r.name[5:]),
'phase_id': phase.id,
'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),
'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')
}, context=context)
self.pool.get('project.phase').write(cr, uid, [phase.id], {
'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),
'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')
}, context=context)
return True
#TODO: DO Resource allocation and compute availability
def compute_allocation(self, rc, uid, ids, start_date, end_date, context=None):
@ -584,186 +333,68 @@ def Project_%d():
return allocation
def schedule_tasks(self, cr, uid, ids, context=None):
"""
Schedule task base on faces lib
"""
if context is None:
context = {}
context = context or {}
if type(ids) in (long, int,):
ids = [ids]
task_pool = self.pool.get('project.task')
resource_pool = self.pool.get('resource.resource')
data_pool = self.pool.get('ir.model.data')
data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
projects = self.browse(cr, uid, ids, context=context)
result = self._schedule_header(cr, uid, ids, context=context)
for project in projects:
result += self._schedule_project(cr, uid, project, context=context)
result += self.pool.get('project.task')._generate_task(cr, uid, project.tasks, ident=4, context=context)
for project in self.browse(cr, uid, ids, context=context):
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
start_date = project.date_start
#Checking the Valid Phase resource allocation from project member
flag = False
res_missing = []
members_ids = []
if project.members:
members_ids = [user.id for user in project.members]
for phase in project.phase_ids:
if phase.resource_ids:
res_ids = [ re.id for re in phase.resource_ids]
for res in self.pool.get('project.resource.allocation').browse(cr, uid, res_ids, context=context):
if res.resource_id.user_id.id not in members_ids:
res_missing += [res.resource_id.name]
flag = True
if flag:
raise osv.except_osv(_('Warning !'),_("Resource(s) %s is(are) not member(s) of the project '%s' .") % (",".join(res_missing), project.name))
#Creating resources using the member of the Project
u_ids = [i.id for i in project.members]
resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
try:
start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
except:
raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
func_str = ''
start = start_date
minimum_time_unit = 1
# default values
working_hours_per_day = 24
working_days_per_week = 7
working_days_per_month = 30
working_days_per_year = 365
vacation = []
if calendar_id:
working_hours_per_day = 8 #TODO: it should be come from calendars
working_days_per_week = 5
working_days_per_month = 20
working_days_per_year = 200
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
local_dict = {}
exec result in local_dict
projects_gantt = Task.BalancedProject(local_dict['Project'])
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
cls_str = ''
# Creating Resources for the Project
for key, vals in resource_objs.items():
cls_str +='''
class Resource_%s(Resource):
title = \"%s\"
vacation = %s
efficiency = %s
'''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
# Create a new project for each phase
func_str += '''
def Project_%d():
from resource.faces import Resource
title = \"%s\"
start = \'%s\'
minimum_time_unit = %s
working_hours_per_day = %s
working_days_per_week = %s
working_days_per_month = %s
working_days_per_year = %s
vacation = %s
working_days = %s
'''%(project.id, project.name, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
parent = False
task_ids = []
todo_task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
('state', 'in', ['draft', 'open', 'pending'])
], order='sequence')
if todo_task_ids:
for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True,context=context)
if not parent:
parent = task
task_ids.append(task.id)
func_str += cls_str
for project in projects:
project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,))
for task in project.tasks:
if task.state in ('done','cancelled'):
continue
if not project.date_start:# or not project.members:
raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
# Allocating Memory for the required Project and Phases and Resources
exec(func_str)
Project = eval('Project_%d' % project.id)
project = None
try:
project = Task.BalancedProject(Project)
except Exception, e:
raise osv.except_osv(_('Error !'), e)
for task_id in task_ids:
task = eval("project.Task_%d" % task_id)
start_date = task.start.to_datetime()
end_date = task.end.to_datetime()
task_pool.write(cr, uid, [task_id], {
'date_start': start_date.strftime('%Y-%m-%d %H:%M:%S'),
'date_end': end_date.strftime('%Y-%m-%d %H:%M:%S')
}, context=context)
p = getattr(project_gantt, 'Task_%d' % (task.id,))
self.pool.get('project.task').write(cr, uid, [task.id], {
'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),
'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')
}, context=context)
if (not task.user_id) and (p.booked_resource):
self.pool.get('project.task').write(cr, uid, [task.id], {
'user_id': int(p.booked_resource[0].name[5:]),
}, context=context)
return True
project()
class resource_resource(osv.osv):
_inherit = "resource.resource"
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if context is None:
context = {}
if context.get('project_id',False):
project_pool = self.pool.get('project.project')
project_rec = project_pool.browse(cr, uid, context['project_id'], context=context)
user_ids = [user_id.id for user_id in project_rec.members]
args.append(('user_id','in',user_ids))
return super(resource_resource, self).search(cr, uid, args, offset, limit, order, context, count)
resource_resource()
class project_task(osv.osv):
_inherit = "project.task"
_columns = {
'phase_id': fields.many2one('project.phase', 'Project Phase'),
}
_defaults = {
'user_id' : False
}
def _generate_task(self, cr, uid, tasks, ident=4, context=None):
context = context or {}
result = ""
ident = ' '*ident
for task in tasks:
if task.state in ('done','cancelled'):
continue
result += '''
%sdef Task_%s():
%s title = \"%s\"
%s todo = \"%.2fH\"
%s effort = \"%.2fH\"''' % (ident,task.id, ident,task.name, ident,task.remaining_hours, ident,task.total_hours)
start = []
for t2 in task.parent_ids:
start.append("up.Task_%s.end" % (t2.id,))
if start:
result += '''
%s start = max(%s)
''' % (ident,','.join(start))
def generate_task(self, cr, uid, task_id, parent=False, flag=False, context=None):
if context is None:
context = {}
task = self.browse(cr, uid, task_id, context=context)
duration = str(task.planned_hours)+ 'H'
str_resource = False
parent = task.parent_ids
if task.phase_id.resource_ids:
str_resource = ('%s | '*len(task.phase_id.resource_ids))[:-2]
str_resource = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, task.phase_id.resource_ids))
# Task Defination for the Phase of the Project
if not flag:
s = '''
def Task_%s():
title = \"%s\"
effort = \'%s\'
resource = %s
'''%(task.id, task.name, duration, str_resource)
if task.child_ids:
seq = [[child.planned_hours, child.id] for child in task.child_ids]
seq.sort(key=itemgetter(0))
s +='''
start = up.Task_%s.end
'''%(seq[-1][1])
else:
s = '''
def Task_%s():
title = \"%s\"
effort = \'%s\'
resource = %s
'''%(task.id, task.name, duration, str_resource)
if task.child_ids:
seq = [[child.planned_hours, child.id] for child in task.child_ids]
seq.sort(key=itemgetter(0))
s +='''
start = up.Task_%s.end
'''%(seq[-1][1])
s += '\n'
return s
if task.user_id:
result += '''
%s resource = %s
''' % (ident, 'User_'+str(task.user_id.id))
result += "\n"
return result
project_task()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,55 +1,9 @@
<?xml version="1.0" ?>
<openerp>
<data noupdate="1">
<!--
This Demo data file Human Resources, Phases and Resources,Tasks allocation and also run scheduling of phase and tasks.
-->
<!-- Human Resources -->
<record id="resource_analyst" model="resource.resource">
<field name="user_id" ref="project.res_users_analyst"/>
<field name="name">Analyst</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_project_manager" model="resource.resource">
<field name="user_id" ref="project.res_users_project_manager"/>
<field name="name">Project Manager</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_technical_leader" model="resource.resource">
<field name="user_id" ref="project.res_users_technical_leader"/>
<field name="name">Technical Leader</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_developer" model="resource.resource">
<field name="user_id" ref="project.res_users_developer"/>
<field name="name">Developer</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_designer" model="resource.resource">
<field name="user_id" ref="project.res_users_designer"/>
<field name="name">Designer</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_tester" model="resource.resource">
<field name="user_id" ref="project.res_users_tester"/>
<field name="name">Tester</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_finacial_manager" model="resource.resource">
<field name="user_id" ref="project.res_users_finacial_manager"/>
<field name="name">Project Finacial Manager</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<!--
This Demo data file Human Resources, Phases and Resources,Tasks allocation and also run scheduling of phase and tasks.
-->
<!-- Project Phases -->
<record id="project_phase_1" model="project.phase">
@ -58,7 +12,6 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
<field name="product_uom" ref="product.uom_day"/>
<field eval="1" name="sequence"/>
<field name="duration">30</field>
<field name="responsible_id" ref="project.res_users_analyst"/>
<field name="project_id" ref="project.project_integrate_openerp"/>
</record>
@ -68,7 +21,6 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
<field name="product_uom" ref="product.uom_day"/>
<field eval="2" name="sequence"/>
<field name="duration">20</field>
<field name="responsible_id" ref="project.res_users_project_manager"/>
<field name="project_id" ref="project.project_integrate_openerp"/>
</record>
@ -78,7 +30,6 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
<field name="product_uom" ref="product.uom_day"/>
<field eval="3" name="sequence"/>
<field name="duration">20</field>
<field name="responsible_id" ref="project.res_users_project_manager"/>
<field name="project_id" ref="project.project_integrate_openerp"/>
</record>
@ -88,7 +39,6 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
<field name="product_uom" ref="product.uom_day"/>
<field eval="4" name="sequence"/>
<field name="duration">90</field>
<field name="responsible_id" ref="project.res_users_technical_leader"/>
<field name="project_id" ref="project.project_integrate_openerp"/>
</record>
@ -98,7 +48,6 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
<field name="product_uom" ref="product.uom_day"/>
<field eval="5" name="sequence"/>
<field name="duration">30</field>
<field name="responsible_id" ref="project.res_users_project_manager"/>
<field name="project_id" ref="project.project_integrate_openerp"/>
</record>
@ -108,56 +57,9 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
<field name="product_uom" ref="product.uom_day"/>
<field eval="5" name="sequence"/>
<field name="duration">10</field>
<field name="responsible_id" ref="project.res_users_analyst"/>
<field name="project_id" ref="project.project_integrate_openerp"/>
</record>
<!-- Project Resource Allocation -->
<record id="resource_allocation_1" model="project.resource.allocation">
<field name="resource_id" ref="resource_analyst"/>
<field name="phase_id" ref="project_phase_1"/>
</record>
<record id="resource_allocation_2" model="project.resource.allocation">
<field name="resource_id" ref="resource_project_manager"/>
<field name="phase_id" ref="project_phase_2"/>
</record>
<record id="resource_allocation_3" model="project.resource.allocation">
<field name="resource_id" ref="resource_project_manager"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="resource_allocation_4" model="project.resource.allocation">
<field name="resource_id" ref="resource_technical_leader"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="resource_allocation_5" model="project.resource.allocation">
<field name="resource_id" ref="resource_developer"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="resource_allocation_6" model="project.resource.allocation">
<field name="resource_id" ref="resource_designer"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="resource_allocation_7" model="project.resource.allocation">
<field name="resource_id" ref="resource_tester"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="resource_allocation_8" model="project.resource.allocation">
<field name="resource_id" ref="resource_project_manager"/>
<field name="phase_id" ref="project_phase_5"/>
</record>
<record id="resource_allocation_9" model="project.resource.allocation">
<field name="resource_id" ref="resource_analyst"/>
<field name="phase_id" ref="project_phase_6"/>
</record>
<!-- Tasks -->
<record id="project.project_task_1" model="project.task">

View File

@ -5,29 +5,29 @@
<menuitem id="base.menu_project_long_term" name="Long Term Planning" parent="base.menu_main_pm" sequence="1"/>
# ------------------------------------------------------
# Project Resource Allocation
# Project User Allocation
# ------------------------------------------------------
<record id="view_project_resource_allocation_gantt" model="ir.ui.view">
<field name="name">project.resource.allocation.gantt</field>
<field name="model">project.resource.allocation</field>
<record id="view_project_user_allocation_gantt" model="ir.ui.view">
<field name="name">project.user.allocation.gantt</field>
<field name="model">project.user.allocation</field>
<field name="type">gantt</field>
<field name="arch" type="xml">
<gantt color="project_id" date_start="date_start" date_stop="date_end" mode="year">
<level object="res.users" link="user_id" domain="[]">
<field name="name"/>
<field name="phase_id"/>
</level>
</gantt>
</field>
</record>
<record id="view_project_resource_allocation_calendar" model="ir.ui.view">
<field name="name">project.resource.allocation.calendar</field>
<field name="model">project.resource.allocation</field>
<record id="view_project_user_allocation_calendar" model="ir.ui.view">
<field name="name">project.user.allocation.calendar</field>
<field name="model">project.user.allocation</field>
<field name="type">calendar</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<calendar color="resource_id" date_start="date_start" date_stop="date_end" day_length="12" string="Resources">
<calendar color="user_id" date_start="date_start" date_stop="date_end" day_length="12" string="Users">
<field name="phase_id"/>
<field name="project_id"/>
</calendar>
@ -35,53 +35,51 @@
</record>
<record id="view_project_resource_allocation_form" model="ir.ui.view">
<field name="name">project.resource.allocation.form</field>
<field name="model">project.resource.allocation</field>
<record id="view_project_user_allocation_form" model="ir.ui.view">
<field name="name">project.user.allocation.form</field>
<field name="model">project.user.allocation</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Project Resource Allocation">
<form string="Project User Allocation">
<group colspan="4" col="6">
<field name="resource_id"/>
<field name="user_id"/>
<field name="phase_id"/>
<field name="project_id"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="useability" string="Availability"/>
</group>
</form>
</field>
</record>
<record id="view_project_resource_allocation_list" model="ir.ui.view">
<field name="name">project.resource.allocation.list</field>
<field name="model">project.resource.allocation</field>
<record id="view_project_user_allocation_list" model="ir.ui.view">
<field name="name">project.user.allocation.list</field>
<field name="model">project.user.allocation</field>
<field name="type">tree</field>
<field name="priority" eval="5"/>
<field name="arch" type="xml">
<tree editable="bottom" string="Project Resource Allocation">
<field name="resource_id"/>
<tree editable="bottom" string="Project User Allocation">
<field name="user_id"/>
<field name="phase_id"/>
<field name="project_id"/>
<field name="useability" string="Availability"/>
</tree>
</field>
</record>
<record id="view_project_resource_allocation_search" model="ir.ui.view">
<field name="name">project.resource.allocation.search</field>
<field name="model">project.resource.allocation</field>
<record id="view_project_user_allocation_search" model="ir.ui.view">
<field name="name">project.user.allocation.search</field>
<field name="model">project.user.allocation</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Resources Allocation">
<search string="Users Allocation">
<group>
<field name="resource_id"/>
<field name="user_id"/>
<field name="phase_id"/>
<field name="project_id"/>
</group>
<newline/>
<group expand="0" string="Group By...">
<filter name="resource" string="Resource" icon="terp-personal" domain="[]" context="{'group_by':'resource_id'}"/>
<filter name="user" string="User" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<separator orientation="vertical"/>
<filter string="Project" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
<filter string="Phase" icon="terp-project" domain="[]" context="{'group_by':'phase_id'}"/>
@ -90,12 +88,12 @@
</field>
</record>
<record id="act_resouce_allocation" model="ir.actions.act_window">
<field name="name">Resources Allocation</field>
<field name="res_model">project.resource.allocation</field>
<field name="name">Users Allocation</field>
<field name="res_model">project.user.allocation</field>
<field name="view_type">form</field>
<field name="view_mode">gantt,tree,form,calendar</field>
<field name="context">{}</field>
<field name="search_view_id" ref="view_project_resource_allocation_search"/>
<field name="search_view_id" ref="view_project_user_allocation_search"/>
</record>
@ -110,32 +108,27 @@
<field name="arch" type="xml">
<form string="Project Phase">
<group colspan="6" col="6">
<group colspan="6" col="6" >
<field name="name" select="1"/>
<field name="project_id" on_change="onchange_project(project_id)"/>
<field name="responsible_id"/>
</group>
<group colspan="6" col="6">
<field name="date_start" readonly="1"/>
<group colspan="6" col="7" >
<field name="name" colspan="4"/>
<field name="project_id" on_change="onchange_project(project_id)" colspan="3"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="duration"/>
<field name="product_uom" nolabel="1" domain="[('category_id.name', '=', 'Working Time')]"/>
<field name="date_end" readonly="1"/>
<field name="product_uom" nolabel="1"/>
</group>
</group>
<notebook colspan="4">
<page string="Resource Allocation">
<field colspan="4" name="resource_ids" nolabel="1">
<tree editable="bottom" string="Project Resource Allocation">
<field name="resource_id" context="{'project_id':parent.project_id}"/>
<page string="Users Allocation">
<field colspan="4" name="user_ids" nolabel="1">
<tree editable="bottom" string="Project User Allocation">
<field name="user_id"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="useability" string="Availability"/>
</tree>
<form string="Project Resource Allocation">
<field name="resource_id" context="{'project_id':parent.project_id}"/>
<form string="Project Users Allocation">
<field name="user_id"/>
<field name="date_start" />
<field name="date_end"/>
<field name="useability" string="Availability"/>
</form>
</field>
<separator string="" colspan="4"/>
@ -162,38 +155,9 @@
<field name="remaining_hours" widget="float_time" sum="Remaining Hours"/>
<field name="state"/>
</tree>
<form string="Project's Tasks">
<notebook colspan="4">
<page string="Task Detail">
<group colspan="4" col="4">
<field name="name"/>
<field name="project_id"/>
<field name="user_id"/>
<field name="sequence"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2"/>
<field name="date_start"/>
<field name="date_end" />
<field name="date_deadline"/>
</group>
<group colspan="2" col="2">
<separator string="Planning" colspan="2"/>
<field name="planned_hours" widget="float_time"/>
<field name="total_hours" widget="float_time"/>
<field name="remaining_hours" widget="float_time"/>
<field name="effective_hours" invisible="1"/>
</group>
<group colspan="6" col="4">
<field name="state"/>
</group>
</page>
</notebook>
</form>
</field>
<button name="%(action_project_schedule_tasks)d" string="Schedule Tasks" type="action" icon="gtk-jump-to"/>
</page>
<page string="Schedule and Display info">
<page string="Constraints">
<group colspan="2" col="2">
<separator string="Constraints" colspan="2"/>
<field name="constraint_date_start"/>
@ -203,10 +167,12 @@
<separator string="Displaying settings" colspan="2"/>
<field name="sequence"/>
</group>
<separator colspan="4" string="Force Assigned Users"/>
<field colspan="4" name="user_force_ids" nolabel="1"/>
<separator colspan="4" string="Previous Phases"/>
<field colspan="4" name="previous_phase_ids" nolabel="1" domain="[('id','!=',active_id)]"/>
<field colspan="4" name="previous_phase_ids" nolabel="1"/>
<separator colspan="4" string="Next Phases"/>
<field colspan="4" name="next_phase_ids" nolabel="1" domain="[('id','!=',active_id)]"/>
<field colspan="4" name="next_phase_ids" nolabel="1"/>
</page>
</notebook>
<newline/>
@ -223,12 +189,10 @@
<tree colors="grey:state in ('cancelled','done');blue:state == 'pending'" string="Project Phases">
<field name="name"/>
<field name="project_id" on_change="onchange_project(project_id)"/>
<field name="responsible_id"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="duration"/>
<field name="state"/>
<button name="%(action_project_schedule_tasks)d" string="Schedule Tasks" type="action" icon="gtk-jump-to"/>
</tree>
</field>
</record>
@ -241,7 +205,6 @@
<field name="arch" type="xml">
<calendar color="project_id" date_start="date_start" date_stop="date_end" day_length="12">
<field name="name"/>
<field name="responsible_id"/>
</calendar>
</field>
</record>
@ -275,14 +238,11 @@
<field name="project_id">
<filter domain="[('project_id.user_id','=',uid)]" help="My Projects" icon="terp-folder-violet"/>
</field>
<field name="responsible_id"/>
<field name="date_start"/>
<field name="date_end"/>
</group>
<newline/>
<group expand="0" string="Group By..." groups="base.group_extended">
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'responsible_id'}"/>
<separator orientation="vertical"/>
<filter string="Project" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}" name="project"/>
<separator orientation="vertical"/>
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
@ -300,7 +260,7 @@
<field name="view_mode">gantt,tree,form,calendar</field>
<field name="context">{"search_default_current": 1}</field>
<field name="search_view_id" ref="view_project_phase_search"/>
<field name="help">A project can be split into the different phases. For each phase, you can define your resources allocation, describe different tasks and link your phase to previous and next phases, add date constraints for the automated scheduling. Use the long term planning in order to planify your available human resources, convert your phases into a series of tasks when you start working on the project.</field>
<field name="help">A project can be split into the different phases. For each phase, you can define your users allocation, describe different tasks and link your phase to previous and next phases, add date constraints for the automated scheduling. Use the long term planning in order to planify your available users, convert your phases into a series of tasks when you start working on the project.</field>
</record>
<record id="act_project_phase_list" model="ir.actions.act_window">
@ -317,7 +277,7 @@
# Project
# ------------------------------------------------------
<record id="project.view_project_resource_form1" model="ir.ui.view">
<record id="project.view_project_user_form1" model="ir.ui.view">
<field name="name">Project Resource Calendar View</field>
<field name="model">project.project</field>
<field name="type">form</field>
@ -402,17 +362,6 @@
view_type="form"
/>
<act_window
context="{'search_default_user_id': [user_id]}"
id="act_project_resource"
name="Resources"
res_model="resource.resource"
src_model="project.project"
domain="[('user_id', '=',user_id)]"
view_mode="tree,form"
view_type="form"
/>
# ------------------------------------------------------
# Menu Items
# ------------------------------------------------------
@ -428,16 +377,16 @@
<menuitem id="menu_resouce_allocation" action="act_resouce_allocation"
icon="STOCK_INDENT"
name="Resource Allocations" parent="base.menu_project_long_term" sequence="2"/>
name="Users Allocations" parent="base.menu_project_long_term" sequence="2"/>
<menuitem id="menu_pm_resources_project1"
<menuitem id="menu_pm_users_project1"
groups="base.group_extended"
name="Resources" parent="project.menu_definitions" sequence="3"/>
name="Users" parent="project.menu_definitions" sequence="3"/>
<menuitem id="menu_phase_schedule" name="Scheduling" parent="base.menu_main_pm" sequence="4" groups="project.group_project_user,project.group_project_manager"/>
<menuitem action="resource.action_resource_resource_tree" id="menu_view_resource" parent="menu_pm_resources_project1" sequence="2"/>
<menuitem action="resource.action_resource_calendar_form" id="menu_view_resource_calendar" parent="menu_pm_resources_project1" sequence="1"/>
<menuitem action="resource.action_resource_calendar_leave_tree" id="menu_view_resource_calendar_leaves" parent="menu_pm_resources_project1" sequence="1"/>
<menuitem action="resource.action_resource_resource_tree" id="menu_view_resource" parent="menu_pm_users_project1" sequence="2"/>
<menuitem action="resource.action_resource_calendar_form" id="menu_view_resource_calendar" parent="menu_pm_users_project1" sequence="1"/>
<menuitem action="resource.action_resource_calendar_leave_tree" id="menu_view_resource_calendar_leaves" parent="menu_pm_users_project1" sequence="1"/>
</data>
</openerp>

View File

@ -1,9 +1,9 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_project_phase","project.phase","model_project_phase","project.group_project_user",1,1,1,0
"access_project_resource_allocation","project.resource.allocation","model_project_resource_allocation","project.group_project_user",1,0,0,0
"access_project_user_allocation","project.user.allocation","model_project_user_allocation","project.group_project_user",1,0,0,0
"access_project_phase_manager","project.phase manager","model_project_phase","project.group_project_manager",1,1,1,1
"access_project_resource_allocation_manager","project.resource.allocation manager","model_project_resource_allocation","project.group_project_manager",1,1,1,1
"access_resource_resource_user","resource.resource user","resource.model_resource_resource","project.group_project_user",1,0,0,0
"access_resource_calendar_leaves_user","resource.calendar.leaves user","resource.model_resource_calendar_leaves","project.group_project_user",1,1,1,1
"access_resource_resource_manager","resource.resource manager","resource.model_resource_resource","project.group_project_manager",1,1,1,1
"access_project_resource_allocation_manager","project.resource.allocation.manager","model_project_resource_allocation","project.group_project_manager",1,1,1,1
"access_project_user_allocation_manager","project.user.allocation manager","model_project_user_allocation","project.group_project_manager",1,1,1,1
"access_resource_resource_user","user.user user","resource.model_resource_resource","project.group_project_user",1,0,0,0
"access_resource_calendar_leaves_user","user.calendar.leaves user","resource.model_resource_calendar_leaves","project.group_project_user",1,1,1,1
"access_resource_resource_manager","user.user manager","resource.model_resource_resource","project.group_project_manager",1,1,1,1
"access_project_user_allocation_manager","project.user.allocation.manager","model_project_user_allocation","project.group_project_manager",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_project_phase project.phase model_project_phase project.group_project_user 1 1 1 0
3 access_project_resource_allocation access_project_user_allocation project.resource.allocation project.user.allocation model_project_resource_allocation model_project_user_allocation project.group_project_user 1 0 0 0
4 access_project_phase_manager project.phase manager model_project_phase project.group_project_manager 1 1 1 1
5 access_project_resource_allocation_manager access_project_user_allocation_manager project.resource.allocation manager project.user.allocation manager model_project_resource_allocation model_project_user_allocation project.group_project_manager 1 1 1 1
6 access_resource_resource_user resource.resource user user.user user resource.model_resource_resource project.group_project_user 1 0 0 0
7 access_resource_calendar_leaves_user resource.calendar.leaves user user.calendar.leaves user resource.model_resource_calendar_leaves project.group_project_user 1 1 1 1
8 access_resource_resource_manager resource.resource manager user.user manager resource.model_resource_resource project.group_project_manager 1 1 1 1
9 access_project_resource_allocation_manager access_project_user_allocation_manager project.resource.allocation.manager project.user.allocation.manager model_project_resource_allocation model_project_user_allocation project.group_project_manager 1 1 1 1

View File

@ -5,6 +5,8 @@
name: "Develop Yaml Project Module"
date_start: !eval time.strftime('%Y-%m-%d')
resource_calendar_id: resource.timesheet_group1
members:
- base.user_admin
-
And I create three human ressources to work on this project, an analyst.
-
@ -43,7 +45,6 @@
name: "Analysis"
product_uom: product.uom_day
project_id: project_project_developyamlproject0
responsible_id: project.res_users_analyst
state: draft
-

View File

@ -4,6 +4,8 @@
!record {model: project.project, id: project_project_developyamlproject_2}:
name: "Develop Yaml Project Module"
date_start: !eval time.strftime('%Y-%m-%d')
members:
- base.user_admin
-
I have set Working Time from Monday to Friday from 9am to 17pm.
@ -107,7 +109,6 @@
!record {model: project.compute.phases, id: project_compute_phases_0}:
project_id: project_project_developyamlproject_2
target_project: one
-
Schedule project phases using Compute Phase Scheduling
-
@ -120,7 +121,7 @@
!python {model: project.project}: |
proj=self.browse(cr, uid, [ref("project_project_developyamlproject_2")])[0]
for phase in proj.phase_ids:
if (not phase.responsible_id) or (not phase.date_start) or (not phase.date_end):
raise AssertionError("Phases not scheduled")
if (not phase.date_start) or (not phase.date_end):
raise AssertionError("Phases not scheduled")

View File

@ -15,7 +15,6 @@
product_uom: product.uom_day
name: "Analysis Flow for Yaml"
project_id: project_project_developyamlproject_2
responsible_id: project.res_users_analyst
state: draft
-
@ -71,7 +70,7 @@
!python {model: project.project}: |
proj=self.browse(cr, uid, [ref("project_project_developyamlproject_2")])[0]
for phase in proj.phase_ids:
if (not phase.responsible_id) or (not phase.date_start) or (not phase.date_end):
if (not phase.date_start) or (not phase.date_end):
raise AssertionError("Phases not scheduled")

View File

@ -1,90 +0,0 @@
-
Create project 'Develop an outlook-openerp synchronization plugin'
-
!record {model: project.project, id: project_project_project4}:
name: Develop an outlook-openerp synchronization plugin
members:
- project.res_users_project_manager
- project.res_users_technical_leader
- project.res_users_developer
- project.res_users_designer
- project.res_users_tester
- project.res_users_analyst
- project.res_users_finacial_manager
-
Create phase 'Develop GUI' in Outlook
-
!record {model: project.phase, id: project_phase_phase0}:
date_start: !eval time.strftime("%Y-%m-%d")
duration: 200.0
name: Develop GUI in Outlook
product_uom: product.uom_day
project_id: project_project_project4
state: draft
resource_ids:
- resource_id: project_long_term.resource_analyst
- resource_id: project_long_term.resource_developer
- resource_id: project_long_term.resource_designer
- resource_id: project_long_term.resource_tester
- resource_id: project_long_term.resource_project_manager
-
Create the phase task 'Develop GUI for Server Configuration'
-
!record {model: project.task, id: project_task_t0}:
name: Develop GUI for Server Configuration
planned_hours: 20.0
remaining_hours: 20.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project4
-
Create the phase task 'Develop GUI for Modules Configuration'
-
!record {model: project.task, id: project_task_t1}:
name: Develop GUI for Modules Configuration
planned_hours: 25.0
remaining_hours: 25.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project4
-
Create the phase task 'Develop GUI for OpenERP Synchronisation'
-
!record {model: project.task, id: project_task_t2}:
name: Develop GUI for OpenERP Synchronisation
planned_hours: 30.0
remaining_hours: 30.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project4
-
Create the phase task 'Design required GUI/Menus'
-
!record {model: project.task, id: project_task_3}:
name: Design required GUI/Menus
planned_hours: 25.0
remaining_hours: 25.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project4
-
Schedule phase tasks
-
!python {model: project.phase}: |
res = self.schedule_tasks(cr, uid, [ref("project_phase_phase0")])
-
Check if tasks scheduled, check that either of task's start_date, end_date and user_id is not null
-
!python {model: project.phase}: |
phase = self.browse(cr, uid, [ref("project_phase_phase0")])[0]
for task in phase.task_ids:
if (not task.date_start) or (not task.date_end):
raise AssertionError("Phase Tasks not scheduled: %d uid=%r start=%r end=%r" % \
(task.id, task.user_id, task.date_start, task.date_end))

View File

@ -31,28 +31,6 @@
name: Establishing Project Feasibility
product_uom: product.uom_day
project_id: project_project_worldbanksproject0
-
Resource1
-
!record {model: project.resource.allocation, id: res_phase1}:
resource_id: project_long_term.resource_project_manager
phase_id: project_phase_definingclientsbasicideaofproject0
-
Resource2
-
!record {model: project.resource.allocation, id: res_phase2}:
resource_id: project_long_term.resource_analyst
phase_id: project_phase_definingclientsbasicideaofproject0
-
Resource3
-
!record {model: project.resource.allocation, id: res_phase3}:
resource_id: project_long_term.resource_technical_leader
phase_id: project_phase_definingclientsbasicideaofproject0
-
Create the phase task 'Develop GUI for Server Configuration'
-
@ -84,20 +62,6 @@
product_uom: product.uom_hour
project_id: project_project_worldbanksproject0
-
Resource4
-
!record {model: project.resource.allocation, id: res_phase4}:
resource_id: project_long_term.resource_developer
phase_id: project_phase_preparationofengineeringdesigns0
-
Resource5
-
!record {model: project.resource.allocation, id: res_phase5}:
resource_id: project_long_term.resource_designer
phase_id: project_phase_preparationofengineeringdesigns0
-
Create the phase task 'Develop GUI for Client Configuration'
-
@ -210,7 +174,7 @@
!python {model: project.project}: |
prj=self.browse(cr, uid, [ref("project_project_worldbanksproject0")])[0]
for phase in prj.phase_ids:
if (not phase.responsible_id) or (not phase.date_start) or (not phase.date_end):
raise AssertionError("Tasks not scheduled")
if (not phase.date_start) or (not phase.date_end):
raise AssertionError("Tasks not scheduled")

View File

@ -11,26 +11,17 @@
- project.res_users_tester
- project.res_users_analyst
- project.res_users_finacial_manager
-
Create phase 'Develop GUI' in thunderbird
-
!record {model: project.phase, id: project_phase_phase1}:
date_start: !eval time.strftime('%Y-%m-%d')
date_start: !eval time.strftime('%Y-%m-%d %H:%M:%S')
duration: 200.0
name: Develop GUI in thunderbird
product_uom: product.uom_day
project_id: project_project_project1
state: draft
resource_ids:
- resource_id: project_long_term.resource_analyst
useability: 80.0
- resource_id: project_long_term.resource_developer
useability: 30.0
- resource_id: project_long_term.resource_designer
useability: 30.0
-
Create the phase task 'Develop GUI for Server Configuration'
-
@ -76,8 +67,7 @@
phase_id: project_phase_phase1
project_id: project_project_project1
user_id: project.res_users_designer
-
Schedule tasks
-
@ -88,7 +78,9 @@
Check if tasks scheduled, check that either of task's start_date, end_date and user_id is not null
-
!python {model: project.project}: |
prj = self.browse(cr, uid, [ref("project_project_project1")])[0]
for task in prj.tasks:
if (not task.user_id) or (not task.date_start) or (not task.date_end):
raise AssertionError("Project Tasks not scheduled")
prj = self.browse(cr, uid, [ref("project_project_project1")])[0]
for task in prj.tasks:
if task.state in ('done','cancelled'):
continue
if (not task.user_id) or (not task.date_start) or (not task.date_end):
raise AssertionError("Project tasks not scheduled!")

View File

@ -63,10 +63,12 @@
import datetime
from dateutil.relativedelta import *
start = (datetime.date.today()).strftime('%Y-%m-%d')
end = (datetime.date.today() + relativedelta(days=2)).strftime('%Y-%m-%d')
end = (datetime.date.today() + relativedelta(days=1)).strftime('%Y-%m-%d 17:00:00')
first_phase = self.browse(cr, uid, ref('project_phase_firstphase0_case1'))
assert (first_phase.date_start == start and first_phase.date_end == end),'Dates are wrong!'
assert (first_phase.date_start[:10] == start),'Start dates are wrong: %s != %s !' % (first_phase.date_start, start)
assert (first_phase.date_end >= end),'End dates are wrong: %s <%s!' % (first_phase.date_end, end)
second_phase = self.browse(cr, uid, ref('project_phase_secondphase0_case2'))
start = first_phase.date_end
end = (datetime.date.today() + relativedelta(days=5)).strftime('%Y-%m-%d')
assert (second_phase.date_start == start and second_phase.date_end == end),'Dates are wrong!'
assert (second_phase.date_start >= start and second_phase.date_end >= end),'Dates are wrong on second phase!'

View File

@ -147,7 +147,7 @@
I create a phase 'Initial Phase' for project 'Development and Testing'.
-
!record {model: project.phase, id: project_phase_phase0}:
date_start: '2011-01-03'
date_start: '2011-01-03 08:00:00'
duration: 0.0
name: Initial Phase
product_uom: product.uom_day

View File

@ -38,7 +38,7 @@
- res_users_user0
- res_users_user1
phase_ids:
- date_start: '2011-01-06'
- date_start: '2011-01-06 08:00:00'
duration: 2.0
name: Phase A
product_uom: product.uom_day
@ -184,16 +184,11 @@
Now I create one phase for the project.
-
!record {model: project.phase, id: project_phase_phasea0}:
date_start: '2011-01-06'
date_start: '2011-01-06 08:00:00'
duration: 2.0
name: Phase A
product_uom: product.uom_day
project_id: project_project_projecta0
resource_ids:
- project_id: project_project_projecta0
resource_id: resource_resource_user0
- project_id: project_project_projecta0
resource_id: resource_resource_user1
state: draft
task_ids:
- delay_hours: 0.0

View File

@ -21,6 +21,5 @@
import project_compute_phases
import project_compute_tasks
import project_schedule_tasks
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -25,21 +25,19 @@ class project_compute_phases(osv.osv_memory):
_name = 'project.compute.phases'
_description = 'Project Compute Phases'
_columns = {
'target_project': fields.selection([('all', 'Compute All Projects'),
('one', 'Compute a Single Project'),
], 'Schedule', required = True),
'target_project': fields.selection([
('all', 'Compute All My Projects'),
('one', 'Compute a Single Project'),
], 'Schedule', required=True),
'project_id': fields.many2one('project.project', 'Project')
}
_defaults = {
'target_project': 'all'
'target_project': 'one'
}
def check_selection(self, cr, uid, ids, context=None):
return self.compute_date(cr, uid, ids, context=context)
def compute_date(self, cr, uid, ids, context=None):
"""
Compute the phases for scheduling.
@ -47,12 +45,12 @@ class project_compute_phases(osv.osv_memory):
project_pool = self.pool.get('project.project')
data = self.read(cr, uid, ids, [], context=context)[0]
if not data['project_id'] and data['target_project'] == 'one':
raise osv.except_osv(_('Error!'), _('Please Specify Project to be schedule'))
raise osv.except_osv(_('Error!'), _('Please specify a project to schedule.'))
if data['project_id']: # If project mentioned find its phases
if data['target_project'] == 'one':
project_ids = [data['project_id'][0]]
else: # Else take all the draft,open,pending states phases
project_ids = project_pool.search(cr, uid, [], context=context)
else:
project_ids = project_pool.search(cr, uid, [('user_id','=',uid)], context=context)
project_pool.schedule_phases(cr, uid, project_ids, context=context)
return self._open_phases_list(cr, uid, data, context=context)
@ -70,8 +68,7 @@ class project_compute_phases(osv.osv_memory):
result = act_obj.read(cr, uid, [id], context=context)[0]
result['target'] = 'current'
project_id = data.get('project_id') and data.get('project_id')[0] or False
result['context'] = {"search_default_project_id":project_id, "default_project_id":project_id, "search_default_responsible_id":uid, "search_default_current": 1}
result['context'] = {"search_default_project_id":project_id, "default_project_id":project_id, "search_default_current": 1}
return result
project_compute_phases()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -2,42 +2,42 @@
<openerp>
<data>
<record id="view_project_compute_phases_select" model="ir.ui.view">
<record id="view_project_compute_phases_select" model="ir.ui.view">
<field name="name">Compute Scheduling of Phases</field>
<field name="model">project.compute.phases</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Compute Scheduling of Phases">
<form string="Compute Scheduling of Phases">
<group colspan="4" col="4">
<separator colspan="4" string="Compute Scheduling of phases for all or specified project" />
<field name="target_project" colspan="4"/>
<field name="project_id" widget="selection" colspan="4" attrs="{'invisible':[('target_project','=','all')], 'required':[('target_project','!=','all')]}"/>
<field name="project_id" colspan="4" attrs="{'invisible':[('target_project','=','all')], 'required':[('target_project','!=','all')]}"/>
<separator colspan="4"/>
<group colspan="2" col="2">
</group>
<group colspan="2" col="2"> <!-- Improve me -->
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="check_selection" string="C_ompute" type="object"/>
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="check_selection" string="C_ompute" type="object"/>
</group>
</group>
</form>
</group>
</form>
</field>
</record>
</record>
<record id="action_project_compute_phases" model="ir.actions.act_window">
<field name="name">Compute Phase Scheduling</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.compute.phases</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_compute_phases_select"/>
<field name="target">new</field>
<field name="help">To schedule phases of all or a specified project. It then open a gantt view.
</field>
</record>
<record id="action_project_compute_phases" model="ir.actions.act_window">
<field name="name">Compute Phase Scheduling</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.compute.phases</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_compute_phases_select"/>
<field name="target">new</field>
<field name="help">To schedule phases of all or a specified project. It then open a gantt view.
</field>
</record>
<menuitem id="menu_compute_phase" name="Compute Phase Scheduling"
parent="menu_phase_schedule" action="action_project_compute_phases"/>
<menuitem id="menu_compute_phase" name="Compute Phase Scheduling"
parent="menu_phase_schedule" action="action_project_compute_phases"/>
</data>
</openerp>

View File

@ -30,7 +30,7 @@ class project_compute_tasks(osv.osv_memory):
def compute_date(self, cr, uid, ids, context=None):
"""
Schedule the tasks according to resource available and priority.
Schedule the tasks according to users and priority.
"""
project_pool = self.pool.get('project.project')
task_pool = self.pool.get('project.task')

View File

@ -2,39 +2,39 @@
<openerp>
<data>
<record id="view_project_compute_tasks" model="ir.ui.view">
<record id="view_project_compute_tasks" model="ir.ui.view">
<field name="name">Compute Task Scheduling</field>
<field name="model">project.compute.tasks</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Compute Scheduling of Task">
<group colspan="4">
<separator colspan="4" string="Compute Scheduling of Task for specified project." />
<field name="project_id" widget="selection" colspan="4"/>
<form string="Compute Scheduling of Task">
<group colspan="4">
<separator colspan="4" string="Compute Scheduling of Task for specified project." />
<field name="project_id" colspan="4"/>
<separator colspan="4"/>
<group colspan="2" col="2">
</group>
<group colspan="2" col="2">
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="compute_date" string="C_ompute" type="object"/>
</group>
</group>
</form>
<button icon="gtk-ok" name="compute_date" string="C_ompute" type="object"/>
</group>
</group>
</form>
</field>
</record>
</record>
<record id="action_project_compute_tasks" model="ir.actions.act_window">
<field name="name">Compute Task Scheduling</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.compute.tasks</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_compute_tasks"/>
<field name="target">new</field>
</record>
<record id="action_project_compute_tasks" model="ir.actions.act_window">
<field name="name">Compute Task Scheduling</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.compute.tasks</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_compute_tasks"/>
<field name="target">new</field>
</record>
<menuitem id="menu_compute_tasks" name="Compute Task Scheduling"
parent="menu_phase_schedule" action="action_project_compute_tasks"/>
<menuitem id="menu_compute_tasks" name="Compute Task Scheduling"
parent="menu_phase_schedule" action="action_project_compute_tasks"/>
</data>
</openerp>

View File

@ -1,51 +0,0 @@
# -*- 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 osv import fields, osv
class project_schedule_task(osv.osv_memory):
_name = "project.schedule.tasks"
_description = 'project.schedule.tasks'
_columns = {
'msg': fields.char('Message', size=64)
}
_defaults = {
'msg': 'Task Scheduling Completed Successfully'
}
def default_get(self, cr, uid, fields_list, context=None):
res = super(project_schedule_task, self).default_get(cr, uid, fields_list, context)
self.compute_date(cr, uid, context=context)
return res
def compute_date(self, cr, uid, context=None):
"""
Schedule the tasks according to resource available and priority.
"""
phase_pool = self.pool.get('project.phase')
if context is None:
context = {}
if not 'active_id' in context:
return {'type': 'ir.actions.act_window_close'}
return phase_pool.schedule_tasks(cr, uid, [context['active_id']], context=context)
project_schedule_task()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_project_schedule_tasks" model="ir.ui.view">
<field name="name">Schedule Tasks</field>
<field name="model">project.schedule.tasks</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Schedule Tasks">
<group height="90" width="275">
<label string="Task Scheduling completed successfully."/>
<group colspan="4" col="6">
<button icon="gtk-ok" colspan="4" special="cancel" string="_Ok"/>
</group>
</group>
</form>
</field>
</record>
<record id="action_project_schedule_tasks" model="ir.actions.act_window">
<field name="name">Schedule Tasks</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.schedule.tasks</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_schedule_tasks"/>
<field name="context">{'record_id': active_id}</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -265,28 +265,20 @@ class resource_resource(osv.osv):
resource_objs = {}
user_pool = self.pool.get('res.users')
for user in user_pool.browse(cr, uid, user_ids, context=context):
resource_objs[user.id] = {
'name' : user.name,
'vacation': [],
'efficiency': 1.0,
}
resource_ids = self.search(cr, uid, [('user_id', '=', user.id)], context=context)
#assert len(resource_ids) < 1, "User should not has more than one resources"
leaves = []
resource_eff = 1.0
if resource_ids:
for resource in self.browse(cr, uid, resource_ids, context=context):
resource_eff = resource.time_efficiency
resource_objs[user.id]['efficiency'] = resource.time_efficiency
resource_cal = resource.calendar_id.id
if resource_cal:
leaves = self.compute_vacation(cr, uid, calendar_id, resource.id, resource_cal, context=context)
temp = {
'name' : resource.name,
'vacation': tuple(leaves),
'efficiency': resource_eff,
}
resource_objs[resource.id] = temp
# resource_objs.append(classobj(str(user.name), (Resource,),{
# '__doc__': user.name,
# '__name__': user.name,
# 'vacation': tuple(leaves),
# 'efficiency': resource_eff,
# }))
resource_objs[user.id]['vacation'] += list(leaves)
return resource_objs
def compute_vacation(self, cr, uid, calendar_id, resource_id=False, resource_calendar=False, context=None):
@ -323,8 +315,8 @@ class resource_resource(osv.osv):
"""
if not calendar_id:
# Calendar is not specified: working days: 24/7
return [('fri', '1:0-12:0','12:0-24:0'), ('thu', '1:0-12:0','12:0-24:0'), ('wed', '1:0-12:0','12:0-24:0'),
('mon', '1:0-12:0','12:0-24:0'), ('tue', '1:0-12:0','12:0-24:0'), ('sat', '1:0-12:0','12:0-24:0'), ('sun', '1:0-12:0','12:0-24:0')]
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'),
('mon', '8:0-12:0','13:0-17:0'), ('tue', '8:0-12:0','13:0-17:0')]
resource_attendance_pool = self.pool.get('resource.calendar.attendance')
time_range = "8:00-8:00"
non_working = ""