diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml
index 44cf3afde69..0b2291224a9 100644
--- a/addons/account/partner_view.xml
+++ b/addons/account/partner_view.xml
@@ -91,7 +91,7 @@
-
+
+
+
+
+
+
diff --git a/addons/html_view/__init__.py b/addons/html_view/__init__.py
new file mode 100644
index 00000000000..465ad75ffe0
--- /dev/null
+++ b/addons/html_view/__init__.py
@@ -0,0 +1 @@
+import html_view
\ No newline at end of file
diff --git a/addons/html_view/__terp__.py b/addons/html_view/__terp__.py
new file mode 100644
index 00000000000..8f32ef9eaaf
--- /dev/null
+++ b/addons/html_view/__terp__.py
@@ -0,0 +1,17 @@
+{
+ "name" : "Html View",
+ "version" : "1.1",
+ "author" : "Tiny",
+ "category" : "Generic Modules/Inventory Control",
+ "depends" : ['base'],
+ "init_xml" : ['html_view.xml'],
+ "demo_xml" : [],
+ "description": """
+ This is the test module which shows html tag supports in normal xml form view.
+ """,
+ 'update_xml': ['html_view.xml'],
+ 'installable': True,
+ 'active': False,
+ 'certificate': '',
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/html_view/html_view.py b/addons/html_view/html_view.py
new file mode 100644
index 00000000000..79f4bd7d0b9
--- /dev/null
+++ b/addons/html_view/html_view.py
@@ -0,0 +1,13 @@
+
+
+from osv import osv, fields
+
+class html_view(osv.osv):
+ _name = 'html.view'
+ _columns = {
+ 'name': fields.char('Name', size=128, required=True, select=True),
+ 'comp_id': fields.many2one('res.company', 'Company', select=1),
+ 'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
+ }
+
+html_view()
\ No newline at end of file
diff --git a/addons/html_view/html_view.xml b/addons/html_view/html_view.xml
new file mode 100644
index 00000000000..d26909586b5
--- /dev/null
+++ b/addons/html_view/html_view.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ htmlform
+ html.view
+ form
+
+
+
+
+
+ Html Test
+ ir.actions.act_window
+ html.view
+ form
+
+
+
+
\ No newline at end of file
diff --git a/addons/project_long_term/__terp__.py b/addons/project_long_term/__terp__.py
index 75c73396549..5367ff02567 100644
--- a/addons/project_long_term/__terp__.py
+++ b/addons/project_long_term/__terp__.py
@@ -26,7 +26,7 @@
"author" : "Tiny",
"website" : "http://www.openerp.com",
"category" : "Generic Modules/Projects & Services",
- "depends" : ["project","resource"],
+ "depends" : ["project", "resource"],
"description": """Long Term Project management module that track planning, scheduling, resources allocation.
""",
"init_xml" : [],
@@ -35,7 +35,7 @@
#"security/ir.model.access.csv",
"project_wizard.xml" ,
"project_view.xml",
- "project_phase_workflow.xml"
+ "project_workflow.xml"
],
'installable': True,
'active': False,
diff --git a/addons/project_long_term/project.py b/addons/project_long_term/project.py
index 9c87f3048c2..595d3c82140 100644
--- a/addons/project_long_term/project.py
+++ b/addons/project_long_term/project.py
@@ -30,25 +30,21 @@ class project_phase(osv.osv):
_name = "project.phase"
_description = "Project Phase"
-
- def _check_recursion(self,cr,uid,ids):
+ def _check_recursion(self, cr, uid, ids):
obj_self = self.browse(cr, uid, ids[0])
prev_ids = obj_self.previous_phase_ids
next_ids = obj_self.next_phase_ids
- #it should nither be in prev_ids nor in next_ids
+ # it should nither be in prev_ids nor in next_ids
if (obj_self in prev_ids) or (obj_self in next_ids):
return False
ids = [id for id in prev_ids if id in next_ids]
-
- #both prev_ids and next_ids must be unique
+ # both prev_ids and next_ids must be unique
if ids:
return False
- #unrelated project
-
+ # unrelated project
prev_ids = [rec.id for rec in prev_ids]
next_ids = [rec.id for rec in next_ids]
-
- #iter prev_ids
+ # iter prev_ids
while prev_ids:
cr.execute('select distinct prv_phase_id from project_phase_rel where next_phase_id in ('+','.join(map(str, prev_ids))+')')
prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
@@ -58,8 +54,7 @@ class project_phase(osv.osv):
if ids:
return False
prev_ids = prv_phase_ids
-
- #iter next_ids
+ # iter next_ids
while next_ids:
cr.execute('select distinct next_phase_id from project_phase_rel where prv_phase_id in ('+','.join(map(str, next_ids))+')')
next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
@@ -72,21 +67,21 @@ class project_phase(osv.osv):
return True
def _check_dates(self, cr, uid, ids):
- phase = self.read(cr, uid, ids[0],['date_start','date_end'])
+ phase = self.read(cr, uid, ids[0], ['date_start', 'date_end'])
if phase['date_start'] and phase['date_end']:
if phase['date_start'] > phase['date_end']:
return False
return True
def _check_constraint_start(self, cr, uid, ids):
- phase = self.read(cr, uid, ids[0],['date_start','constraint_date_start'])
+ phase = self.read(cr, uid, ids[0], ['date_start', 'constraint_date_start'])
if phase['date_start'] and phase['constraint_date_start']:
if phase['date_start'] < phase['constraint_date_start']:
return False
return True
def _check_constraint_end(self, cr, uid, ids):
- phase = self.read(cr, uid, ids[0],['date_end','constraint_date_end'])
+ phase = self.read(cr, uid, ids[0], ['date_end', 'constraint_date_end'])
if phase['date_end'] and phase['constraint_date_end']:
if phase['date_end'] > phase['constraint_date_end']:
return False
@@ -102,74 +97,76 @@ class project_phase(osv.osv):
'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases'),
'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases'),
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of phases."),
- 'duration': fields.float('Duration',required=True),
- 'product_uom': fields.many2one('product.uom', 'Duration UoM',required=True, help="UoM (Unit of Measure) is the unit of measurement for Duration"),
+ 'duration': fields.float('Duration', required=True),
+ 'product_uom': fields.many2one('product.uom', 'Duration UoM', required=True, help="UoM (Unit of Measure) is the unit of measurement for Duration"),
'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks"),
'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources"),
'responsible_id':fields.many2one('res.users', 'Responsible'),
- 'state': fields.selection([('draft', 'Draft'),('open', 'In Progress'),('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
+ 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
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.\
\n If the phase is over, the states is set to \'Done\'.')
-
}
-
_defaults = {
'responsible_id': lambda obj,cr,uid,context: uid,
'date_start': lambda *a: time.strftime('%Y-%m-%d'),
'state': lambda *a: 'draft',
'sequence': lambda *a: 10,
}
-
_order = "name"
_constraints = [
- (_check_recursion,'Error ! Loops In Phases Not Allowed',['next_phase_ids','previous_phase_ids']),
+ (_check_recursion,'Error ! Loops In Phases Not Allowed',['next_phase_ids', 'previous_phase_ids']),
(_check_dates, 'Error! Phase start-date must be lower then Phase end-date.', ['date_start', 'date_end']),
(_check_constraint_start, 'Error! Phase must start-after Constraint Start Date.', ['date_start', 'constraint_date_start']),
(_check_constraint_end, 'Error! Phase must end-before Constraint End Date.', ['date_end', 'constraint_date_end']),
-
]
def onchange_project(self, cr, uid, ids, project):
result = {}
if project:
- project_pool = self.pool.get('project.project')
- project_id = project_pool.browse(cr, uid, project)
+ project_obj = self.pool.get('project.project')
+ project_id = project_obj.browse(cr, uid, project)
if project_id.date_start:
result['date_start'] = mx.DateTime.strptime(project_id.date_start, "%Y-%m-%d").strftime('%Y-%m-%d %H:%M:%S')
- return {'value' : result}
- return {'value' : {'date_start' : []}}
+ return {'value': result}
+ return {'value': {'date_start': []}}
- def constraint_date_start(self, cr, uid, phase, date_end, context=None):
- # Recursive call for all previous phases if change in date_start < older time
-
- resource_cal_pool = self.pool.get('resource.calendar')
- uom_pool = self.pool.get('product.uom')
- resource_pool = self.pool.get('resource.resource')
+ def _check_date_start(self, cr, uid, phase, date_end, context=None):
+ """
+ Check And Compute date_end of phase if change in date_start < older time.
+ """
+ resource_calendar_obj = self.pool.get('resource.calendar')
+ uom_obj = self.pool.get('product.uom')
+ resource_obj = self.pool.get('resource.resource')
calendar_id = phase.project_id.resource_calendar_id.id
- resource_id = resource_pool.search(cr, uid, [('user_id','=',phase.responsible_id.id)])
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
if resource_id:
- calendar_id = resource_pool.browse(cr, uid, resource_id[0]).calendar_id.id
- default_uom_id = uom_pool.search(cr, uid, [('name','=','Hour')])[0]
- avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
- work_time = resource_cal_pool.interval_min_get(cr, uid, calendar_id or False, date_end, avg_hours or 0.0, resource_id or False)
- dt_start = work_time[0][0].strftime('%Y-%m-%d %H:%M:%S')
- self.write(cr, uid, [phase.id], {'date_start' : dt_start, 'date_end' : date_end.strftime('%Y-%m-%d %H:%M:%S')})
+ cal_id = resource_obj.browse(cr, uid, resource_id[0]).calendar_id.id
+ if cal_id:
+ calendar_id = cal_id
+ default_uom_id = uom_obj.search(cr, uid, [('name', '=', 'Hour')])[0]
+ avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id or False, date_end, avg_hours or 0.0, resource_id or False)
+ dt_start = work_times[0][0].strftime('%Y-%m-%d %H:%M:%S')
+ self.write(cr, uid, [phase.id], {'date_start': dt_start, 'date_end': date_end.strftime('%Y-%m-%d %H:%M:%S')})
- def constraint_date_end(self, cr, uid, phase, date_start, context=None):
- # Recursive call for all next phases if change in date_end > older time
-
- resource_cal_pool = self.pool.get('resource.calendar')
- uom_pool = self.pool.get('product.uom')
- resource_pool = self.pool.get('resource.resource')
+ def _check_date_end(self, cr, uid, phase, date_start, context=None):
+ """
+ Check And Compute date_end of phase if change in date_end > older time.
+ """
+ resource_calendar_obj = self.pool.get('resource.calendar')
+ uom_obj = self.pool.get('product.uom')
+ resource_obj = self.pool.get('resource.resource')
calendar_id = phase.project_id.resource_calendar_id.id
- resource_id = resource_pool.search(cr, uid, [('user_id','=',phase.responsible_id.id)])
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
if resource_id:
- calendar_id = resource_pool.browse(cr, uid, resource_id[0]).calendar_id.id
- default_uom_id = uom_pool.search(cr, uid, [('name','=','Hour')])[0]
- avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
- work_time = resource_cal_pool.interval_get(cr, uid, calendar_id or False, date_start, avg_hours or 0.0, resource_id or False)
- dt_end = work_time[-1][1].strftime('%Y-%m-%d %H:%M:%S')
- self.write(cr, uid, [phase.id], {'date_start' : date_start.strftime('%Y-%m-%d %H:%M:%S'), 'date_end' : dt_end})
+ cal_id = resource_obj.browse(cr, uid, resource_id[0]).calendar_id.id
+ if cal_id:
+ calendar_id = cal_id
+ default_uom_id = uom_obj.search(cr, uid, [('name', '=', 'Hour')])[0]
+ avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ work_times = resource_calendar_obj.interval_get(cr, uid, calendar_id or False, date_start, avg_hours or 0.0, resource_id or False)
+ dt_end = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
+ self.write(cr, uid, [phase.id], {'date_start': date_start.strftime('%Y-%m-%d %H:%M:%S'), 'date_end': dt_end})
def write(self, cr, uid, ids, vals, context=None):
@@ -179,62 +176,62 @@ class project_phase(osv.osv):
if context.get('scheduler',False):
return super(project_phase, self).write(cr, uid, ids, vals, context=context)
-# if the phase is performed by a resource then its calendar and efficiency also taken
-# otherwise the project's working calendar considered
+ # Consider calendar and efficiency if the phase is performed by a resource
+ # otherwise consider the project's working calendar
phase = self.browse(cr, uid, ids[0])
- resource_cal_pool = self.pool.get('resource.calendar')
- resource_pool = self.pool.get('resource.resource')
- uom_pool = self.pool.get('product.uom')
+ resource_calendar_obj = self.pool.get('resource.calendar')
+ resource_obj = self.pool.get('resource.resource')
+ uom_obj = self.pool.get('product.uom')
resource_id = False
calendar_id = phase.project_id.resource_calendar_id.id
- resource_id = resource_pool.search(cr, uid, [('user_id','=',phase.responsible_id.id)])
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
if resource_id:
- calendar_id = resource_pool.browse(cr, uid, resource_id[0]).calendar_id.id
- default_uom_id = uom_pool.search(cr, uid, [('name','=','Hour')])[0]
- avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
-
-# write method changes the date_start and date_end
-#for previous and next phases respectively based on valid condition
+ cal_id = resource_obj.browse(cr, uid, resource_id[0]).calendar_id.id
+ if cal_id:
+ calendar_id = cal_id
+ default_uom_id = uom_obj.search(cr, uid, [('name', '=', 'Hour')])[0]
+ avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ # Change the date_start and date_end
+ # for previous and next phases respectively based on valid condition
if vals.get('date_start'):
if vals['date_start'] < phase.date_start:
dt_start = mx.DateTime.strptime(vals['date_start'],'%Y-%m-%d %H:%M:%S')
- work_times = resource_cal_pool.interval_get(cr, uid, calendar_id or False, dt_start, avg_hours or 0.0, resource_id or False)
+ work_times = resource_calendar_obj.interval_get(cr, uid, calendar_id or False, dt_start, avg_hours or 0.0, resource_id or False)
vals['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
super(project_phase, self).write(cr, uid, ids, vals, context=context)
for prv_phase in phase.previous_phase_ids:
- self.constraint_date_start(cr, uid, prv_phase, dt_start)
-
+ self._check_date_start(cr, uid, prv_phase, dt_start)
if vals.get('date_end'):
if vals['date_end'] > phase.date_end:
dt_end = mx.DateTime.strptime(vals['date_end'],'%Y-%m-%d %H:%M:%S')
- work_times = resource_cal_pool.interval_min_get(cr, uid, calendar_id or False, dt_end, avg_hours or 0.0, resource_id or False)
+ work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id or False, dt_end, avg_hours or 0.0, resource_id or False)
vals['date_start'] = work_times[0][0].strftime('%Y-%m-%d %H:%M:%S')
super(project_phase, self).write(cr, uid, ids, vals, context=context)
for next_phase in phase.next_phase_ids:
- self.constraint_date_end(cr, uid, next_phase, dt_end)
+ self._check_date_end(cr, uid, next_phase, dt_end)
return super(project_phase, self).write(cr, uid, ids, vals, context=context)
- def phase_draft(self, cr, uid, ids,*args):
+ def set_draft(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'draft'})
return True
- def phase_start(self, cr, uid, ids,*args):
+ def set_open(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'open'})
return True
- def phase_pending(self, cr, uid, ids,*args):
+ def set_pending(self, cr, uid, ids,*args):
self.write(cr, uid, ids, {'state': 'pending'})
return True
- def phase_cancel(self, cr, uid, ids,*args):
+ def set_cancel(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'cancelled'})
return True
- def phase_done(self, cr, uid, ids,*args):
+ def set_done(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'done'})
return True
@@ -246,7 +243,7 @@ class project_resource_allocation(osv.osv):
_rec_name = 'resource_id'
_columns = {
'resource_id': fields.many2one('resource.resource', 'Resource', required=True),
- 'phase_id': fields.many2one('project.phase', 'Project Phase',required=True),
+ 'phase_id': fields.many2one('project.phase', 'Project Phase', required=True),
'useability': fields.float('Useability', help="Useability of this ressource for this project phase in percentage (=50%)"),
}
_defaults = {
@@ -257,7 +254,7 @@ project_resource_allocation()
class project(osv.osv):
_inherit = "project.project"
-
+ _description = "Project"
_columns = {
'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report"),
@@ -267,7 +264,7 @@ project()
class task(osv.osv):
_inherit = "project.task"
-
+ _description = "Task"
_columns = {
'phase_id': fields.many2one('project.phase', 'Project Phase'),
'occupation_rate': fields.float('Occupation Rate', help='The occupation rate fields indicates how much of his time a user is working on a task. A 100% occupation rate means the user works full time on the tasks. The ending date of a task is computed like this: Starting Date + Duration / Occupation Rate.'),
@@ -280,53 +277,58 @@ class task(osv.osv):
def onchange_planned(self, cr, uid, ids, project, user_id=False, planned=0.0, effective=0.0, date_start=None, occupation_rate=0.0):
result = {}
if date_start:
- resource_pool = self.pool.get('resource.resource')
+ resource_obj = self.pool.get('resource.resource')
project_pool = self.pool.get('project.project')
+ hrs = float(planned / float(occupation_rate))
+ calendar_id = project_pool.browse(cr, uid, project).resource_calendar_id.id
resource_calendar = self.pool.get('resource.calendar')
dt_start = mx.DateTime.strptime(date_start, '%Y-%m-%d %H:%M:%S')
- resource_id = resource_pool.search(cr, uid, [('user_id','=',user_id)])
+ resource_id = resource_obj.search(cr, uid, [('user_id','=',user_id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id)[0]
- hrs = planned / (float(occupation_rate) * resource_obj.time_efficiency)
- calendar_id = resource_obj.calendar_id.id
- else:
- hrs = float(planned / float(occupation_rate))
- calendar_id = project_pool.browse(cr, uid, project).resource_calendar_id .id
+ resource = resource_obj.browse(cr, uid, resource_id)[0]
+ hrs = planned / (float(occupation_rate) * resource.time_efficiency)
+ if resource.calendar_id.id:
+ calendar_id = resource.calendar_id.id
work_times = resource_calendar.interval_get(cr, uid, calendar_id or False, dt_start, hrs or 0.0, resource_id or False)
result['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
result['remaining_hours'] = planned - effective
return {'value' : result}
- def constraint_date_start(self, cr, uid, task, date_end, context=None):
- # Recursive call for all previous tasks if change in date_start < older time
-
- resource_cal_pool = self.pool.get('resource.calendar')
- resource_pool = self.pool.get('resource.resource')
+ def _check_date_start(self, cr, uid, task, date_end, context=None):
+ """
+ Check And Compute date_end of task if change in date_start < older time.
+ """
+ resource_calendar_obj = self.pool.get('resource.calendar')
+ resource_obj = self.pool.get('resource.resource')
calendar_id = task.project_id.resource_calendar_id.id
- hours = task.remaining_hours / task.occupation_rate
- resource_id = resource_pool.search(cr, uid, [('user_id','=',task.user_id.id)])
+ hours = task.planned_hours / task.occupation_rate
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', task.user_id.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id[0])
- calendar_id = resource_obj.calendar_id.id
- hours = task.planned_hours / (float(task.occupation_rate) * resource_obj.time_efficiency)
- work_time = resource_cal_pool.interval_min_get(cr, uid, calendar_id or False, date_end, hours or 0.0, resource_id or False)
- dt_start = work_time[0][0].strftime('%Y-%m-%d %H:%M:%S')
+ resource = resource_obj.browse(cr, uid, resource_id[0])
+ if resource.calendar_id.id:
+ calendar_id = resource.calendar_id.id
+ hours = task.planned_hours / (float(task.occupation_rate) * resource.time_efficiency)
+ work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id or False, date_end, hours or 0.0, resource_id or False)
+ dt_start = work_times[0][0].strftime('%Y-%m-%d %H:%M:%S')
self.write(cr, uid, [task.id], {'date_start' : dt_start,'date_end' : date_end.strftime('%Y-%m-%d %H:%M:%S')})
- def constraint_date_end(self, cr, uid, task, date_start, context=None):
- # Recursive call for all next tasks if change in date_end > older time
+ def _check_date_end(self, cr, uid, task, date_start, context=None):
+ """
+ Check And Compute date_end of task if change in date_end > older time.
+ """
- resource_cal_pool = self.pool.get('resource.calendar')
- resource_pool = self.pool.get('resource.resource')
+ resource_calendar_obj = self.pool.get('resource.calendar')
+ resource_obj = self.pool.get('resource.resource')
calendar_id = task.project_id.resource_calendar_id.id
- hours = task.remaining_hours / task.occupation_rate
- resource_id = resource_pool.search(cr,uid,[('user_id','=',task.user_id.id)])
+ hours = task.planned_hours / task.occupation_rate
+ resource_id = resource_obj.search(cr,uid,[('user_id', '=', task.user_id.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id[0])
- calendar_id = resource_obj.calendar_id.id
- hours = task.planned_hours / (float(task.occupation_rate) * resource_obj.time_efficiency)
- work_time = resource_cal_pool.interval_get(cr, uid, calendar_id or False, date_start, hours or 0.0, resource_id or False)
- dt_end = work_time[-1][1].strftime('%Y-%m-%d %H:%M:%S')
+ resource = resource_obj.browse(cr, uid, resource_id[0])
+ if resource.calendar_id.id:
+ calendar_id = resource.calendar_id.id
+ hours = task.planned_hours / (float(task.occupation_rate) * resource.time_efficiency)
+ work_times = resource_calendar_obj.interval_get(cr, uid, calendar_id or False, date_start, hours or 0.0, resource_id or False)
+ dt_end = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
self.write(cr, uid, [task.id], {'date_start' : date_start.strftime('%Y-%m-%d %H:%M:%S'),'date_end' : dt_end})
def write(self, cr, uid, ids, vals, context=None):
@@ -337,44 +339,43 @@ class task(osv.osv):
if context.get('scheduler',False):
return super(task, self).write(cr, uid, ids, vals, context=context)
-# if the task is performed by a resource then its calendar and efficiency also taken
-# otherwise the project's working calendar considered
+ # Consider calendar and efficiency if the task is performed by a resource
+ # otherwise consider the project's working calendar
task_id = ids
if isinstance(ids, list):
task_id = ids[0]
- tasks = self.browse(cr, uid, task_id, context=context)
- resource_cal_pool = self.pool.get('resource.calendar')
- resource_pool = self.pool.get('resource.resource')
- calendar_id = tasks.project_id.resource_calendar_id.id
- hrs = tasks.remaining_hours / tasks.occupation_rate
- resource_id = resource_pool.search(cr, uid, [('user_id','=',tasks.user_id.id)])
+ task_rec = self.browse(cr, uid, task_id, context=context)
+ resource_calendar_obj = self.pool.get('resource.calendar')
+ resource_obj = self.pool.get('resource.resource')
+ calendar_id = task_rec.project_id.resource_calendar_id.id
+ hrs = task_rec.planned_hours / task_rec.occupation_rate
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', task_rec.user_id.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id[0])
- calendar_id = resource_obj.calendar_id.id
- hrs = tasks.planned_hours / (float(tasks.occupation_rate) * resource_obj.time_efficiency)
+ resource = resource_obj.browse(cr, uid, resource_id[0])
+ if resource.calendar_id.id:
+ calendar_id = resource.calendar_id.id
+ hrs = task_rec.planned_hours / (float(task_rec.occupation_rate) * resource.time_efficiency)
-# write method changes the date_start and date_end
-# for previous and next tasks respectively based on valid condition
+ # Change the date_start and date_end
+ # for previous and next tasks respectively based on valid condition
if vals.get('date_start'):
- if vals['date_start'] < tasks.date_start:
- dt_start = mx.DateTime.strptime(vals['date_start'],'%Y-%m-%d %H:%M:%S')
- work_times = resource_cal_pool.interval_get(cr, uid, calendar_id or False, dt_start, hrs or 0.0, resource_id or False)
+ if vals['date_start'] < task_rec.date_start:
+ dt_start = mx.DateTime.strptime(vals['date_start'], '%Y-%m-%d %H:%M:%S')
+ work_times = resource_calendar_obj.interval_get(cr, uid, calendar_id or False, dt_start, hrs or 0.0, resource_id or False)
vals['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
super(task, self).write(cr, uid, ids, vals, context=context)
- for prv_task in tasks.parent_ids:
- self.constraint_date_start(cr, uid, prv_task, dt_start)
-
+ for prv_task in task_rec.parent_ids:
+ self._check_date_start(cr, uid, prv_task, dt_start)
if vals.get('date_end'):
- if vals['date_end'] > tasks.date_end:
- dt_end = mx.DateTime.strptime(vals['date_end'],'%Y-%m-%d %H:%M:%S')
- hrs = tasks.remaining_hours / tasks.occupation_rate
- work_times = resource_cal_pool.interval_min_get(cr, uid, calendar_id or False, dt_end, hrs or 0.0, resource_id or False)
+ if vals['date_end'] > task_rec.date_end:
+ dt_end = mx.DateTime.strptime(vals['date_end'], '%Y-%m-%d %H:%M:%S')
+ work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id or False, dt_end, hrs or 0.0, resource_id or False)
vals['date_start'] = work_times[0][0].strftime('%Y-%m-%d %H:%M:%S')
super(task, self).write(cr, uid, ids, vals, context=context)
- for next_task in tasks.child_ids:
- self.constraint_date_end(cr, uid, next_task, dt_end)
+ for next_task in task_rec.child_ids:
+ self._check_date_end(cr, uid, next_task, dt_end)
return super(task, self).write(cr, uid, ids, vals, context=context)
diff --git a/addons/project_long_term/project_demo.xml b/addons/project_long_term/project_demo.xml
index 64dcb19c31e..24bc7ff9438 100644
--- a/addons/project_long_term/project_demo.xml
+++ b/addons/project_long_term/project_demo.xml
@@ -201,6 +201,7 @@
+
diff --git a/addons/project_long_term/project_view.xml b/addons/project_long_term/project_view.xml
index 059e0a8300a..0af1e09c422 100644
--- a/addons/project_long_term/project_view.xml
+++ b/addons/project_long_term/project_view.xml
@@ -1,6 +1,11 @@
+
+ # ------------------------------------------------------
+ # Project Resource Allocation
+ # ------------------------------------------------------
+
project.resource.allocation.form
project.resource.allocation
@@ -13,7 +18,7 @@
-
+
project.resource.allocation.list
project.resource.allocation
@@ -26,7 +31,11 @@
-
+
+ # ------------------------------------------------------
+ # Project Phase
+ # ------------------------------------------------------
+
project.phase.form
project.phase
@@ -57,11 +66,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -128,7 +137,7 @@
-
+
project.phase.list
project.phase
@@ -185,7 +194,7 @@
-
+
@@ -194,7 +203,7 @@
-
+
@@ -207,6 +216,10 @@
+ # ------------------------------------------------------
+ # Project
+ # ------------------------------------------------------
+
phase.project.form1
project.project
@@ -220,6 +233,10 @@
+ # ------------------------------------------------------
+ # Project Task
+ # ------------------------------------------------------
+
project.phase.task.form1
project.task
@@ -262,9 +279,11 @@
view_mode="tree,form"
view_type="form" />
-
+ # ------------------------------------------------------
+ # Menu Items
+ # ------------------------------------------------------
-
+
diff --git a/addons/project_long_term/project_phase_workflow.xml b/addons/project_long_term/project_workflow.xml
similarity index 71%
rename from addons/project_long_term/project_phase_workflow.xml
rename to addons/project_long_term/project_workflow.xml
index c1999fc55f9..f476ac16cd6 100644
--- a/addons/project_long_term/project_phase_workflow.xml
+++ b/addons/project_long_term/project_workflow.xml
@@ -10,95 +10,99 @@
True
- phase_draft
+ set_draft
function
- phase_draft()
+ set_draft()
- phase_start
+ set_open
function
- phase_start()
-
+ set_open()
- phase_cancel
+ set_cancel
True
function
- phase_cancel()
-
+ set_cancel()
- phase_pending
+ set_pending
function
- phase_pending()
+ set_pending()
- phase_done
+ set_done
True
function
- phase_done()
+ set_done()
- phase_start
+ set_open
- phase_cancel
+ set_cancel
- phase_done
+ set_done
- phase_pending
+ set_pending
- phase_cancel
+ set_cancel
- phase_draft
+ set_draft
-
-
- phase_cancel
+
+
+ set_open
-
- phase_done
+
+ set_cancel
+
+
+ set_done
+
+
+
- phase_draft
+ set_draft
\ No newline at end of file
diff --git a/addons/project_long_term/wizard/__init__.py b/addons/project_long_term/wizard/__init__.py
index fffe3ded100..06880dbe6e2 100644
--- a/addons/project_long_term/wizard/__init__.py
+++ b/addons/project_long_term/wizard/__init__.py
@@ -22,7 +22,7 @@
import compute_phases_date
import compute_tasks_date
import schedule_tasks
-import project_resource
+import working_calendar
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/compute_phases_date.py b/addons/project_long_term/wizard/compute_phases_date.py
index 54051b521e2..3c14d7525aa 100644
--- a/addons/project_long_term/wizard/compute_phases_date.py
+++ b/addons/project_long_term/wizard/compute_phases_date.py
@@ -23,9 +23,11 @@ import wizard
import pooler
from tools.translate import _
import datetime
+
from resource.faces import *
from new import classobj
-import project_resource as proj
+
+import working_calendar as wkcal
compute_form = """
"""
compute_fields = {
- 'project_id': {'string':'Project', 'type':'many2one', 'relation': 'project.project'},
+ 'project_id': {'string':'Project', 'type':'many2one', 'relation':'project.project'},
}
-success_msg = """
-"""
+class wizard_compute_phases(wizard.interface):
+ def _phase_schedule(self, cr, uid, phase, start_date, calendar_id=False, context={}):
+
+ """Schedule phase with the start date till all the next phases are completed.
+
+ Arguements: start_dsate -- start date for the phase
+ calendar_id -- working calendar of the project
+
+ """
-def phase_schedule(cr, uid, phase, start_date, calendar_id=False):
pool = pooler.get_pool(cr.dbname)
- phase_pool = pool.get('project.phase')
- resource_pool = pool.get('resource.resource')
- uom_pool = pool.get('product.uom')
- wktime_cal = []
- resource_cal = False
- phase_resource = False
+ phase_obj = pool.get('project.phase')
+ resource_obj = pool.get('resource.resource')
+ uom_obj = pool.get('product.uom')
+ phase_resource_obj = False
if phase:
- resource_id = resource_pool.search(cr, uid, [('user_id','=',phase.responsible_id.id)])
+ leaves = []
+ time_efficiency = 1.0
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id)[0]
- leaves = proj.leaves_resource(cr, uid, calendar_id or False , resource_id, resource_obj.calendar_id.id)
- phase_resource = classobj(str(resource_obj.name), (Resource,), {'__doc__' : resource_obj.name, '__name__' : resource_obj.name, 'vacation' : tuple(leaves), 'efficiency' : resource_obj.time_efficiency})
- default_uom_id = uom_pool.search(cr, uid, [('name','=','Hour')])[0]
- avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ # Create a new resource object with
+ # all the attributes of the Resource Class
+ resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
+ time_efficiency = resource.time_efficiency
+ leaves = wkcal.compute_leaves(cr, uid, calendar_id or False , resource_id, resource.calendar_id.id)
+ phase_resource_obj = classobj(str(phase.responsible_id.name), (Resource,),
+ {'__doc__': phase.responsible_id.name,
+ '__name__': phase.responsible_id.name,
+ 'vacation': tuple(leaves),
+ 'efficiency': time_efficiency
+ })
+ default_uom_id = uom_obj.search(cr, uid, [('name','=','Hour')])[0]
+ avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
duration = str(avg_hours) + 'H'
-
- # Creating a new project for each phase
+ # Create a new project for each phase
def Project():
start = start_date
minimum_time_unit = 1
- resource = phase_resource
- # If project has working calendar else the default one would be considered
+ resource = phase_resource_obj
+ # If project has working calendar then that
+ # else the default one would be considered
if calendar_id:
- working_days = proj.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(proj.leaves_resource(cr, uid, calendar_id))
+ working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
+ vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
def phase():
effort = duration
@@ -78,7 +92,8 @@ def phase_schedule(cr, uid, phase, start_date, calendar_id=False):
project = BalancedProject(Project)
s_date = project.phase.start.to_datetime()
e_date = project.phase.end.to_datetime()
- # According to constraints on date start and date end on phase recalculation done
+ # Recalculate date_start and date_end
+ # according to constraints on date start and date end on phase
if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d %H:%M:%S')
else:
@@ -89,54 +104,59 @@ def phase_schedule(cr, uid, phase, start_date, calendar_id=False):
else:
end_date = e_date
date_start = end_date
-
- # Writing the dates back
- phase_pool.write(cr, uid, [phase.id], {'date_start' :start_date.strftime('%Y-%m-%d %H:%M:%S'), 'date_end' :end_date.strftime('%Y-%m-%d %H:%M:%S')}, context={'scheduler' :True})
-
- # Recursive calling the next phases till all the phases are scheduled
+ # Write the calculated dates back
+ phase_obj.write(cr, uid, [phase.id], {'date_start': start_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_end': end_date.strftime('%Y-%m-%d %H:%M:%S')},
+ context={'scheduler': True
+ })
+ # Recursive call till all the next phases scheduled
for phase in phase.next_phase_ids:
if phase.state in ['draft','open','pending']:
- phase_schedule(cr, uid, phase, date_start, phase.project_id.resource_calendar_id.id or False)
+ self._phase_schedule(cr, uid, phase, date_start, phase.project_id.resource_calendar_id.id or False)
else:
continue
-#
-class wizard_compute_phases(wizard.interface):
-
def _compute_date(self, cr, uid, data, context):
+ """
+ Compute the phases for scheduling.
+ """
pool = pooler.get_pool(cr.dbname)
- project_pool = pool.get('project.project')
- phase_pool = pool.get('project.phase')
-
- # if project mentioned
- if data['form']['project_id']:
- project_id = project_pool.browse(cr, uid, data['form']['project_id'])
- phase_ids = phase_pool.search(cr, uid, [('project_id','=',project_id.id), ('state','in',['draft','open','pending']), ('previous_phase_ids','=',False)])
-
- # else all the draft,open,pending states phases taken
- else:
- phase_ids = phase_pool.search(cr, uid,[('state','in',['draft','open','pending']), ('previous_phase_ids','=',False)])
-
+ project_obj = pool.get('project.project')
+ phase_obj = pool.get('project.phase')
+ if data['form']['project_id']: # If project mentioned find its phases
+ project_id = project_obj.browse(cr, uid, data['form']['project_id'], context=context)
+ phase_ids = phase_obj.search(cr, uid, [('project_id', '=', project_id.id),
+ ('state', 'in', ['draft', 'open', 'pending']),
+ ('previous_phase_ids', '=', False)
+ ])
+ else: # Else take all the draft,open,pending states phases
+ phase_ids = phase_obj.search(cr, uid,[('state', 'in', ['draft', 'open', 'pending']),
+ ('previous_phase_ids', '=', False)
+ ])
phase_ids.sort()
- phase_objs = phase_pool.browse(cr, uid, phase_ids)
+ phase_objs = phase_obj.browse(cr, uid, phase_ids, context=context)
for phase in phase_objs:
start_date = phase.project_id.date_start
if not phase.project_id.date_start:
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
start_dt = datetime.datetime.strftime((datetime.datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d %H:%M")
calendar_id = phase.project_id.resource_calendar_id.id
- phase_schedule(cr, uid, phase, start_dt, calendar_id or False)
+ self._phase_schedule(cr, uid, phase, start_dt, calendar_id or False)
return {}
- def phases_open_list(self, cr, uid, data, context):
+ def _open_phases_list(self, cr, uid, data, context):
+ """
+ Return the scheduled phases list.
+ """
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
result = mod_obj._get_id(cr, uid, 'project_long_term', 'act_project_phase')
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
result = act_obj.read(cr, uid, [id], context=context)[0]
- if data['form']['project_id']:
- result['domain'] = [('project_id', '=', data['form']['project_id'])]
result['domain'] = [('state', 'not in', ['cancelled','done'])]
+ if data['form']['project_id']:
+ result['domain'] = [('project_id', '=', data['form']['project_id']),
+ ('state', 'not in', ['cancelled','done'])]
return result
states = {
@@ -150,11 +170,8 @@ class wizard_compute_phases(wizard.interface):
},
'compute': {
'actions': [_compute_date],
- 'result': {'type': 'action', 'action':phases_open_list, 'state':'end'},
+ 'result': {'type': 'action', 'action':_open_phases_list, 'state':'end'},
},
}
-
wizard_compute_phases('wizard.compute.phases')
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/compute_tasks_date.py b/addons/project_long_term/wizard/compute_tasks_date.py
index 3cf865a48db..cc6a443a454 100644
--- a/addons/project_long_term/wizard/compute_tasks_date.py
+++ b/addons/project_long_term/wizard/compute_tasks_date.py
@@ -23,10 +23,12 @@ import wizard
import pooler
from tools.translate import _
import datetime
+
from resource.faces import *
from new import classobj
import operator
-import project_resource as proj
+
+import working_calendar as wkcal
compute_form = """
"""
compute_fields = {
- 'project_id': {'string':'Project', 'type':'many2one', 'relation': 'project.project', 'required':'True'},
+ 'project_id': {'string':'Project', 'type':'many2one', 'relation':'project.project', 'required':'True'},
}
class wizard_compute_tasks(wizard.interface):
def _compute_date(self, cr, uid, data, context):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
pool = pooler.get_pool(cr.dbname)
- project_pool = pool.get('project.project')
+ project_obj = pool.get('project.project')
task_pool = pool.get('project.task')
- resource_pool = pool.get('resource.resource')
- user_pool = pool.get('res.users')
+ resource_obj = pool.get('resource.resource')
+ user_obj = pool.get('res.users')
project_id = data['form']['project_id']
- project = project_pool.browse(cr, uid, project_id)
- task_ids = task_pool.search(cr, uid, [('project_id','=',project_id), ('state','in',['draft','open','pending'])])
+ project = project_obj.browse(cr, uid, project_id, context=context)
+ task_ids = task_pool.search(cr, uid, [('project_id', '=', project_id),
+ ('state', 'in', ['draft', 'open', 'pending'])
+ ])
if task_ids:
- wktime_cal = []
task_ids.sort()
- task_obj = task_pool.browse(cr, uid, task_ids)
+ task_objs = task_pool.browse(cr, uid, task_ids, context=context)
calendar_id = project.resource_calendar_id.id
start_date = project.date_start
if not project.date_start:
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
-
-# To create resources which are the Project Members
- resource_objs = []
- for resource in project.members:
+ # Create Resource Class objects which are the Project Members
+ resources = []
+ for user in project.members:
leaves = []
- resource_id = resource_pool.search(cr, uid, [('user_id','=',resource.id)])
+ time_efficiency = 1.0
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', user.id)])
if resource_id:
- resource_obj = resource_pool.browse(cr, uid, resource_id)[0]
- leaves = proj.leaves_resource(cr, uid, calendar_id or False , resource_id, resource_obj.calendar_id.id)
- resource_objs.append(classobj(str(resource.name), (Resource,), {'__doc__' : resource.name, '__name__' : resource.name, 'vacation' : tuple(leaves), 'efficiency' : resource_obj.time_efficiency}))
-
- priority_dict = {'0' :1000, '1' :800, '2' :500, '3' :300,'4' :100}
-
-# To create dynamic no of tasks with the resource specified
- def tasks_resource(j, eff, priorty=500, obj=None):
+ resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
+ leaves = wkcal.compute_leaves(cr, uid, calendar_id or False , resource_id, resource.calendar_id.id)
+ time_efficiency = resource.time_efficiency
+ resources.append(classobj(str(user.name), (Resource,), {'__doc__': user.name,
+ '__name__': user.name,
+ 'vacation': tuple(leaves),
+ 'efficiency': time_efficiency
+ }))
+ priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300,'4': 100}
+ # Create dynamic no of tasks with the resource specified
+ def create_tasks(j, eff, priorty=500, obj=None):
def task():
"""
task is a dynamic method!
@@ -89,43 +98,47 @@ class wizard_compute_tasks(wizard.interface):
task.__name__ = "task%d" %j
return task
-# Creating the project with all the tasks and resources
+ # Create a 'Faces' project with all the tasks and resources
def Project():
title = project.name
start = date_start
- resource = reduce(operator.or_, resource_objs)
+ try:
+ resource = reduce(operator.or_, resources)
+ except:
+ raise wizard.except_wizard(_('MemberError'), _('Project must have members assigned !'))
minimum_time_unit = 1
-
-# If project has calendar
- if calendar_id:
- working_days = proj.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(proj.leaves_resource(cr, uid, calendar_id))
-
-# Dynamic Creation of tasks
+ if calendar_id: # If project has calendar
+ working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
+ vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
+ # Dynamic Creation of tasks
i = 0
- for each_task in task_obj:
+ for each_task in task_objs:
hours = str(each_task.planned_hours / each_task.occupation_rate)+ 'H'
if each_task.priority in priority_dict.keys():
priorty = priority_dict[each_task.priority]
if each_task.user_id:
- for resource_object in resource_objs:
- if resource_object.__name__ == each_task.user_id.name:
- task = tasks_resource(i, hours, priorty, resource_object)
+ for resource in resources:
+ if resource.__name__ == each_task.user_id.name:
+ task = create_tasks(i, hours, priorty, resource)
else:
- task = tasks_resource(i, hours, priorty)
+ task = create_tasks(i, hours, priorty)
i += 1
-# Writing back the dates
project = BalancedProject(Project)
loop_no = 0
+ # Write back the computed dates
for t in project:
s_date = t.start.to_datetime()
e_date = t.end.to_datetime()
if loop_no == 0:
- project_pool.write(cr, uid, [project_id], {'date' : e_date})
+ project_obj.write(cr, uid, [project_id], {'date' : e_date})
else:
- user_id = user_pool.search(cr, uid, [('name','=',t.booked_resource[0].__name__)])
- task_pool.write(cr, uid, [task_obj[loop_no-1].id], {'date_start' :s_date.strftime('%Y-%m-%d %H:%M:%S'), 'date_deadline' :e_date.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' :user_id[0]}, context={'scheduler' :True})
+ user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
+ task_pool.write(cr, uid, [task_objs[loop_no-1].id], {'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_deadline': e_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'user_id': user_id[0]},
+ context={'scheduler': True
+ })
loop_no +=1
return {}
@@ -137,14 +150,10 @@ class wizard_compute_tasks(wizard.interface):
('compute', 'Compute')
]},
},
-
-
'compute': {
'actions': [_compute_date],
'result': {'type':'form','arch':success_msg,'fields':{}, 'state':[('end', 'Ok')]},
}
}
wizard_compute_tasks('wizard.compute.tasks')
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/project_resource.py b/addons/project_long_term/wizard/project_resource.py
deleted file mode 100644
index c3bc686d980..00000000000
--- a/addons/project_long_term/wizard/project_resource.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import pooler
-import datetime
-
-def timeformat_convert(cr, uid, time_string, context={}):
-# Function to convert input time string:: 8.5 to output time string 8:30
-
- split_list = str(time_string).split('.')
- hour_part = split_list[0]
- mins_part = split_list[1]
- round_mins = int(round(float(mins_part) * 60,-2))
- converted_string = hour_part + ':' + str(round_mins)[0:2]
- return converted_string
-
-def leaves_resource(cr, uid, calendar_id, resource_id=False, resource_calendar=False):
-# To get the leaves for the resource_ids working on phase
-
- pool = pooler.get_pool(cr.dbname)
- resource_leaves_pool = pool.get('resource.calendar.leaves')
- leaves = []
- if resource_id:
- resource_leave_ids = resource_leaves_pool.search(cr, uid, ['|', ('calendar_id','=',calendar_id), ('calendar_id','=',resource_calendar), ('resource_id','=',resource_id)])
- else:
- resource_leave_ids = resource_leaves_pool.search(cr, uid, [('calendar_id','=',calendar_id), ('resource_id','=',False)])
- res_leaves = resource_leaves_pool.read(cr, uid, resource_leave_ids, ['date_from', 'date_to'])
- for leave in range(len(res_leaves)):
- dt_start = datetime.datetime.strptime(res_leaves[leave]['date_from'], '%Y-%m-%d %H:%M:%S')
- dt_end = datetime.datetime.strptime(res_leaves[leave]['date_to'], '%Y-%m-%d %H:%M:%S')
- no = dt_end - dt_start
- [leaves.append((dt_start + datetime.timedelta(days=x)).strftime('%Y-%m-%d')) for x in range(int(no.days + 1))]
- leaves.sort()
- return leaves
-
-def compute_working_calendar(cr, uid, calendar_id):
-# To change the format of working calendar to bring it into 'faces' format
-
- pool = pooler.get_pool(cr.dbname)
- resource_week_pool = pool.get('resource.calendar.week')
- time_range = "8:00-8:00"
- non_working = ""
- wk = {"0":"mon","1":"tue","2":"wed","3":"thu","4":"fri","5":"sat","6":"sun"}
- wk_days = {}
- wk_time = {}
- wktime_list = []
- wktime_cal = []
- week_ids = resource_week_pool.search(cr, uid, [('calendar_id','=',calendar_id)])
- week_obj = resource_week_pool.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'])
-
-# Converting time formats into appropriate format required
-# and creating a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
- for week in week_obj:
- res_str = ""
- if wk.has_key(week['dayofweek']):
- day = wk[week['dayofweek']]
- wk_days[week['dayofweek']] = wk[week['dayofweek']]
-
- hour_from_str = timeformat_convert(cr, uid, week['hour_from'])
- hour_to_str = timeformat_convert(cr, uid, week['hour_to'])
- res_str = hour_from_str + '-' + hour_to_str
- wktime_list.append((day, res_str))
-
-# Converting it to format like [('mon', '8:00-12:00', '13:00-18:00')]
- for item in wktime_list:
- if wk_time.has_key(item[0]):
- wk_time[item[0]].append(item[1])
- else:
- wk_time[item[0]] = [item[0]]
- wk_time[item[0]].append(item[1])
-
- for k,v in wk_time.items():
- wktime_cal.append(tuple(v))
-
-# For non working days adding [('tue,wed,fri,sat,sun', '8:00-8:00')]
- for k,v in wk_days.items():
- if wk.has_key(k):
- wk.pop(k)
- for v in wk.itervalues():
- non_working += v + ','
- if non_working:
- wktime_cal.append((non_working[:-1], time_range))
-
- return wktime_cal
\ No newline at end of file
diff --git a/addons/project_long_term/wizard/schedule_tasks.py b/addons/project_long_term/wizard/schedule_tasks.py
index ac968e276f6..6db678333a9 100644
--- a/addons/project_long_term/wizard/schedule_tasks.py
+++ b/addons/project_long_term/wizard/schedule_tasks.py
@@ -23,45 +23,53 @@ import wizard
import pooler
from tools.translate import _
import datetime
+
from resource.faces import *
from new import classobj
import operator
-import time
-import project_resource as proj
+
+import working_calendar as wkcal
success_msg = """
"""
-def resource_list(cr, uid, phase):
-# To create resources which are the Project Members
+class wizard_schedule_task(wizard.interface):
+ def _create_resources(self, cr, uid, phase, context={}):
+ """
+ Return a list of Resource Class objects for the resources allocated to the phase.
+ """
resource_objs = []
for resource in phase.resource_ids:
res = resource.resource_id
leaves = []
resource_eff = res.time_efficiency
resource_cal = res.calendar_id.id
- wktime_cal = proj.compute_working_calendar(cr, uid, resource_cal)
- leaves = proj.leaves_resource(cr, uid, phase.project_id.resource_calendar_id.id or False , res.id, resource_cal)
- resource_objs.append(classobj(str(res.user_id.name), (Resource,), {'__doc__' : res.user_id.name, '__name__' : res.user_id.name, 'vacation' : tuple(leaves), 'efficiency' : resource_eff}))
+ if resource_cal:
+ leaves = wkcal.compute_leaves(cr, uid, phase.project_id.resource_calendar_id.id or False, res.id, resource_cal)
+ resource_objs.append(classobj(str(res.user_id.name), (Resource,),
+ {'__doc__': res.user_id.name,
+ '__name__': res.user_id.name,
+ 'vacation': tuple(leaves),
+ 'efficiency': resource_eff
+ }))
return resource_objs
-class wizard_schedule_task(wizard.interface):
-
def _compute_date(self, cr, uid, data, context):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
pool = pooler.get_pool(cr.dbname)
- phase_pool = pool.get('project.phase')
- task_pool = pool.get('project.task')
- user_pool = pool.get('res.users')
- phase = phase_pool.browse(cr, uid, data['id'])
- task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open','draft','pending'] , phase.task_ids)))
-
+ phase_obj = pool.get('project.phase')
+ task_obj = pool.get('project.task')
+ user_obj = pool.get('res.users')
+ phase = phase_obj.browse(cr, uid, data['id'], context=context)
+ task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open', 'draft', 'pending'] , phase.task_ids)))
if task_ids:
task_ids.sort()
- tasks = task_pool.browse(cr, uid, task_ids)
- wktime_cal = []
+ tasks = task_obj.browse(cr, uid, task_ids, context=context)
start_date = str(phase.date_start)[:-9]
if not phase.date_start:
if not phase.project_id.date_start:
@@ -70,11 +78,10 @@ class wizard_schedule_task(wizard.interface):
start_date = phase.project_id.date_start
date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
calendar_id = phase.project_id.resource_calendar_id.id
- resource_objs = resource_list(cr, uid, phase)
- priority_dict = {'0' :1000,'1' :800,'2' :500,'3' :300,'4' :100}
-
-# To create dynamic no of tasks with the resource specified
- def tasks_resource(j, eff, priorty=500, obj=False):
+ resources = self._create_resources(cr, uid, phase)
+ priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300, '4': 100}
+ # Create dynamic no of tasks with the resource specified
+ def create_tasks(j, eff, priorty=500, obj=False):
def task():
"""
task is a dynamic method!
@@ -87,44 +94,47 @@ class wizard_schedule_task(wizard.interface):
task.__name__ = "task%d" %j
return task
-# Creating the project with all the tasks and resources
+ # Create a 'Faces' project with all the tasks and resources
def Project():
- title = "Test Project"
+ title = "Project"
start = date_start
- resource = reduce(operator.or_, resource_objs)
+ try:
+ resource = reduce(operator.or_, resources)
+ except:
+ raise wizard.except_wizard(_('ResourceError'), _('Phase must have resources assigned !'))
minimum_time_unit = 1
-
-# If project has calendar
- if calendar_id:
- working_days = proj.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(proj.leaves_resource(cr, uid, calendar_id))
-
-# Dynamic Creation of tasks
+ if calendar_id: # If project has working calendar
+ working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
+ vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
+ # Dynamic creation of tasks
i = 0
for each_task in tasks:
hours = str(each_task.planned_hours / each_task.occupation_rate)+ 'H'
if each_task.priority in priority_dict.keys():
priorty = priority_dict[each_task.priority]
if each_task.user_id:
- for resource_object in resource_objs:
- if resource_object.__name__ == each_task.user_id.name:
- task = tasks_resource(i, hours, priorty, resource_object)
+ for resource in resources:
+ if resource.__name__ == each_task.user_id.name:
+ task = create_tasks(i, hours, priorty, resource)
else:
- task = tasks_resource(i, hours, priorty)
+ task = create_tasks(i, hours, priorty)
i += 1
-# Writing back the dates
project = BalancedProject(Project)
loop_no = 0
+ # Write back the computed dates
for t in project:
s_date = t.start.to_datetime()
e_date = t.end.to_datetime()
if loop_no > 0:
- user_id = user_pool.search(cr, uid, [('name','=',t.booked_resource[0].__name__)])
- task_pool.write(cr, uid, [tasks[loop_no-1].id], {'date_start' :s_date.strftime('%Y-%m-%d %H:%M:%S'), 'date_deadline' :e_date.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' :user_id[0]}, context={'scheduler' :True})
+ user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
+ task_obj.write(cr, uid, [tasks[loop_no-1].id], {'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_deadline': e_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'user_id': user_id[0]},
+ context={'scheduler': True
+ })
loop_no +=1
return {}
-
states = {
'init': {
'actions': [_compute_date],
@@ -132,6 +142,4 @@ class wizard_schedule_task(wizard.interface):
}
}
wizard_schedule_task('phase.schedule.tasks')
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/working_calendar.py b/addons/project_long_term/wizard/working_calendar.py
new file mode 100644
index 00000000000..faddcdd0011
--- /dev/null
+++ b/addons/project_long_term/wizard/working_calendar.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import pooler
+import datetime
+
+def convert_timeformat(cr, uid, time_string, context={}):
+ """ Convert input time string: 8.5 to output time string 8:30."""
+
+ split_list = str(time_string).split('.')
+ hour_part = split_list[0]
+ mins_part = split_list[1]
+ round_mins = int(round(float(mins_part) * 60,-2))
+ converted_string = hour_part + ':' + str(round_mins)[0:2]
+ return converted_string
+
+def compute_leaves(cr, uid, calendar_id, resource_id=False, resource_calendar=False):
+
+ """Compute the leaves from the working calendar of the resource.
+
+ Arguements: calendar_id -- working calendar of the project
+ resource_id -- resource working on phase/task
+ resource_calendar -- working calendar of the resource
+
+ """
+
+ pool = pooler.get_pool(cr.dbname)
+ resource_calendar_leaves_obj = pool.get('resource.calendar.leaves')
+ leave_list = []
+ if resource_id:
+ leave_ids = resource_calendar_leaves_obj.search(cr, uid, ['|', ('calendar_id', '=', calendar_id),
+ ('calendar_id', '=', resource_calendar),
+ ('resource_id', '=', resource_id)
+ ])
+ else:
+ leave_ids = resource_calendar_leaves_obj.search(cr, uid, [('calendar_id', '=', calendar_id),
+ ('resource_id', '=', False)
+ ])
+ leaves = resource_calendar_leaves_obj.read(cr, uid, leave_ids, ['date_from', 'date_to'])
+ for i in range(len(leaves)):
+ dt_start = datetime.datetime.strptime(leaves[i]['date_from'], '%Y-%m-%d %H:%M:%S')
+ dt_end = datetime.datetime.strptime(leaves[i]['date_to'], '%Y-%m-%d %H:%M:%S')
+ no = dt_end - dt_start
+ [leave_list.append((dt_start + datetime.timedelta(days=x)).strftime('%Y-%m-%d')) for x in range(int(no.days + 1))]
+ leave_list.sort()
+ return leave_list
+
+def compute_working_calendar(cr, uid, calendar_id):
+
+ """Change the format of working calendar from 'Openerp' format to bring it into 'Faces' format.
+
+ Arguement: calendar_id -- working calendar of the project
+
+ """
+
+ pool = pooler.get_pool(cr.dbname)
+ resource_week_obj = pool.get('resource.calendar.week')
+ time_range = "8:00-8:00"
+ non_working = ""
+ week_days = {"0": "mon", "1": "tue", "2": "wed","3": "thu", "4": "fri", "5": "sat", "6": "sun"}
+ wk_days = {}
+ wk_time = {}
+ wktime_list = []
+ wktime_cal = []
+ week_ids = resource_week_obj.search(cr, uid, [('calendar_id', '=', calendar_id)])
+ weeks = resource_week_obj.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'])
+ # Convert time formats into appropriate format required
+ # and create a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
+ for week in weeks:
+ res_str = ""
+ if week_days.has_key(week['dayofweek']):
+ day = week_days[week['dayofweek']]
+ wk_days[week['dayofweek']] = week_days[week['dayofweek']]
+ hour_from_str = convert_timeformat(cr, uid, week['hour_from'])
+ hour_to_str = convert_timeformat(cr, uid, week['hour_to'])
+ res_str = hour_from_str + '-' + hour_to_str
+ wktime_list.append((day, res_str))
+ # Convert into format like [('mon', '8:00-12:00', '13:00-18:00')]
+ for item in wktime_list:
+ if wk_time.has_key(item[0]):
+ wk_time[item[0]].append(item[1])
+ else:
+ wk_time[item[0]] = [item[0]]
+ wk_time[item[0]].append(item[1])
+ for k,v in wk_time.items():
+ wktime_cal.append(tuple(v))
+ # Add for the non-working days like: [('sat, sun', '8:00-8:00')]
+ for k,v in wk_days.items():
+ if week_days.has_key(k):
+ week_days.pop(k)
+ for v in week_days.itervalues():
+ non_working += v + ','
+ if non_working:
+ wktime_cal.append((non_working[:-1], time_range))
+ return wktime_cal
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/scrum/report/__init__.py b/addons/scrum/report/__init__.py
index 2e7bbe68cd0..6112b117959 100644
--- a/addons/scrum/report/__init__.py
+++ b/addons/scrum/report/__init__.py
@@ -19,7 +19,6 @@
#
##############################################################################
-import task_burndown
import sprint_burndown
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/scrum/report/sprint_burndown.py b/addons/scrum/report/sprint_burndown.py
index 79a549ff81f..cdc837fe96b 100644
--- a/addons/scrum/report/sprint_burndown.py
+++ b/addons/scrum/report/sprint_burndown.py
@@ -50,9 +50,6 @@ class report_tasks(report_int):
cr.execute('select id,date_start,date_stop from scrum_sprint where id=%s', (datas['id'],))
for (id,date_start,date_stop) in cr.fetchall():
- date_to_int = lambda x: int(x.ticks())
- int_to_date = lambda x: '/a60{}'+DateTime.localtime(x).strftime('%d/%m/%Y')
-
cr.execute('select id from project_task where product_backlog_id in(select id from scrum_product_backlog where sprint_id=%s)', (id,))
ids = map(lambda x: x[0], cr.fetchall())
@@ -71,7 +68,9 @@ class report_tasks(report_int):
if (not result) or result[-1]<>res:
result.append(res)
return result
-
+
+ guideline__data=[(datas[0][0],max_hour), (datas[-1][0],0)]
+
ar = area.T(x_grid_style=line_style.gray50_dash1,
x_axis=axis.X(label="Date", format=int_to_date),
y_axis=axis.Y(label="Burndown Chart - Planned Hours"),
@@ -80,7 +79,14 @@ class report_tasks(report_int):
y_range = (0,max_hour),
legend = None,
size = (680,450))
- ar.add_plot(line_plot.T(data=datas))
+ ar.add_plot(line_plot.T(data=guideline__data, line_style=line_style.red))
+ ar.add_plot(line_plot.T(data=datas, line_style=line_style.green))
+
+ entr1 = pychart.legend.Entry(label="guideline", line_style=line_style.red)
+ entr2 = pychart.legend.Entry(label="burndownchart",line_style=line_style.green)
+ legend = pychart.legend.T(nr_rows=2, inter_row_sep=5)
+ legend.draw(ar,[entr1,entr2],canv)
+
ar.draw(canv)
canv.close()
diff --git a/addons/scrum/scrum_report.xml b/addons/scrum/scrum_report.xml
index a5b3a672986..845a677c356 100644
--- a/addons/scrum/scrum_report.xml
+++ b/addons/scrum/scrum_report.xml
@@ -1,10 +1,6 @@
-
-
-
-
+
-