diff options
Diffstat (limited to 'addons/project_long_term/wizard')
| -rw-r--r-- | addons/project_long_term/wizard/__init__.py | 2 | ||||
| -rw-r--r-- | addons/project_long_term/wizard/compute_phases_date.py | 129 | ||||
| -rw-r--r-- | addons/project_long_term/wizard/compute_tasks_date.py | 97 | ||||
| -rw-r--r-- | addons/project_long_term/wizard/project_resource.py | 81 | ||||
| -rw-r--r-- | addons/project_long_term/wizard/schedule_tasks.py | 92 | ||||
| -rw-r--r-- | addons/project_long_term/wizard/working_calendar.py | 114 |
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 |
