summaryrefslogtreecommitdiff
path: root/addons/project_long_term/wizard
diff options
context:
space:
mode:
authorFabien Pinckaers <fp@tinyerp.com>2010-03-10 16:23:52 +0100
committerFabien Pinckaers <fp@tinyerp.com>2010-03-10 16:23:52 +0100
commitc8b1ffac18aaf0e1b7e944dbbd63edf00edf8941 (patch)
tree8de94d7753b1cf39e8b026120e756b03781ed5af /addons/project_long_term/wizard
parent36788afa1a982c914f41e00f9b54d579b904cce7 (diff)
parent49738feae5ff778be8c9ca7da67ca649dc0480b2 (diff)
merge
bzr revid: fp@tinyerp.com-20100310152352-9a1yga9rt7aqebvv
Diffstat (limited to 'addons/project_long_term/wizard')
-rw-r--r--addons/project_long_term/wizard/__init__.py2
-rw-r--r--addons/project_long_term/wizard/compute_phases_date.py129
-rw-r--r--addons/project_long_term/wizard/compute_tasks_date.py97
-rw-r--r--addons/project_long_term/wizard/project_resource.py81
-rw-r--r--addons/project_long_term/wizard/schedule_tasks.py92
-rw-r--r--addons/project_long_term/wizard/working_calendar.py114
6 files changed, 291 insertions, 224 deletions
diff --git a/addons/project_long_term/wizard/__init__.py b/addons/project_long_term/wizard/__init__.py
index fffe3ded100..06880dbe6e2 100644
--- a/addons/project_long_term/wizard/__init__.py
+++ b/addons/project_long_term/wizard/__init__.py
@@ -22,7 +22,7 @@
import compute_phases_date
import compute_tasks_date
import schedule_tasks
-import project_resource
+import working_calendar
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/compute_phases_date.py b/addons/project_long_term/wizard/compute_phases_date.py
index 54051b521e2..3c14d7525aa 100644
--- a/addons/project_long_term/wizard/compute_phases_date.py
+++ b/addons/project_long_term/wizard/compute_phases_date.py
@@ -23,9 +23,11 @@ import wizard
import pooler
from tools.translate import _
import datetime
+
from resource.faces import *
from new import classobj
-import project_resource as proj
+
+import working_calendar as wkcal
compute_form = """<?xml version="1.0" ?>
<form string="Compute Scheduling of Phases">
@@ -35,42 +37,54 @@ compute_form = """<?xml version="1.0" ?>
</form>"""
compute_fields = {
- 'project_id': {'string':'Project', 'type':'many2one', 'relation': 'project.project'},
+ 'project_id': {'string':'Project', 'type':'many2one', 'relation':'project.project'},
}
-success_msg = """<?xml version="1.0" ?>
-<form string="Compute Scheduling of Phases">
- <label string="Phase Scheduling completed successfully."/>
-</form>"""
+class wizard_compute_phases(wizard.interface):
+ def _phase_schedule(self, cr, uid, phase, start_date, calendar_id=False, context={}):
+
+ """Schedule phase with the start date till all the next phases are completed.
+
+ Arguements: start_dsate -- start date for the phase
+ calendar_id -- working calendar of the project
+
+ """
-def phase_schedule(cr, uid, phase, start_date, calendar_id=False):
pool = pooler.get_pool(cr.dbname)
- phase_pool = pool.get('project.phase')
- resource_pool = pool.get('resource.resource')
- uom_pool = pool.get('product.uom')
- wktime_cal = []
- resource_cal = False
- phase_resource = False
+ phase_obj = pool.get('project.phase')
+ resource_obj = pool.get('resource.resource')
+ uom_obj = pool.get('product.uom')
+ phase_resource_obj = False
if phase:
- resource_id = resource_pool.search(cr, uid, [('user_id','=',phase.responsible_id.id)])
+ leaves = []
+ time_efficiency = 1.0
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id)[0]
- leaves = proj.leaves_resource(cr, uid, calendar_id or False , resource_id, resource_obj.calendar_id.id)
- phase_resource = classobj(str(resource_obj.name), (Resource,), {'__doc__' : resource_obj.name, '__name__' : resource_obj.name, 'vacation' : tuple(leaves), 'efficiency' : resource_obj.time_efficiency})
- default_uom_id = uom_pool.search(cr, uid, [('name','=','Hour')])[0]
- avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ # Create a new resource object with
+ # all the attributes of the Resource Class
+ resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
+ time_efficiency = resource.time_efficiency
+ leaves = wkcal.compute_leaves(cr, uid, calendar_id or False , resource_id, resource.calendar_id.id)
+ phase_resource_obj = classobj(str(phase.responsible_id.name), (Resource,),
+ {'__doc__': phase.responsible_id.name,
+ '__name__': phase.responsible_id.name,
+ 'vacation': tuple(leaves),
+ 'efficiency': time_efficiency
+ })
+ 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)
duration = str(avg_hours) + 'H'
-
- # Creating a new project for each phase
+ # Create a new project for each phase
def Project():
start = start_date
minimum_time_unit = 1
- resource = phase_resource
- # If project has working calendar else the default one would be considered
+ resource = phase_resource_obj
+ # If project has working calendar then that
+ # else the default one would be considered
if calendar_id:
- working_days = proj.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(proj.leaves_resource(cr, uid, calendar_id))
+ working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
+ vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
def phase():
effort = duration
@@ -78,7 +92,8 @@ def phase_schedule(cr, uid, phase, start_date, calendar_id=False):
project = BalancedProject(Project)
s_date = project.phase.start.to_datetime()
e_date = project.phase.end.to_datetime()
- # According to constraints on date start and date end on phase recalculation done
+ # Recalculate date_start and date_end
+ # according to constraints on date start and date end on phase
if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d %H:%M:%S')
else:
@@ -89,54 +104,59 @@ def phase_schedule(cr, uid, phase, start_date, calendar_id=False):
else:
end_date = e_date
date_start = end_date
-
- # Writing the dates back
- phase_pool.write(cr, uid, [phase.id], {'date_start' :start_date.strftime('%Y-%m-%d %H:%M:%S'), 'date_end' :end_date.strftime('%Y-%m-%d %H:%M:%S')}, context={'scheduler' :True})
-
- # Recursive calling the next phases till all the phases are scheduled
+ # Write the calculated dates back
+ phase_obj.write(cr, uid, [phase.id], {'date_start': start_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_end': end_date.strftime('%Y-%m-%d %H:%M:%S')},
+ context={'scheduler': True
+ })
+ # Recursive call till all the next phases scheduled
for phase in phase.next_phase_ids:
if phase.state in ['draft','open','pending']:
- phase_schedule(cr, uid, phase, date_start, phase.project_id.resource_calendar_id.id or False)
+ self._phase_schedule(cr, uid, phase, date_start, phase.project_id.resource_calendar_id.id or False)
else:
continue
-#
-class wizard_compute_phases(wizard.interface):
-
def _compute_date(self, cr, uid, data, context):
+ """
+ Compute the phases for scheduling.
+ """
pool = pooler.get_pool(cr.dbname)
- project_pool = pool.get('project.project')
- phase_pool = pool.get('project.phase')
-
- # if project mentioned
- if data['form']['project_id']:
- project_id = project_pool.browse(cr, uid, data['form']['project_id'])
- phase_ids = phase_pool.search(cr, uid, [('project_id','=',project_id.id), ('state','in',['draft','open','pending']), ('previous_phase_ids','=',False)])
-
- # else all the draft,open,pending states phases taken
- else:
- phase_ids = phase_pool.search(cr, uid,[('state','in',['draft','open','pending']), ('previous_phase_ids','=',False)])
-
+ project_obj = pool.get('project.project')
+ phase_obj = pool.get('project.phase')
+ if data['form']['project_id']: # If project mentioned find its phases
+ project_id = project_obj.browse(cr, uid, data['form']['project_id'], context=context)
+ phase_ids = phase_obj.search(cr, uid, [('project_id', '=', project_id.id),
+ ('state', 'in', ['draft', 'open', 'pending']),
+ ('previous_phase_ids', '=', False)
+ ])
+ else: # Else take all the draft,open,pending states phases
+ phase_ids = phase_obj.search(cr, uid,[('state', 'in', ['draft', 'open', 'pending']),
+ ('previous_phase_ids', '=', False)
+ ])
phase_ids.sort()
- phase_objs = phase_pool.browse(cr, uid, phase_ids)
+ phase_objs = phase_obj.browse(cr, uid, phase_ids, context=context)
for phase in phase_objs:
start_date = phase.project_id.date_start
if not phase.project_id.date_start:
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
start_dt = datetime.datetime.strftime((datetime.datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d %H:%M")
calendar_id = phase.project_id.resource_calendar_id.id
- phase_schedule(cr, uid, phase, start_dt, calendar_id or False)
+ self._phase_schedule(cr, uid, phase, start_dt, calendar_id or False)
return {}
- def phases_open_list(self, cr, uid, data, context):
+ def _open_phases_list(self, cr, uid, data, context):
+ """
+ Return the scheduled phases list.
+ """
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
result = mod_obj._get_id(cr, uid, 'project_long_term', 'act_project_phase')
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
result = act_obj.read(cr, uid, [id], context=context)[0]
- if data['form']['project_id']:
- result['domain'] = [('project_id', '=', data['form']['project_id'])]
result['domain'] = [('state', 'not in', ['cancelled','done'])]
+ if data['form']['project_id']:
+ result['domain'] = [('project_id', '=', data['form']['project_id']),
+ ('state', 'not in', ['cancelled','done'])]
return result
states = {
@@ -150,11 +170,8 @@ class wizard_compute_phases(wizard.interface):
},
'compute': {
'actions': [_compute_date],
- 'result': {'type': 'action', 'action':phases_open_list, 'state':'end'},
+ 'result': {'type': 'action', 'action':_open_phases_list, 'state':'end'},
},
}
-
wizard_compute_phases('wizard.compute.phases')
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/compute_tasks_date.py b/addons/project_long_term/wizard/compute_tasks_date.py
index 3cf865a48db..cc6a443a454 100644
--- a/addons/project_long_term/wizard/compute_tasks_date.py
+++ b/addons/project_long_term/wizard/compute_tasks_date.py
@@ -23,10 +23,12 @@ import wizard
import pooler
from tools.translate import _
import datetime
+
from resource.faces import *
from new import classobj
import operator
-import project_resource as proj
+
+import working_calendar as wkcal
compute_form = """<?xml version="1.0" ?>
<form string="Compute Scheduling of Tasks">
@@ -39,44 +41,51 @@ success_msg = """<?xml version="1.0" ?>
</form>"""
compute_fields = {
- 'project_id': {'string':'Project', 'type':'many2one', 'relation': 'project.project', 'required':'True'},
+ 'project_id': {'string':'Project', 'type':'many2one', 'relation':'project.project', 'required':'True'},
}
class wizard_compute_tasks(wizard.interface):
def _compute_date(self, cr, uid, data, context):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
pool = pooler.get_pool(cr.dbname)
- project_pool = pool.get('project.project')
+ project_obj = pool.get('project.project')
task_pool = pool.get('project.task')
- resource_pool = pool.get('resource.resource')
- user_pool = pool.get('res.users')
+ resource_obj = pool.get('resource.resource')
+ user_obj = pool.get('res.users')
project_id = data['form']['project_id']
- project = project_pool.browse(cr, uid, project_id)
- task_ids = task_pool.search(cr, uid, [('project_id','=',project_id), ('state','in',['draft','open','pending'])])
+ project = project_obj.browse(cr, uid, project_id, context=context)
+ task_ids = task_pool.search(cr, uid, [('project_id', '=', project_id),
+ ('state', 'in', ['draft', 'open', 'pending'])
+ ])
if task_ids:
- wktime_cal = []
task_ids.sort()
- task_obj = task_pool.browse(cr, uid, task_ids)
+ task_objs = task_pool.browse(cr, uid, task_ids, context=context)
calendar_id = project.resource_calendar_id.id
start_date = project.date_start
if not project.date_start:
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
-
-# To create resources which are the Project Members
- resource_objs = []
- for resource in project.members:
+ # Create Resource Class objects which are the Project Members
+ resources = []
+ for user in project.members:
leaves = []
- resource_id = resource_pool.search(cr, uid, [('user_id','=',resource.id)])
+ time_efficiency = 1.0
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', user.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id)[0]
- leaves = proj.leaves_resource(cr, uid, calendar_id or False , resource_id, resource_obj.calendar_id.id)
- resource_objs.append(classobj(str(resource.name), (Resource,), {'__doc__' : resource.name, '__name__' : resource.name, 'vacation' : tuple(leaves), 'efficiency' : resource_obj.time_efficiency}))
-
- priority_dict = {'0' :1000, '1' :800, '2' :500, '3' :300,'4' :100}
-
-# To create dynamic no of tasks with the resource specified
- def tasks_resource(j, eff, priorty=500, obj=None):
+ resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
+ leaves = wkcal.compute_leaves(cr, uid, calendar_id or False , resource_id, resource.calendar_id.id)
+ time_efficiency = resource.time_efficiency
+ resources.append(classobj(str(user.name), (Resource,), {'__doc__': user.name,
+ '__name__': user.name,
+ 'vacation': tuple(leaves),
+ 'efficiency': time_efficiency
+ }))
+ priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300,'4': 100}
+ # Create dynamic no of tasks with the resource specified
+ def create_tasks(j, eff, priorty=500, obj=None):
def task():
"""
task is a dynamic method!
@@ -89,43 +98,47 @@ class wizard_compute_tasks(wizard.interface):
task.__name__ = "task%d" %j
return task
-# Creating the project with all the tasks and resources
+ # Create a 'Faces' project with all the tasks and resources
def Project():
title = project.name
start = date_start
- resource = reduce(operator.or_, resource_objs)
+ try:
+ resource = reduce(operator.or_, resources)
+ except:
+ raise wizard.except_wizard(_('MemberError'), _('Project must have members assigned !'))
minimum_time_unit = 1
-
-# If project has calendar
- if calendar_id:
- working_days = proj.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(proj.leaves_resource(cr, uid, calendar_id))
-
-# Dynamic Creation of tasks
+ if calendar_id: # If project has calendar
+ working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
+ vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
+ # Dynamic Creation of tasks
i = 0
- for each_task in task_obj:
+ for each_task in task_objs:
hours = str(each_task.planned_hours / each_task.occupation_rate)+ 'H'
if each_task.priority in priority_dict.keys():
priorty = priority_dict[each_task.priority]
if each_task.user_id:
- for resource_object in resource_objs:
- if resource_object.__name__ == each_task.user_id.name:
- task = tasks_resource(i, hours, priorty, resource_object)
+ for resource in resources:
+ if resource.__name__ == each_task.user_id.name:
+ task = create_tasks(i, hours, priorty, resource)
else:
- task = tasks_resource(i, hours, priorty)
+ task = create_tasks(i, hours, priorty)
i += 1
-# Writing back the dates
project = BalancedProject(Project)
loop_no = 0
+ # Write back the computed dates
for t in project:
s_date = t.start.to_datetime()
e_date = t.end.to_datetime()
if loop_no == 0:
- project_pool.write(cr, uid, [project_id], {'date' : e_date})
+ project_obj.write(cr, uid, [project_id], {'date' : e_date})
else:
- user_id = user_pool.search(cr, uid, [('name','=',t.booked_resource[0].__name__)])
- task_pool.write(cr, uid, [task_obj[loop_no-1].id], {'date_start' :s_date.strftime('%Y-%m-%d %H:%M:%S'), 'date_deadline' :e_date.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' :user_id[0]}, context={'scheduler' :True})
+ user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
+ task_pool.write(cr, uid, [task_objs[loop_no-1].id], {'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_deadline': e_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'user_id': user_id[0]},
+ context={'scheduler': True
+ })
loop_no +=1
return {}
@@ -137,14 +150,10 @@ class wizard_compute_tasks(wizard.interface):
('compute', 'Compute')
]},
},
-
-
'compute': {
'actions': [_compute_date],
'result': {'type':'form','arch':success_msg,'fields':{}, 'state':[('end', 'Ok')]},
}
}
wizard_compute_tasks('wizard.compute.tasks')
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/project_resource.py b/addons/project_long_term/wizard/project_resource.py
deleted file mode 100644
index c3bc686d980..00000000000
--- a/addons/project_long_term/wizard/project_resource.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import pooler
-import datetime
-
-def timeformat_convert(cr, uid, time_string, context={}):
-# Function to convert input time string:: 8.5 to output time string 8:30
-
- split_list = str(time_string).split('.')
- hour_part = split_list[0]
- mins_part = split_list[1]
- round_mins = int(round(float(mins_part) * 60,-2))
- converted_string = hour_part + ':' + str(round_mins)[0:2]
- return converted_string
-
-def leaves_resource(cr, uid, calendar_id, resource_id=False, resource_calendar=False):
-# To get the leaves for the resource_ids working on phase
-
- pool = pooler.get_pool(cr.dbname)
- resource_leaves_pool = pool.get('resource.calendar.leaves')
- leaves = []
- if resource_id:
- resource_leave_ids = resource_leaves_pool.search(cr, uid, ['|', ('calendar_id','=',calendar_id), ('calendar_id','=',resource_calendar), ('resource_id','=',resource_id)])
- else:
- resource_leave_ids = resource_leaves_pool.search(cr, uid, [('calendar_id','=',calendar_id), ('resource_id','=',False)])
- res_leaves = resource_leaves_pool.read(cr, uid, resource_leave_ids, ['date_from', 'date_to'])
- for leave in range(len(res_leaves)):
- dt_start = datetime.datetime.strptime(res_leaves[leave]['date_from'], '%Y-%m-%d %H:%M:%S')
- dt_end = datetime.datetime.strptime(res_leaves[leave]['date_to'], '%Y-%m-%d %H:%M:%S')
- no = dt_end - dt_start
- [leaves.append((dt_start + datetime.timedelta(days=x)).strftime('%Y-%m-%d')) for x in range(int(no.days + 1))]
- leaves.sort()
- return leaves
-
-def compute_working_calendar(cr, uid, calendar_id):
-# To change the format of working calendar to bring it into 'faces' format
-
- pool = pooler.get_pool(cr.dbname)
- resource_week_pool = pool.get('resource.calendar.week')
- time_range = "8:00-8:00"
- non_working = ""
- wk = {"0":"mon","1":"tue","2":"wed","3":"thu","4":"fri","5":"sat","6":"sun"}
- wk_days = {}
- wk_time = {}
- wktime_list = []
- wktime_cal = []
- week_ids = resource_week_pool.search(cr, uid, [('calendar_id','=',calendar_id)])
- week_obj = resource_week_pool.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'])
-
-# Converting time formats into appropriate format required
-# and creating a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
- for week in week_obj:
- res_str = ""
- if wk.has_key(week['dayofweek']):
- day = wk[week['dayofweek']]
- wk_days[week['dayofweek']] = wk[week['dayofweek']]
-
- hour_from_str = timeformat_convert(cr, uid, week['hour_from'])
- hour_to_str = timeformat_convert(cr, uid, week['hour_to'])
- res_str = hour_from_str + '-' + hour_to_str
- wktime_list.append((day, res_str))
-
-# Converting it to format like [('mon', '8:00-12:00', '13:00-18:00')]
- for item in wktime_list:
- if wk_time.has_key(item[0]):
- wk_time[item[0]].append(item[1])
- else:
- wk_time[item[0]] = [item[0]]
- wk_time[item[0]].append(item[1])
-
- for k,v in wk_time.items():
- wktime_cal.append(tuple(v))
-
-# For non working days adding [('tue,wed,fri,sat,sun', '8:00-8:00')]
- for k,v in wk_days.items():
- if wk.has_key(k):
- wk.pop(k)
- for v in wk.itervalues():
- non_working += v + ','
- if non_working:
- wktime_cal.append((non_working[:-1], time_range))
-
- return wktime_cal \ No newline at end of file
diff --git a/addons/project_long_term/wizard/schedule_tasks.py b/addons/project_long_term/wizard/schedule_tasks.py
index ac968e276f6..6db678333a9 100644
--- a/addons/project_long_term/wizard/schedule_tasks.py
+++ b/addons/project_long_term/wizard/schedule_tasks.py
@@ -23,45 +23,53 @@ import wizard
import pooler
from tools.translate import _
import datetime
+
from resource.faces import *
from new import classobj
import operator
-import time
-import project_resource as proj
+
+import working_calendar as wkcal
success_msg = """<?xml version="1.0" ?>
<form string="Compute Scheduling of Tasks">
<label string="Task Scheduling completed successfully."/>
</form>"""
-def resource_list(cr, uid, phase):
-# To create resources which are the Project Members
+class wizard_schedule_task(wizard.interface):
+ def _create_resources(self, cr, uid, phase, context={}):
+ """
+ Return a list of Resource Class objects for the resources allocated to the phase.
+ """
resource_objs = []
for resource in phase.resource_ids:
res = resource.resource_id
leaves = []
resource_eff = res.time_efficiency
resource_cal = res.calendar_id.id
- wktime_cal = proj.compute_working_calendar(cr, uid, resource_cal)
- leaves = proj.leaves_resource(cr, uid, phase.project_id.resource_calendar_id.id or False , res.id, resource_cal)
- resource_objs.append(classobj(str(res.user_id.name), (Resource,), {'__doc__' : res.user_id.name, '__name__' : res.user_id.name, 'vacation' : tuple(leaves), 'efficiency' : resource_eff}))
+ if resource_cal:
+ leaves = wkcal.compute_leaves(cr, uid, phase.project_id.resource_calendar_id.id or False, res.id, resource_cal)
+ resource_objs.append(classobj(str(res.user_id.name), (Resource,),
+ {'__doc__': res.user_id.name,
+ '__name__': res.user_id.name,
+ 'vacation': tuple(leaves),
+ 'efficiency': resource_eff
+ }))
return resource_objs
-class wizard_schedule_task(wizard.interface):
-
def _compute_date(self, cr, uid, data, context):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
pool = pooler.get_pool(cr.dbname)
- phase_pool = pool.get('project.phase')
- task_pool = pool.get('project.task')
- user_pool = pool.get('res.users')
- phase = phase_pool.browse(cr, uid, data['id'])
- task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open','draft','pending'] , phase.task_ids)))
-
+ phase_obj = pool.get('project.phase')
+ task_obj = pool.get('project.task')
+ user_obj = pool.get('res.users')
+ phase = phase_obj.browse(cr, uid, data['id'], context=context)
+ task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open', 'draft', 'pending'] , phase.task_ids)))
if task_ids:
task_ids.sort()
- tasks = task_pool.browse(cr, uid, task_ids)
- wktime_cal = []
+ tasks = task_obj.browse(cr, uid, task_ids, context=context)
start_date = str(phase.date_start)[:-9]
if not phase.date_start:
if not phase.project_id.date_start:
@@ -70,11 +78,10 @@ class wizard_schedule_task(wizard.interface):
start_date = phase.project_id.date_start
date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
calendar_id = phase.project_id.resource_calendar_id.id
- resource_objs = resource_list(cr, uid, phase)
- priority_dict = {'0' :1000,'1' :800,'2' :500,'3' :300,'4' :100}
-
-# To create dynamic no of tasks with the resource specified
- def tasks_resource(j, eff, priorty=500, obj=False):
+ resources = self._create_resources(cr, uid, phase)
+ priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300, '4': 100}
+ # Create dynamic no of tasks with the resource specified
+ def create_tasks(j, eff, priorty=500, obj=False):
def task():
"""
task is a dynamic method!
@@ -87,44 +94,47 @@ class wizard_schedule_task(wizard.interface):
task.__name__ = "task%d" %j
return task
-# Creating the project with all the tasks and resources
+ # Create a 'Faces' project with all the tasks and resources
def Project():
- title = "Test Project"
+ title = "Project"
start = date_start
- resource = reduce(operator.or_, resource_objs)
+ try:
+ resource = reduce(operator.or_, resources)
+ except:
+ raise wizard.except_wizard(_('ResourceError'), _('Phase must have resources assigned !'))
minimum_time_unit = 1
-
-# If project has calendar
- if calendar_id:
- working_days = proj.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(proj.leaves_resource(cr, uid, calendar_id))
-
-# Dynamic Creation of tasks
+ if calendar_id: # If project has working calendar
+ working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
+ vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
+ # Dynamic creation of tasks
i = 0
for each_task in tasks:
hours = str(each_task.planned_hours / each_task.occupation_rate)+ 'H'
if each_task.priority in priority_dict.keys():
priorty = priority_dict[each_task.priority]
if each_task.user_id:
- for resource_object in resource_objs:
- if resource_object.__name__ == each_task.user_id.name:
- task = tasks_resource(i, hours, priorty, resource_object)
+ for resource in resources:
+ if resource.__name__ == each_task.user_id.name:
+ task = create_tasks(i, hours, priorty, resource)
else:
- task = tasks_resource(i, hours, priorty)
+ task = create_tasks(i, hours, priorty)
i += 1
-# Writing back the dates
project = BalancedProject(Project)
loop_no = 0
+ # Write back the computed dates
for t in project:
s_date = t.start.to_datetime()
e_date = t.end.to_datetime()
if loop_no > 0:
- user_id = user_pool.search(cr, uid, [('name','=',t.booked_resource[0].__name__)])
- task_pool.write(cr, uid, [tasks[loop_no-1].id], {'date_start' :s_date.strftime('%Y-%m-%d %H:%M:%S'), 'date_deadline' :e_date.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' :user_id[0]}, context={'scheduler' :True})
+ user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
+ task_obj.write(cr, uid, [tasks[loop_no-1].id], {'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_deadline': e_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'user_id': user_id[0]},
+ context={'scheduler': True
+ })
loop_no +=1
return {}
-
states = {
'init': {
'actions': [_compute_date],
@@ -132,6 +142,4 @@ class wizard_schedule_task(wizard.interface):
}
}
wizard_schedule_task('phase.schedule.tasks')
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/working_calendar.py b/addons/project_long_term/wizard/working_calendar.py
new file mode 100644
index 00000000000..faddcdd0011
--- /dev/null
+++ b/addons/project_long_term/wizard/working_calendar.py
@@ -0,0 +1,114 @@
+# -*- 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/>.
+#
+##############################################################################
+
+import pooler
+import datetime
+
+def convert_timeformat(cr, uid, time_string, context={}):
+ """ Convert input time string: 8.5 to output time string 8:30."""
+
+ split_list = str(time_string).split('.')
+ hour_part = split_list[0]
+ mins_part = split_list[1]
+ round_mins = int(round(float(mins_part) * 60,-2))
+ converted_string = hour_part + ':' + str(round_mins)[0:2]
+ return converted_string
+
+def compute_leaves(cr, uid, calendar_id, resource_id=False, resource_calendar=False):
+
+ """Compute the leaves from the working calendar of the resource.
+
+ Arguements: calendar_id -- working calendar of the project
+ resource_id -- resource working on phase/task
+ resource_calendar -- working calendar of the resource
+
+ """
+
+ pool = pooler.get_pool(cr.dbname)
+ resource_calendar_leaves_obj = pool.get('resource.calendar.leaves')
+ leave_list = []
+ if resource_id:
+ leave_ids = resource_calendar_leaves_obj.search(cr, uid, ['|', ('calendar_id', '=', calendar_id),
+ ('calendar_id', '=', resource_calendar),
+ ('resource_id', '=', resource_id)
+ ])
+ else:
+ leave_ids = resource_calendar_leaves_obj.search(cr, uid, [('calendar_id', '=', calendar_id),
+ ('resource_id', '=', False)
+ ])
+ leaves = resource_calendar_leaves_obj.read(cr, uid, leave_ids, ['date_from', 'date_to'])
+ for i in range(len(leaves)):
+ dt_start = datetime.datetime.strptime(leaves[i]['date_from'], '%Y-%m-%d %H:%M:%S')
+ dt_end = datetime.datetime.strptime(leaves[i]['date_to'], '%Y-%m-%d %H:%M:%S')
+ no = dt_end - dt_start
+ [leave_list.append((dt_start + datetime.timedelta(days=x)).strftime('%Y-%m-%d')) for x in range(int(no.days + 1))]
+ leave_list.sort()
+ return leave_list
+
+def compute_working_calendar(cr, uid, calendar_id):
+
+ """Change the format of working calendar from 'Openerp' format to bring it into 'Faces' format.
+
+ Arguement: calendar_id -- working calendar of the project
+
+ """
+
+ pool = pooler.get_pool(cr.dbname)
+ resource_week_obj = pool.get('resource.calendar.week')
+ time_range = "8:00-8:00"
+ non_working = ""
+ week_days = {"0": "mon", "1": "tue", "2": "wed","3": "thu", "4": "fri", "5": "sat", "6": "sun"}
+ wk_days = {}
+ wk_time = {}
+ wktime_list = []
+ wktime_cal = []
+ week_ids = resource_week_obj.search(cr, uid, [('calendar_id', '=', calendar_id)])
+ weeks = resource_week_obj.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'])
+ # Convert time formats into appropriate format required
+ # and create a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
+ for week in weeks:
+ res_str = ""
+ if week_days.has_key(week['dayofweek']):
+ day = week_days[week['dayofweek']]
+ wk_days[week['dayofweek']] = week_days[week['dayofweek']]
+ hour_from_str = convert_timeformat(cr, uid, week['hour_from'])
+ hour_to_str = convert_timeformat(cr, uid, week['hour_to'])
+ res_str = hour_from_str + '-' + hour_to_str
+ wktime_list.append((day, res_str))
+ # Convert into format like [('mon', '8:00-12:00', '13:00-18:00')]
+ for item in wktime_list:
+ if wk_time.has_key(item[0]):
+ wk_time[item[0]].append(item[1])
+ else:
+ wk_time[item[0]] = [item[0]]
+ wk_time[item[0]].append(item[1])
+ for k,v in wk_time.items():
+ wktime_cal.append(tuple(v))
+ # Add for the non-working days like: [('sat, sun', '8:00-8:00')]
+ for k,v in wk_days.items():
+ if week_days.has_key(k):
+ week_days.pop(k)
+ for v in week_days.itervalues():
+ non_working += v + ','
+ if non_working:
+ wktime_cal.append((non_working[:-1], time_range))
+ return wktime_cal
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file