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 for project in self.browse(cr, uid, ids, context=context):
449 root_phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
450 ('state', 'in', ['draft', 'open', 'pending']),
451 ('previous_phase_ids', '=', False)
453 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
454 start_date = project.date_start
456 # start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
457 #Creating resources using the member of the Project
458 u_ids = [i.id for i in project.members]
459 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
462 minimum_time_unit = 1
464 working_hours_per_day = 24
465 working_days_per_week = 7
466 working_days_per_month = 30
467 working_days_per_year = 365
471 working_hours_per_day = 8 #TODO: it should be come from calendars
472 working_days_per_week = 5
473 working_days_per_month = 20
474 working_days_per_year = 200
475 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
477 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
480 # Creating Resources for the Project
481 for key, vals in resource_objs.items():
483 class Resource_%s(Resource):
487 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
489 # Create a new project for each phase
492 from resource.faces import Resource
495 minimum_time_unit = %s
496 working_hours_per_day = %s
497 working_days_per_week = %s
498 working_days_per_month = %s
499 working_days_per_year = %s
502 '''%(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 )
506 for root_phase in phase_pool.browse(cr, uid, root_phase_ids, context=context):
507 phases, child_phase_ids = phase_pool.generate_phase(cr, uid, [root_phase.id], '', context=context)
509 phase_ids += child_phase_ids
511 # Allocating Memory for the required Project and Pahses and Resources
513 Project = eval('Project_%d' % project.id)
516 project = Task.BalancedProject(Project)
518 raise osv.except_osv(_('Error !'),_('Invalid Project Members.\nPhase Scheduling is not possible.'))
520 for phase_id in phase_ids:
521 act_phase = phase_pool.browse(cr, uid, phase_id, context=context)
522 resources = act_phase.resource_ids
523 phase = eval("project.Phase_%d" % phase_id)
524 start_date = phase.start.to_datetime()
525 end_date = phase.end.to_datetime()
528 for res in resources:
530 vals.update({'date_start' : start_date })
531 vals.update({'date_end' : end_date})
532 resource_allocation_pool.write(cr, uid, res.id, vals, context=context)
533 if act_phase.task_ids:
534 for task in act_phase.task_ids:
536 #Getting values of the Tasks
537 temp = eval("phase.Task_%s"%task.id)
538 if temp.booked_resource:
539 res_name = temp.booked_resource[0].title
540 res_id = resource_pool.search(cr, uid,[('name','=',res_name)], context = context)
542 res = resource_pool.browse(cr, uid, res_id[0], context = context)
543 vals.update({'user_id' : res.user_id.id})
545 vals.update({'date_start' : temp.start.strftime('%Y-%m-%d %H:%M:%S')})
546 vals.update({'date_end' : temp.end.strftime('%Y-%m-%d %H:%M:%S')})
547 task_pool.write(cr, uid, task.id, vals, context=context)
550 phase_pool.write(cr, uid, [phase_id], {
551 'date_start': start_date.strftime('%Y-%m-%d'),
552 'date_end': end_date.strftime('%Y-%m-%d')
556 #TODO: DO Resource allocation and compute availability
557 def compute_allocation(self, rc, uid, ids, start_date, end_date, context=None):
563 def schedule_tasks(self, cr, uid, ids, context=None):
565 Schedule task base on faces lib
569 if type(ids) in (long, int,):
571 task_pool = self.pool.get('project.task')
572 resource_pool = self.pool.get('resource.resource')
573 data_pool = self.pool.get('ir.model.data')
574 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
576 for project in self.browse(cr, uid, ids, context=context):
577 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
578 start_date = project.date_start
579 #Creating resources using the member of the Project
580 u_ids = [i.id for i in project.members]
581 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
583 start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
585 raise osv.except_osv(_('Error !'),_('Task Scheduling is not possible.\nProject should have the Start date for scheduling.'))
588 minimum_time_unit = 1
590 working_hours_per_day = 24
591 working_days_per_week = 7
592 working_days_per_month = 30
593 working_days_per_year = 365
597 working_hours_per_day = 8 #TODO: it should be come from calendars
598 working_days_per_week = 5
599 working_days_per_month = 20
600 working_days_per_year = 200
601 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
603 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
606 # Creating Resources for the Project
607 for key, vals in resource_objs.items():
609 class Resource_%s(Resource):
613 '''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
615 # Create a new project for each phase
618 from resource.faces import Resource
621 minimum_time_unit = %s
622 working_hours_per_day = %s
623 working_days_per_week = %s
624 working_days_per_month = %s
625 working_days_per_year = %s
628 '''%(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 )
632 todo_task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
633 ('state', 'in', ['draft', 'open', 'pending'])
636 for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
637 func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True,context=context)
640 task_ids.append(task.id)
643 # Allocating Memory for the required Project and Pahses and Resources
645 Project = eval('Project_%d' % project.id)
648 project = Task.BalancedProject(Project)
650 raise osv.except_osv(_('Error !'),_('Phase Scheduling is not possible.\nProject should have the Start date and member for scheduling.'))
652 for task_id in task_ids:
653 task = eval("project.Task_%d" % task_id)
654 start_date = task.start.to_datetime()
655 end_date = task.end.to_datetime()
657 task_pool.write(cr, uid, [task_id], {
658 'date_start': start_date.strftime('%Y-%m-%d'),
659 'date_end': end_date.strftime('%Y-%m-%d')
665 class resource_resource(osv.osv):
666 _inherit = "resource.resource"
667 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
670 if context.get('project_id',False):
671 project_pool = self.pool.get('project.project')
672 project_rec = project_pool.browse(cr, uid, context['project_id'], context=context)
673 user_ids = [user_id.id for user_id in project_rec.members]
674 args.append(('user_id','in',user_ids))
675 return super(resource_resource, self).search(cr, uid, args, offset, limit, order, context, count)
679 class project_task(osv.osv):
680 _inherit = "project.task"
682 'phase_id': fields.many2one('project.phase', 'Project Phase'),
688 def generate_task(self, cr, uid, task_id, parent=False, flag=False, context=None):
691 task = self.browse(cr, uid, task_id, context=context)
692 duration = str(task.planned_hours )+ 'H'
694 if task.phase_id.resource_ids:
695 str_resource = ('%s | '*len(task.phase_id.resource_ids))[:-2]
696 str_resource = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, task.phase_id.resource_ids))
697 # Task Defination for the Phase of the Project
704 '''%(task.id, task.name, duration, str_resource)
705 #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
712 '''%(task.id, task.name, duration, str_resource)
716 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: