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, timedelta
23 from dateutil.relativedelta import relativedelta
24 from tools.translate import _
25 from osv import fields, osv
26 from resource.faces import task as Task
28 from new import classobj
32 class project_phase(osv.osv):
33 _name = "project.phase"
34 _description = "Project Phase"
36 def _check_recursion(self, cr, uid, ids, context=None):
40 data_phase = self.browse(cr, uid, ids[0], context=context)
41 prev_ids = data_phase.previous_phase_ids
42 next_ids = data_phase.next_phase_ids
43 # it should neither be in prev_ids nor in next_ids
44 if (data_phase in prev_ids) or (data_phase in next_ids):
46 ids = [id for id in prev_ids if id in next_ids]
47 # both prev_ids and next_ids must be unique
51 prev_ids = [rec.id for rec in prev_ids]
52 next_ids = [rec.id for rec in next_ids]
55 cr.execute('SELECT distinct prv_phase_id FROM project_phase_rel WHERE next_phase_id IN %s', (tuple(prev_ids),))
56 prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
57 if data_phase.id in prv_phase_ids:
59 ids = [id for id in prv_phase_ids if id in next_ids]
62 prev_ids = prv_phase_ids
65 cr.execute('SELECT distinct next_phase_id FROM project_phase_rel WHERE prv_phase_id IN %s', (tuple(next_ids),))
66 next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
67 if data_phase.id in next_phase_ids:
69 ids = [id for id in next_phase_ids if id in prev_ids]
72 next_ids = next_phase_ids
75 def _check_dates(self, cr, uid, ids, context=None):
76 for phase in self.read(cr, uid, ids, ['date_start', 'date_end'], context=context):
77 if phase['date_start'] and phase['date_end'] and phase['date_start'] > phase['date_end']:
81 def _check_constraint_start(self, cr, uid, ids, context=None):
82 phase = self.read(cr, uid, ids[0], ['date_start', 'constraint_date_start'], context=context)
83 if phase['date_start'] and phase['constraint_date_start'] and phase['date_start'] < phase['constraint_date_start']:
87 def _check_constraint_end(self, cr, uid, ids, context=None):
88 phase = self.read(cr, uid, ids[0], ['date_end', 'constraint_date_end'], context=context)
89 if phase['date_end'] and phase['constraint_date_end'] and phase['date_end'] > phase['constraint_date_end']:
93 def _get_default_uom_id(self, cr, uid):
94 model_data_obj = self.pool.get('ir.model.data')
95 model_data_id = model_data_obj._get_id(cr, uid, 'product', 'uom_hour')
96 return model_data_obj.read(cr, uid, [model_data_id], ['res_id'])[0]['res_id']
98 def _compute(self, cr, uid, ids, field_name, arg, context=None):
102 for phase in self.browse(cr, uid, ids, context=context):
104 for task in phase.task_ids:
105 tot += task.planned_hours
110 'name': fields.char("Name", size=64, required=True),
111 '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)]}),
112 '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)]}),
113 'constraint_date_start': fields.date('Minimum Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
114 'constraint_date_end': fields.date('Deadline', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
115 'project_id': fields.many2one('project.project', 'Project', required=True),
116 'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases', states={'cancelled':[('readonly',True)]}),
117 'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases', states={'cancelled':[('readonly',True)]}),
118 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of phases."),
119 'duration': fields.float('Duration', required=True, help="By default in days", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
120 '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)]}),
121 'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
122 'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources",states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
123 'responsible_id': fields.many2one('res.users', 'Responsible', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
124 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
125 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.\
126 \n If the phase is over, the states is set to \'Done\'.'),
127 'total_hours': fields.function(_compute, method=True, string='Total Hours'),
130 'responsible_id': lambda obj,cr,uid,context: uid,
133 'product_uom': lambda self,cr,uid,c: self.pool.get('product.uom').search(cr, uid, [('name', '=', _('Day'))], context=c)[0]
135 _order = "project_id, date_start, sequence, name"
137 (_check_recursion,'Loops in phases not allowed',['next_phase_ids', 'previous_phase_ids']),
138 (_check_dates, 'Phase start-date must be lower than phase end-date.', ['date_start', 'date_end']),
141 def onchange_project(self, cr, uid, ids, project, context=None):
143 result['date_start'] = False
144 project_obj = self.pool.get('project.project')
146 project_id = project_obj.browse(cr, uid, project, context=context)
147 result['date_start'] = project_id.date_start
148 return {'value': result}
151 def _check_date_start(self, cr, uid, phase, date_end, context=None):
153 Check And Compute date_end of phase if change in date_start < older time.
155 uom_obj = self.pool.get('product.uom')
156 resource_obj = self.pool.get('resource.resource')
157 cal_obj = self.pool.get('resource.calendar')
158 calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
159 resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
161 res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
162 cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
165 default_uom_id = self._get_default_uom_id(cr, uid)
166 avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
167 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)
168 dt_start = work_times[0][0].strftime('%Y-%m-%d')
169 self.write(cr, uid, [phase.id], {'date_start': dt_start, 'date_end': date_end.strftime('%Y-%m-%d')}, context=context)
171 def _check_date_end(self, cr, uid, phase, date_start, context=None):
173 Check And Compute date_end of phase if change in date_end > older time.
175 uom_obj = self.pool.get('product.uom')
176 resource_obj = self.pool.get('resource.resource')
177 cal_obj = self.pool.get('resource.calendar')
178 calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
179 resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)], context=context)
181 res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
182 cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
185 default_uom_id = self._get_default_uom_id(cr, uid)
186 avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
187 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)
188 dt_end = work_times[-1][1].strftime('%Y-%m-%d')
189 self.write(cr, uid, [phase.id], {'date_start': date_start.strftime('%Y-%m-%d'), 'date_end': dt_end}, context=context)
191 def copy(self, cr, uid, id, default=None, context=None):
194 if not default.get('name', False):
195 default['name'] = self.browse(cr, uid, id, context=context).name + _(' (copy)')
196 return super(project_phase, self).copy(cr, uid, id, default, context)
198 def set_draft(self, cr, uid, ids, *args):
199 self.write(cr, uid, ids, {'state': 'draft'})
202 def set_open(self, cr, uid, ids, *args):
203 self.write(cr, uid, ids, {'state': 'open'})
206 def set_pending(self, cr, uid, ids, *args):
207 self.write(cr, uid, ids, {'state': 'pending'})
210 def set_cancel(self, cr, uid, ids, *args):
211 self.write(cr, uid, ids, {'state': 'cancelled'})
214 def set_done(self, cr, uid, ids, *args):
215 self.write(cr, uid, ids, {'state': 'done'})
218 def generate_phase(self, cr, uid, ids, f, parent=False, context=None):
222 resource_pool = self.pool.get('resource.resource')
223 data_pool = self.pool.get('ir.model.data')
224 resource_allocation_pool = self.pool.get('project.resource.allocation')
225 uom_pool = self.pool.get('product.uom')
226 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
227 for phase in self.browse(cr, uid, ids, context=context):
228 avg_days = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, day_uom_id)
229 duration = str(avg_days) + 'd'
230 # Create a new project for each phase
231 str_resource = ('%s,'*len(phase.resource_ids))[:-1]
232 str_vals = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, phase.resource_ids))
233 # Phases Defination for the Project
238 '''%(phase.id, duration, str_vals or False)
240 start = 'up.Phase_%s.end' % (parent.id)
242 start = phase.project_id.date_start or phase.date_start
243 #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
248 phase_ids.append(phase.id)
249 # Recursive call till all the next phases scheduled
250 for next_phase in phase.next_phase_ids:
251 if next_phase.state in ['draft', 'open', 'pending']:
252 rf, rphase_ids = self.generate_phase(cr, uid, [next_phase.id], f = '', parent=phase, context=context)
254 phase_ids += rphase_ids
261 def schedule_tasks(self, cr, uid, ids, context=None):
263 Schedule the tasks according to resource available and priority.
265 task_pool = self.pool.get('project.task')
266 resource_pool = self.pool.get('resource.resource')
267 resources_list = self.generate_resources(cr, uid, ids, context=context)
269 for phase in self.browse(cr, uid, ids, context=context):
270 start_date = phase.date_start
271 if not start_date and phase.project_id.date_start:
272 start_date = phase.project_id.date_start
274 start_date = datetime.now().strftime("%Y-%m-%d")
275 resources = resources_list.get(phase.id, [])
276 calendar_id = phase.project_id.resource_calendar_id.id
277 task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['draft'] , phase.task_ids))) #reassign only task not yet started
279 task_pool.generate_schedule(cr, uid, task_ids, resources, calendar_id, start_date, context=context)
282 warning_msg = _("No tasks to compute for Phase '%s'.") % (phase.name)
283 if "warning" not in return_msg:
284 return_msg["warning"] = warning_msg
286 return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg
289 def schedule_tasks(self, cr, uid, ids, context=None):
291 Schedule tasks base on faces lib
295 if type(ids) in (long, int,):
297 task_pool = self.pool.get('project.task')
298 resource_pool = self.pool.get('resource.resource')
299 data_pool = self.pool.get('ir.model.data')
300 resource_allocation_pool = self.pool.get('project.resource.allocation')
302 for phase in self.browse(cr, uid, ids, context=context):
303 task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
304 ('state', 'in', ['draft', 'open', 'pending'])
306 project = phase.project_id
307 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
308 start_date = project.date_start
309 #Creating resources using the member of the Project
310 u_ids = [i.id for i in project.members]
311 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
312 start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
315 minimum_time_unit = 1
317 working_hours_per_day = 24
318 working_days_per_week = 7
319 working_days_per_month = 30
320 working_days_per_year = 365
324 working_hours_per_day = 8 #TODO: it should be come from calendars
325 working_days_per_week = 5
326 working_days_per_month = 20
327 working_days_per_year = 200
328 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
330 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
333 # Creating Resources for the Project
334 for key, vals in resource_objs.items():
336 class Resource_%s(Resource):
339 '''%(key, vals.get('vacation', False), vals.get('efficiency', False))
341 # Create a new project for each phase
344 from resource.faces import Resource
346 minimum_time_unit = %s
347 working_hours_per_day = %s
348 working_days_per_week = %s
349 working_days_per_month = %s
350 working_days_per_year = %s
353 '''%(phase.id, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
357 for task in task_pool.browse(cr, uid, task_ids, context=context):
358 func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, context=context)
361 task_ids.append(task.id)
363 #Temp File to test the Code for the Allocation
364 #fn = '/home/hmo/Desktop/plt.py'
366 #fp.writelines(func_str)
369 # Allocating Memory for the required Project and Pahses and Resources
371 Phase = eval('Phase_%d' % phase.id)
372 phase = Task.BalancedProject(Phase)
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 resource_pool = self.pool.get('resource.resource')
443 data_pool = self.pool.get('ir.model.data')
444 resource_allocation_pool = self.pool.get('project.resource.allocation')
445 uom_pool = self.pool.get('product.uom')
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)
481 # Creating Resources for the Project
482 for key, vals in resource_objs.items():
484 class Resource_%s(Resource):
487 '''%(key, vals.get('vacation', False), vals.get('efficiency', False))
489 # Create a new project for each phase
492 from resource.faces import Resource
494 minimum_time_unit = %s
495 working_hours_per_day = %s
496 working_days_per_week = %s
497 working_days_per_month = %s
498 working_days_per_year = %s
501 '''%(project.id, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
504 for root_phase in phase_pool.browse(cr, uid, root_phase_ids, context=context):
505 phases, child_phase_ids = phase_pool.generate_phase(cr, uid, [root_phase.id], '', context=context)
507 phase_ids += child_phase_ids
508 #Temp File to test the Code for the Allocation
509 #fn = '/home/hmo/Desktop/plt.py'
511 #fp.writelines(func_str)
514 # Allocating Memory for the required Project and Pahses and Resources
516 Project = eval('Project_%d' % project.id)
517 project = Task.BalancedProject(Project)
519 for phase_id in phase_ids:
520 phase = eval("project.Phase_%d" % phase_id)
521 start_date = phase.start.to_datetime()
522 end_date = phase.end.to_datetime()
524 # Recalculate date_start and date_end
525 # according to constraints on date start and date end on phase
527 #if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
528 # start_date = datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
530 # start_date = s_date
531 #if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
532 # end_date= datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
533 # date_start = phase.constraint_date_end
536 # date_start = end_date
538 # Write the calculated dates back
539 #ctx = context.copy()
540 #ctx.update({'scheduler': True})
541 phase_pool.write(cr, uid, [phase_id], {
542 'date_start': start_date.strftime('%Y-%m-%d'),
543 'date_end': end_date.strftime('%Y-%m-%d')
547 def schedule_tasks(self, cr, uid, ids, context=None):
549 Schedule task base on faces lib
553 if type(ids) in (long, int,):
555 task_pool = self.pool.get('project.task')
556 resource_pool = self.pool.get('resource.resource')
557 data_pool = self.pool.get('ir.model.data')
558 resource_allocation_pool = self.pool.get('project.resource.allocation')
559 uom_pool = self.pool.get('product.uom')
560 data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
562 for project in self.browse(cr, uid, ids, context=context):
563 task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
564 ('state', 'in', ['draft', 'open', 'pending'])
566 calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
567 start_date = project.date_start
568 #Creating resources using the member of the Project
569 u_ids = [i.id for i in project.members]
570 resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
571 start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
574 minimum_time_unit = 1
576 working_hours_per_day = 24
577 working_days_per_week = 7
578 working_days_per_month = 30
579 working_days_per_year = 365
583 working_hours_per_day = 8 #TODO: it should be come from calendars
584 working_days_per_week = 5
585 working_days_per_month = 20
586 working_days_per_year = 200
587 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
589 working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
592 # Creating Resources for the Project
593 for key, vals in resource_objs.items():
595 class Resource_%s(Resource):
598 '''%(key, vals.get('vacation', False), vals.get('efficiency', False))
600 # Create a new project for each phase
603 from resource.faces import Resource
605 minimum_time_unit = %s
606 working_hours_per_day = %s
607 working_days_per_week = %s
608 working_days_per_month = %s
609 working_days_per_year = %s
612 '''%(project.id, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
616 for task in task_pool.browse(cr, uid, task_ids, context=context):
617 func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, context=context)
620 task_ids.append(task.id)
622 #Temp File to test the Code for the Allocation
623 fn = '/home/hmo/Desktop/plt.py'
625 fp.writelines(func_str)
628 # Allocating Memory for the required Project and Pahses and Resources
630 Project = eval('Project_%d' % project.id)
631 project = Task.BalancedProject(Project)
633 for task_id in task_ids:
634 task = eval("project.Task_%d" % task_id)
635 start_date = task.start.to_datetime()
636 end_date = task.end.to_datetime()
638 task_pool.write(cr, uid, [task_id], {
639 'date_start': start_date.strftime('%Y-%m-%d'),
640 'date_end': end_date.strftime('%Y-%m-%d')
646 class resource_resource(osv.osv):
647 _inherit = "resource.resource"
648 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
651 if context.get('project_id',False):
652 project_pool = self.pool.get('project.project')
653 project_rec = project_pool.browse(cr, uid, context['project_id'], context=context)
654 user_ids = [user_id.id for user_id in project_rec.members]
655 args.append(('user_id','in',user_ids))
656 return super(resource_resource, self).search(cr, uid, args, offset, limit, order, context, count)
660 class project_task(osv.osv):
661 _inherit = "project.task"
663 'phase_id': fields.many2one('project.phase', 'Project Phase'),
666 def generate_task(self, cr, uid, task_id, parent=False, context=None):
669 resource_pool = self.pool.get('resource.resource')
670 resource_allocation_pool = self.pool.get('project.resource.allocation')
671 task = self.browse(cr, uid, task_id, context=context)
672 duration = str(task.planned_hours )+ 'H'
673 resource_ids = self.search(cr, uid, [('user_id', '=', task.user_id.id)], context=context)
675 if len(resource_ids):
676 resource = 'Resource_%s'%resource_ids[0]
677 # Phases Defination for the Project
682 '''%(task.id, duration, resource)
684 start = 'up.Task_%s.end' % (parent.id)
686 start = task.project_id.date_start or task.date_start
687 #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
694 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: