1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 from datetime import datetime
23 from tools.translate import _
24 from osv import fields, osv
25 from resource.faces import task as Task
27 class project_phase(osv.osv):
28 _name = "project.phase"
29 _description = "Project Phase"
31 def _check_recursion(self, cr, uid, ids, context=None):
35 data_phase = self.browse(cr, uid, ids[0], context=context)
36 prev_ids = data_phase.previous_phase_ids
37 next_ids = data_phase.next_phase_ids
38 # it should neither be in prev_ids nor in next_ids
39 if (data_phase in prev_ids) or (data_phase in next_ids):
41 ids = [id for id in prev_ids if id in next_ids]
42 # both prev_ids and next_ids must be unique
46 prev_ids = [rec.id for rec in prev_ids]
47 next_ids = [rec.id for rec in next_ids]
50 cr.execute('SELECT distinct prv_phase_id FROM project_phase_rel WHERE next_phase_id IN %s', (tuple(prev_ids),))
51 prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
52 if data_phase.id in prv_phase_ids:
54 ids = [id for id in prv_phase_ids if id in next_ids]
57 prev_ids = prv_phase_ids
60 cr.execute('SELECT distinct next_phase_id FROM project_phase_rel WHERE prv_phase_id IN %s', (tuple(next_ids),))
61 next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
62 if data_phase.id in next_phase_ids:
64 ids = [id for id in next_phase_ids if id in prev_ids]
67 next_ids = next_phase_ids
70 def _check_dates(self, cr, uid, ids, context=None):
71 for phase in self.read(cr, uid, ids, ['date_start', 'date_end'], context=context):
72 if phase['date_start'] and phase['date_end'] and phase['date_start'] > phase['date_end']:
76 def _check_constraint_start(self, cr, uid, ids, context=None):
77 phase = self.read(cr, uid, ids[0], ['date_start', 'constraint_date_start'], context=context)
78 if phase['date_start'] and phase['constraint_date_start'] and phase['date_start'] < phase['constraint_date_start']:
82 def _check_constraint_end(self, cr, uid, ids, context=None):
83 phase = self.read(cr, uid, ids[0], ['date_end', 'constraint_date_end'], context=context)
84 if phase['date_end'] and phase['constraint_date_end'] and phase['date_end'] > phase['constraint_date_end']:
88 def _get_default_uom_id(self, cr, uid):
89 model_data_obj = self.pool.get('ir.model.data')
90 model_data_id = model_data_obj._get_id(cr, uid, 'product', 'uom_hour')
91 return model_data_obj.read(cr, uid, [model_data_id], ['res_id'])[0]['res_id']
93 def _compute(self, cr, uid, ids, field_name, arg, context=None):
97 for phase in self.browse(cr, uid, ids, context=context):
99 for task in phase.task_ids:
100 tot += task.planned_hours
105 'name': fields.char("Name", size=64, required=True),
106 '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)]}),
107 '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)]}),
108 'constraint_date_start': fields.date('Minimum Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
109 'constraint_date_end': fields.date('Deadline', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
110 'project_id': fields.many2one('project.project', 'Project', required=True),
111 'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases', states={'cancelled':[('readonly',True)]}),
112 'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases', states={'cancelled':[('readonly',True)]}),
113 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of phases."),
114 'duration': fields.float('Duration', required=True, help="By default in days", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
115 '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)]}),
116 'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
117 'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources",states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
118 'responsible_id': fields.many2one('res.users', 'Responsible', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
119 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
120 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.\
121 \n If the phase is over, the states is set to \'Done\'.'),
122 'total_hours': fields.function(_compute, method=True, string='Total Hours'),
125 'responsible_id': lambda obj,cr,uid,context: uid,
128 'product_uom': lambda self,cr,uid,c: self.pool.get('product.uom').search(cr, uid, [('name', '=', _('Day'))], context=c)[0]
130 _order = "project_id, date_start, sequence, name"
132 (_check_recursion,'Loops in phases not allowed',['next_phase_ids', 'previous_phase_ids']),
133 (_check_dates, 'Phase start-date must be lower than phase end-date.', ['date_start', 'date_end']),
136 def onchange_project(self, cr, uid, ids, project, context=None):
138 result['date_start'] = False
139 project_obj = self.pool.get('project.project')
141 project_id = project_obj.browse(cr, uid, project, context=context)
142 result['date_start'] = project_id.date_start
143 return {'value': result}
146 def _check_date_start(self, cr, uid, phase, date_end, context=None):
148 Check And Compute date_end of phase if change in date_start < older time.
150 uom_obj = self.pool.get('product.uom')
151 resource_obj = self.pool.get('resource.resource')
152 cal_obj = self.pool.get('resource.calendar')
153 calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
154 resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
156 res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
157 cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
160 default_uom_id = self._get_default_uom_id(cr, uid)
161 avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
162 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)
163 dt_start = work_times[0][0].strftime('%Y-%m-%d')
164 self.write(cr, uid, [phase.id], {'date_start': dt_start, 'date_end': date_end.strftime('%Y-%m-%d')}, context=context)
166 def _check_date_end(self, cr, uid, phase, date_start, context=None):
168 Check And Compute date_end of phase if change in date_end > older time.
170 uom_obj = self.pool.get('product.uom')
171 resource_obj = self.pool.get('resource.resource')
172 cal_obj = self.pool.get('resource.calendar')
173 calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
174 resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)], context=context)
176 res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
177 cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
180 default_uom_id = self._get_default_uom_id(cr, uid)
181 avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
182 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)
183 dt_end = work_times[-1][1].strftime('%Y-%m-%d')
184 self.write(cr, uid, [phase.id], {'date_start': date_start.strftime('%Y-%m-%d'), 'date_end': dt_end}, context=context)
186 def copy(self, cr, uid, id, default=None, context=None):
189 if not default.get('name', False):
190 default['name'] = self.browse(cr, uid, id, context=context).name + _(' (copy)')
191 return super(project_phase, self).copy(cr, uid, id, default, context)
193 def set_draft(self, cr, uid, ids, *args):
194 self.write(cr, uid, ids, {'state': 'draft'})
197 def set_open(self, cr, uid, ids, *args):
198 self.write(cr, uid, ids, {'state': 'open'})
201 def set_pending(self, cr, uid, ids, *args):
202 self.write(cr, uid, ids, {'state': 'pending'})
205 def set_cancel(self, cr, uid, ids, *args):
206 self.write(cr, uid, ids, {'state': 'cancelled'})
209 def set_done(self, cr, uid, ids, *args):
210 self.write(cr, uid, ids, {'state': 'done'})
213 def generate_phase(self, cr, uid, ids, f, parent=False, context=None):
217 data_pool = self.pool.get('ir.model.data')
218 uom_pool = self.pool.get('product.uom')
219 task_pool = self.pool.get('project.task')
220 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
221 for phase in self.browse(cr, uid, ids, context=context):
222 avg_days = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, day_uom_id)
223 duration = str(avg_days) + 'd'
224 # Create a new project for each phase
225 str_resource = ('%s & '*len(phase.resource_ids))[:-2]
226 str_vals = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, phase.resource_ids))
228 # Phases Defination for the Project
234 '''%(phase.id, phase.name, duration, str_vals or False)
236 # Recalculate date_start and date_end
237 # according to constraints on date start and date end on phase
240 if phase.constraint_date_start:
241 start_date = datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
244 '''%(datetime.strftime(start_date, "%Y-%m-%d"))
247 start = 'up.Phase_%s.end' % (parent.id)
252 start = phase.project_id.date_start or phase.date_start
257 if phase.constraint_date_end :
258 end_date= datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
261 '''%(datetime.strftime(end_date, "%Y-%m-%d"))
264 #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
266 phase_ids.append(phase.id)
269 todo_task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
270 ('state', 'in', ['draft', 'open', 'pending'])
273 for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
274 s += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=False, context=context)
277 task_ids.append(task.id)
280 # Recursive call till all the next phases scheduled
281 for next_phase in phase.next_phase_ids:
282 if next_phase.state in ['draft', 'open', 'pending']:
283 rf, rphase_ids = self.generate_phase(cr, uid, [next_phase.id], f = '', parent=phase, context=context)
285 phase_ids += rphase_ids
290 def schedule_tasks(self, cr, uid, ids, context=None):
292 Schedule tasks base on faces lib
296 if type(ids) in (long, int,):
298 task_pool = self.pool.get('project.task')
299 resource_pool = self.pool.get('resource.resource')
300 for phase in self.browse(cr, uid, ids, context=context):
301 project = phase.project_id
302 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
303 start_date = project.date_start
304 #Creating resources using the member of the Project
305 u_ids = [i.id for i in project.members]
306 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
307 start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
310 minimum_time_unit = 1
312 working_hours_per_day = 24
313 working_days_per_week = 7
314 working_days_per_month = 30
315 working_days_per_year = 365
319 working_hours_per_day = 8 #TODO: it should be come from calendars
320 working_days_per_week = 5
321 working_days_per_month = 20
322 working_days_per_year = 200
323 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
325 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
328 # Creating Resources for the Project
329 for key, vals in resource_objs.items():
331 class Resource_%s(Resource):
335 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
337 # Create a new project for each phase
340 from resource.faces import Resource
343 minimum_time_unit = %s
344 working_hours_per_day = %s
345 working_days_per_week = %s
346 working_days_per_month = %s
347 working_days_per_year = %s
350 '''%(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 )
354 todo_task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
355 ('state', 'in', ['draft', 'open', 'pending'])
357 for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
358 func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True, context=context)
361 task_ids.append(task.id)
364 # Allocating Memory for the required Project and Pahses and Resources
366 Phase = eval('Phase_%d' % phase.id)
369 phase = Task.BalancedProject(Phase)
371 raise osv.except_osv(_('Error !'),_('Invalid Project Members.\nPhase Scheduling is not possible.'))
374 for task_id in task_ids:
375 task = eval("phase.Task_%d" % task_id)
376 start_date = task.start.to_datetime()
377 end_date = task.end.to_datetime()
379 task_pool.write(cr, uid, [task_id], {
380 'date_start': start_date.strftime('%Y-%m-%d'),
381 'date_end': end_date.strftime('%Y-%m-%d')
386 class project_resource_allocation(osv.osv):
387 _name = 'project.resource.allocation'
388 _description = 'Project Resource Allocation'
389 _rec_name = 'resource_id'
391 def get_name(self, cr, uid, ids, field_name, arg, context=None):
393 for allocation in self.browse(cr, uid, ids, context=context):
394 name = allocation.phase_id.name
395 name += ' (%s%%)' %(allocation.useability)
396 res[allocation.id] = name
399 'name': fields.function(get_name, method=True, type='char', size=256),
400 'resource_id': fields.many2one('resource.resource', 'Resource', required=True),
401 'phase_id': fields.many2one('project.phase', 'Project Phase', ondelete='cascade', required=True),
402 'project_id': fields.related('phase_id', 'project_id', type='many2one', relation="project.project", string='Project', store=True),
403 'user_id': fields.related('resource_id', 'user_id', type='many2one', relation="res.users", string='User'),
404 'date_start': fields.date('Start Date', help="Starting Date"),
405 'date_end': fields.date('End Date', help="Ending Date"),
406 'useability': fields.float('Availability', help="Availability of this resource for this project phase in percentage (=50%)"),
412 project_resource_allocation()
414 class project(osv.osv):
415 _inherit = "project.project"
417 'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
418 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
420 def generate_members(self, cr, uid, ids, context=None):
422 Return a list of Resource Class objects for the resources allocated to the phase.
425 resource_pool = self.pool.get('resource.resource')
426 for project in self.browse(cr, uid, ids, context=context):
427 user_ids = map(lambda x:x.id, project.members)
428 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
429 resource_objs = resource_pool.generate_resources(cr, uid, user_ids, calendar_id, context=context)
430 res[project.id] = resource_objs
433 def schedule_phases(self, cr, uid, ids, context=None):
435 Schedule phase base on faces lib
439 if type(ids) in (long, int,):
441 phase_pool = self.pool.get('project.phase')
442 task_pool = self.pool.get('project.task')
443 resource_pool = self.pool.get('resource.resource')
444 data_pool = self.pool.get('ir.model.data')
445 resource_allocation_pool = self.pool.get('project.resource.allocation')
446 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
448 #Checking the Valid Phase resource allocation from project member
449 for project in self.browse(cr, uid, ids, context=context):
453 resource_user_ids = []
455 memebrs_ids = [use.id for use in project.members]
456 phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id)], context=context)
458 for phase in phase_pool.browse(cr, uid, phase_ids, context=context):
459 if phase.resource_ids:
460 res_ids = [ re.id for re in phase.resource_ids]
461 for res in resource_allocation_pool.browse(cr, uid,res_ids, context=context):
462 if res.resource_id.user_id.id not in memebrs_ids:
463 res_msg += " '%s' %s , "%(res.resource_id.name,res.resource_id.user_id.name)
466 raise osv.except_osv(_('Warning !'),_("Resource %s is/are not Members of the Project '%s' .")%(res_msg[:-3], project.name))
468 for project in self.browse(cr, uid, ids, context=context):
469 root_phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
470 ('state', 'in', ['draft', 'open', 'pending']),
471 ('previous_phase_ids', '=', False)
473 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
474 start_date = project.date_start
476 # start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
477 #Creating resources using the member of the Project
478 u_ids = [i.id for i in project.members]
479 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
482 minimum_time_unit = 1
484 working_hours_per_day = 24
485 working_days_per_week = 7
486 working_days_per_month = 30
487 working_days_per_year = 365
491 working_hours_per_day = 8 #TODO: it should be come from calendars
492 working_days_per_week = 5
493 working_days_per_month = 20
494 working_days_per_year = 200
495 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
497 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
500 # Creating Resources for the Project
501 for key, vals in resource_objs.items():
503 class Resource_%s(Resource):
507 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
509 # Create a new project for each phase
512 from resource.faces import Resource
515 minimum_time_unit = %s
516 working_hours_per_day = %s
517 working_days_per_week = %s
518 working_days_per_month = %s
519 working_days_per_year = %s
522 '''%(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 )
526 for root_phase in phase_pool.browse(cr, uid, root_phase_ids, context=context):
527 phases, child_phase_ids = phase_pool.generate_phase(cr, uid, [root_phase.id], '', context=context)
529 phase_ids += child_phase_ids
531 # Allocating Memory for the required Project and Pahses and Resources
533 Project = eval('Project_%d' % project.id)
536 project = Task.BalancedProject(Project)
538 raise osv.except_osv(_('Error !'),_('Invalid Project Members.\nPhase Scheduling is not possible.'))
540 for phase_id in phase_ids:
541 act_phase = phase_pool.browse(cr, uid, phase_id, context=context)
542 resources = act_phase.resource_ids
543 phase = eval("project.Phase_%d" % phase_id)
544 start_date = phase.start.to_datetime()
545 end_date = phase.end.to_datetime()
548 for res in resources:
550 vals.update({'date_start' : start_date })
551 vals.update({'date_end' : end_date})
552 resource_allocation_pool.write(cr, uid, res.id, vals, context=context)
553 if act_phase.task_ids:
554 for task in act_phase.task_ids:
556 #Getting values of the Tasks
557 temp = eval("phase.Task_%s"%task.id)
558 if temp.booked_resource:
559 res_name = temp.booked_resource[0].title
560 res_id = resource_pool.search(cr, uid,[('name','=',res_name)], context = context)
562 res = resource_pool.browse(cr, uid, res_id[0], context = context)
563 vals.update({'user_id' : res.user_id.id})
565 vals.update({'date_start' : temp.start.strftime('%Y-%m-%d %H:%M:%S')})
566 vals.update({'date_end' : temp.end.strftime('%Y-%m-%d %H:%M:%S')})
567 task_pool.write(cr, uid, task.id, vals, context=context)
570 phase_pool.write(cr, uid, [phase_id], {
571 'date_start': start_date.strftime('%Y-%m-%d'),
572 'date_end': end_date.strftime('%Y-%m-%d')
576 #TODO: DO Resource allocation and compute availability
577 def compute_allocation(self, rc, uid, ids, start_date, end_date, context=None):
583 def schedule_tasks(self, cr, uid, ids, context=None):
585 Schedule task base on faces lib
589 if type(ids) in (long, int,):
591 task_pool = self.pool.get('project.task')
592 resource_pool = self.pool.get('resource.resource')
593 data_pool = self.pool.get('ir.model.data')
594 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
596 for project in self.browse(cr, uid, ids, context=context):
597 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
598 start_date = project.date_start
599 #Creating resources using the member of the Project
600 u_ids = [i.id for i in project.members]
601 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
603 start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
605 raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
608 minimum_time_unit = 1
610 working_hours_per_day = 24
611 working_days_per_week = 7
612 working_days_per_month = 30
613 working_days_per_year = 365
617 working_hours_per_day = 8 #TODO: it should be come from calendars
618 working_days_per_week = 5
619 working_days_per_month = 20
620 working_days_per_year = 200
621 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
623 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
626 # Creating Resources for the Project
627 for key, vals in resource_objs.items():
629 class Resource_%s(Resource):
633 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
635 # Create a new project for each phase
638 from resource.faces import Resource
641 minimum_time_unit = %s
642 working_hours_per_day = %s
643 working_days_per_week = %s
644 working_days_per_month = %s
645 working_days_per_year = %s
648 '''%(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 )
652 todo_task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
653 ('state', 'in', ['draft', 'open', 'pending'])
656 for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
657 func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True,context=context)
660 task_ids.append(task.id)
663 # Allocating Memory for the required Project and Pahses and Resources
665 Project = eval('Project_%d' % project.id)
668 project = Task.BalancedProject(Project)
670 raise osv.except_osv(_('Error !'),_('Phase Scheduling is not possible.\nProject should have the Start date and member for scheduling.'))
672 for task_id in task_ids:
673 task = eval("project.Task_%d" % task_id)
674 start_date = task.start.to_datetime()
675 end_date = task.end.to_datetime()
677 task_pool.write(cr, uid, [task_id], {
678 'date_start': start_date.strftime('%Y-%m-%d'),
679 'date_end': end_date.strftime('%Y-%m-%d')
685 class resource_resource(osv.osv):
686 _inherit = "resource.resource"
687 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
690 if context.get('project_id',False):
691 project_pool = self.pool.get('project.project')
692 project_rec = project_pool.browse(cr, uid, context['project_id'], context=context)
693 user_ids = [user_id.id for user_id in project_rec.members]
694 args.append(('user_id','in',user_ids))
695 return super(resource_resource, self).search(cr, uid, args, offset, limit, order, context, count)
699 class project_task(osv.osv):
700 _inherit = "project.task"
702 'phase_id': fields.many2one('project.phase', 'Project Phase'),
708 def generate_task(self, cr, uid, task_id, parent=False, flag=False, context=None):
711 task = self.browse(cr, uid, task_id, context=context)
712 duration = str(task.planned_hours )+ 'H'
714 if task.phase_id.resource_ids:
715 str_resource = ('%s | '*len(task.phase_id.resource_ids))[:-2]
716 str_resource = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, task.phase_id.resource_ids))
717 # Task Defination for the Phase of the Project
724 '''%(task.id, task.name, duration, str_resource)
725 #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
732 '''%(task.id, task.name, duration, str_resource)
736 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: