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 #check known constraints before running Face algorithm in order to have the error translated
365 if not phase.project_id.date_start:
366 raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
367 # Allocating Memory for the required Project and Pahses and Resources
369 Phase = eval('Phase_%d' % phase.id)
372 phase = Task.BalancedProject(Phase)
374 raise osv.except_osv(_('Error !'),e)
376 for task_id in task_ids:
377 task = eval("phase.Task_%d" % task_id)
378 start_date = task.start.to_datetime()
379 end_date = task.end.to_datetime()
381 task_pool.write(cr, uid, [task_id], {
382 'date_start': start_date.strftime('%Y-%m-%d'),
383 'date_end': end_date.strftime('%Y-%m-%d')
388 class project_resource_allocation(osv.osv):
389 _name = 'project.resource.allocation'
390 _description = 'Project Resource Allocation'
391 _rec_name = 'resource_id'
393 def get_name(self, cr, uid, ids, field_name, arg, context=None):
395 for allocation in self.browse(cr, uid, ids, context=context):
396 name = allocation.phase_id.name
397 name += ' (%s%%)' %(allocation.useability)
398 res[allocation.id] = name
401 'name': fields.function(get_name, method=True, type='char', size=256),
402 'resource_id': fields.many2one('resource.resource', 'Resource', required=True),
403 'phase_id': fields.many2one('project.phase', 'Project Phase', ondelete='cascade', required=True),
404 'project_id': fields.related('phase_id', 'project_id', type='many2one', relation="project.project", string='Project', store=True),
405 'user_id': fields.related('resource_id', 'user_id', type='many2one', relation="res.users", string='User'),
406 'date_start': fields.date('Start Date', help="Starting Date"),
407 'date_end': fields.date('End Date', help="Ending Date"),
408 'useability': fields.float('Availability', help="Availability of this resource for this project phase in percentage (=50%)"),
414 project_resource_allocation()
416 class project(osv.osv):
417 _inherit = "project.project"
419 'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
420 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
422 def generate_members(self, cr, uid, ids, context=None):
424 Return a list of Resource Class objects for the resources allocated to the phase.
427 resource_pool = self.pool.get('resource.resource')
428 for project in self.browse(cr, uid, ids, context=context):
429 user_ids = map(lambda x:x.id, project.members)
430 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
431 resource_objs = resource_pool.generate_resources(cr, uid, user_ids, calendar_id, context=context)
432 res[project.id] = resource_objs
435 def schedule_phases(self, cr, uid, ids, context=None):
437 Schedule phase base on faces lib
441 if type(ids) in (long, int,):
443 phase_pool = self.pool.get('project.phase')
444 task_pool = self.pool.get('project.task')
445 resource_pool = self.pool.get('resource.resource')
446 data_pool = self.pool.get('ir.model.data')
447 resource_allocation_pool = self.pool.get('project.resource.allocation')
448 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
450 #Checking the Valid Phase resource allocation from project member
451 for project in self.browse(cr, uid, ids, context=context):
456 members_ids = [user.id for user in project.members]
457 for phase in project.phase_ids:
458 if phase.resource_ids:
459 res_ids = [ re.id for re in phase.resource_ids]
460 for res in resource_allocation_pool.browse(cr, uid, res_ids, context=context):
461 if res.resource_id.user_id.id not in members_ids:
462 res_missing += [res.resource_id.name]
465 raise osv.except_osv(_('Warning !'),_("Resource(s) %s is(are) not member(s) of the project '%s' .") % (",".join(res_missing), project.name))
467 for project in self.browse(cr, uid, ids, context=context):
468 root_phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
469 ('state', 'in', ['draft', 'open', 'pending']),
470 ('previous_phase_ids', '=', False)
472 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
473 start_date = project.date_start
475 # start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
476 #Creating resources using the member of the Project
477 u_ids = [i.id for i in project.members]
478 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
481 minimum_time_unit = 1
483 working_hours_per_day = 24
484 working_days_per_week = 7
485 working_days_per_month = 30
486 working_days_per_year = 365
490 working_hours_per_day = 8 #TODO: it should be come from calendars
491 working_days_per_week = 5
492 working_days_per_month = 20
493 working_days_per_year = 200
494 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
496 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
499 # Creating Resources for the Project
500 for key, vals in resource_objs.items():
502 class Resource_%s(Resource):
506 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
508 # Create a new project for each phase
511 from resource.faces import Resource
514 minimum_time_unit = %s
515 working_hours_per_day = %s
516 working_days_per_week = %s
517 working_days_per_month = %s
518 working_days_per_year = %s
521 '''%(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 )
525 for root_phase in phase_pool.browse(cr, uid, root_phase_ids, context=context):
526 phases, child_phase_ids = phase_pool.generate_phase(cr, uid, [root_phase.id], '', context=context)
528 phase_ids += child_phase_ids
530 project_id = project.id
531 if not project.date_start:
532 raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
533 # Allocating Memory for the required Project and Phases and Resources
535 Project = eval('Project_%d' % project.id)
538 project = Task.BalancedProject(Project)
540 raise osv.except_osv(_('Error !'), e)
542 for phase_id in phase_ids:
543 act_phase = phase_pool.browse(cr, uid, phase_id, context=context)
544 resources = act_phase.resource_ids
545 phase = eval("project.Phase_%d" % phase_id)
546 start_date = phase.start.to_datetime()
547 end_date = phase.end.to_datetime()
550 for res in resources:
552 vals.update({'date_start' : start_date })
553 vals.update({'date_end' : end_date})
554 resource_allocation_pool.write(cr, uid, res.id, vals, context=context)
555 if act_phase.task_ids:
556 for task in act_phase.task_ids:
558 #Getting values of the Tasks
559 temp = eval("phase.Task_%s"%task.id)
560 if temp.booked_resource:
561 res_name = temp.booked_resource[0].title
562 res_id = resource_pool.search(cr, uid,[('name','=',res_name)], context = context)
564 res = resource_pool.browse(cr, uid, res_id[0], context = context)
565 vals.update({'user_id' : res.user_id.id})
567 vals.update({'date_start' : temp.start.strftime('%Y-%m-%d %H:%M:%S')})
568 vals.update({'date_end' : temp.end.strftime('%Y-%m-%d %H:%M:%S')})
569 task_pool.write(cr, uid, task.id, vals, context=context)
572 phase_pool.write(cr, uid, [phase_id], {
573 'date_start': start_date.strftime('%Y-%m-%d'),
574 'date_end': end_date.strftime('%Y-%m-%d')
578 #TODO: DO Resource allocation and compute availability
579 def compute_allocation(self, rc, uid, ids, start_date, end_date, context=None):
585 def schedule_tasks(self, cr, uid, ids, context=None):
587 Schedule task base on faces lib
591 if type(ids) in (long, int,):
593 task_pool = self.pool.get('project.task')
594 resource_pool = self.pool.get('resource.resource')
595 data_pool = self.pool.get('ir.model.data')
596 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
598 for project in self.browse(cr, uid, ids, context=context):
599 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
600 start_date = project.date_start
602 #Checking the Valid Phase resource allocation from project member
607 members_ids = [user.id for user in project.members]
608 for phase in project.phase_ids:
609 if phase.resource_ids:
610 res_ids = [ re.id for re in phase.resource_ids]
611 for res in self.pool.get('project.resource.allocation').browse(cr, uid, res_ids, context=context):
612 if res.resource_id.user_id.id not in members_ids:
613 res_missing += [res.resource_id.name]
616 raise osv.except_osv(_('Warning !'),_("Resource(s) %s is(are) not member(s) of the project '%s' .") % (",".join(res_missing), project.name))
617 #Creating resources using the member of the Project
618 u_ids = [i.id for i in project.members]
619 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
621 start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
623 raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
626 minimum_time_unit = 1
628 working_hours_per_day = 24
629 working_days_per_week = 7
630 working_days_per_month = 30
631 working_days_per_year = 365
635 working_hours_per_day = 8 #TODO: it should be come from calendars
636 working_days_per_week = 5
637 working_days_per_month = 20
638 working_days_per_year = 200
639 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
641 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
644 # Creating Resources for the Project
645 for key, vals in resource_objs.items():
647 class Resource_%s(Resource):
651 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
653 # Create a new project for each phase
656 from resource.faces import Resource
659 minimum_time_unit = %s
660 working_hours_per_day = %s
661 working_days_per_week = %s
662 working_days_per_month = %s
663 working_days_per_year = %s
666 '''%(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 )
670 todo_task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
671 ('state', 'in', ['draft', 'open', 'pending'])
674 for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
675 func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True,context=context)
678 task_ids.append(task.id)
681 if not project.date_start:# or not project.members:
682 raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
683 # Allocating Memory for the required Project and Phases and Resources
685 Project = eval('Project_%d' % project.id)
688 project = Task.BalancedProject(Project)
690 raise osv.except_osv(_('Error !'), e)
692 for task_id in task_ids:
693 task = eval("project.Task_%d" % task_id)
694 start_date = task.start.to_datetime()
695 end_date = task.end.to_datetime()
697 task_pool.write(cr, uid, [task_id], {
698 'date_start': start_date.strftime('%Y-%m-%d'),
699 'date_end': end_date.strftime('%Y-%m-%d')
705 class resource_resource(osv.osv):
706 _inherit = "resource.resource"
707 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
710 if context.get('project_id',False):
711 project_pool = self.pool.get('project.project')
712 project_rec = project_pool.browse(cr, uid, context['project_id'], context=context)
713 user_ids = [user_id.id for user_id in project_rec.members]
714 args.append(('user_id','in',user_ids))
715 return super(resource_resource, self).search(cr, uid, args, offset, limit, order, context, count)
719 class project_task(osv.osv):
720 _inherit = "project.task"
722 'phase_id': fields.many2one('project.phase', 'Project Phase'),
728 def generate_task(self, cr, uid, task_id, parent=False, flag=False, context=None):
731 task = self.browse(cr, uid, task_id, context=context)
732 duration = str(task.planned_hours )+ 'H'
734 parent = task.parent_ids
735 if task.phase_id.resource_ids:
736 str_resource = ('%s | '*len(task.phase_id.resource_ids))[:-2]
737 str_resource = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, task.phase_id.resource_ids))
738 # Task Defination for the Phase of the Project
745 '''%(task.id, task.name, duration, str_resource)
748 start = up.Task_%s.end
756 '''%(task.id, task.name, duration, str_resource)
759 start = up.Task_%s.end
764 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: