summaryrefslogtreecommitdiff
path: root/addons/project/project.py
diff options
context:
space:
mode:
Diffstat (limited to 'addons/project/project.py')
-rw-r--r--addons/project/project.py160
1 files changed, 143 insertions, 17 deletions
diff --git a/addons/project/project.py b/addons/project/project.py
index abebd2d35ff..0046dea4409 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -114,6 +114,7 @@ class project(osv.osv):
if task.project_id: result[task.project_id.id] = True
return result.keys()
+ #dead code
def _get_project_work(self, cr, uid, ids, context=None):
result = {}
for work in self.pool.get('project.task.work').browse(cr, uid, ids, context=context):
@@ -360,7 +361,7 @@ def Project():
working_days = %s
resource = %s
""" % (
- project.id,
+ project.id,
project.date_start, working_days,
'|'.join(['User_'+str(x) for x in puids])
)
@@ -879,14 +880,24 @@ class task(osv.osv):
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
return True
+
+ def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None):
+ attachment = self.pool.get('ir.attachment')
+ attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', task_id)], context=context)
+ new_attachment_ids = []
+ for attachment_id in attachment_ids:
+ new_attachment_ids.append(attachment.copy(cr, uid, attachment_id, default={'res_id': delegated_task_id}, context=context))
+ return new_attachment_ids
+
+
def do_delegate(self, cr, uid, ids, delegate_data={}, context=None):
"""
Delegate Task to another users.
"""
assert delegate_data['user_id'], _("Delegated User should be specified")
- delegrated_tasks = {}
+ delegated_tasks = {}
for task in self.browse(cr, uid, ids, context=context):
- delegrated_task_id = self.copy(cr, uid, task.id, {
+ delegated_task_id = self.copy(cr, uid, task.id, {
'name': delegate_data['name'],
'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False,
'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False,
@@ -897,6 +908,7 @@ class task(osv.osv):
'child_ids': [],
'work_ids': []
}, context=context)
+ self._delegate_task_attachments(cr, uid, task.id, delegated_task_id, context=context)
newname = delegate_data['prefix'] or ''
task.write({
'remaining_hours': delegate_data['planned_hours_me'],
@@ -910,8 +922,8 @@ class task(osv.osv):
message = _("The task '%s' has been delegated to %s.") % (delegate_data['name'], delegate_data['user_id'][1])
self.log(cr, uid, task.id, message)
- delegrated_tasks[task.id] = delegrated_task_id
- return delegrated_tasks
+ delegated_tasks[task.id] = delegated_task_id
+ return delegated_tasks
def do_pending(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'pending'}, context=context)
@@ -920,21 +932,24 @@ class task(osv.osv):
self.log(cr, uid, id, message)
return True
- def set_remaining_time_1(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 1.0}, context=context)
+ def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None):
+ for task in self.browse(cr, uid, ids, context=context):
+ if (task.state=='draft') or (task.planned_hours==0.0):
+ self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context)
+ self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context)
return True
+ def set_remaining_time_1(self, cr, uid, ids, context=None):
+ return self.set_remaining_time(cr, uid, ids, 1.0, context)
+
def set_remaining_time_2(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 2.0}, context=context)
- return True
+ return self.set_remaining_time(cr, uid, ids, 2.0, context)
def set_remaining_time_5(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 5.0}, context=context)
- return True
+ return self.set_remaining_time(cr, uid, ids, 5.0, context)
def set_remaining_time_10(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 10.0}, context=context)
- return True
+ return self.set_remaining_time(cr, uid, ids, 10.0, context)
def set_kanban_state_blocked(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'kanban_state': 'blocked'}, context=context)
@@ -974,6 +989,25 @@ class task(osv.osv):
def prev_type(self, cr, uid, ids, *args):
return self._change_type(cr, uid, ids, False, *args)
+ def _store_history(self, cr, uid, ids, context=None):
+ for task in self.browse(cr, uid, ids, context=context):
+ self.pool.get('project.task.history').create(cr, uid, {
+ 'task_id': task.id,
+ 'remaining_hours': task.remaining_hours,
+ 'planned_hours': task.planned_hours,
+ 'kanban_state': task.kanban_state,
+ 'type_id': task.type_id.id,
+ 'state': task.state,
+ 'user_id': task.user_id.id
+
+ }, context=context)
+ return True
+
+ def create(self, cr, uid, vals, context=None):
+ result = super(task, self).create(cr, uid, vals, context=context)
+ self._store_history(cr, uid, [result], context=context)
+ return result
+
# Overridden to reset the kanban_state to normal whenever
# the stage (type_id) of the task changes.
def write(self, cr, uid, ids, vals, context=None):
@@ -985,8 +1019,12 @@ class task(osv.osv):
for t in self.browse(cr, uid, ids, context=context):
write_vals = vals_reset_kstate if t.type_id != new_stage else vals
super(task,self).write(cr, uid, [t.id], write_vals, context=context)
- return True
- return super(task,self).write(cr, uid, ids, vals, context=context)
+ result = True
+ else:
+ result = super(task,self).write(cr, uid, ids, vals, context=context)
+ if ('type_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals):
+ self._store_history(cr, uid, ids, context=context)
+ return result
def unlink(self, cr, uid, ids, context=None):
if context == None:
@@ -1074,7 +1112,7 @@ class account_analytic_account(osv.osv):
if vals.get('child_ids', False) and context.get('analytic_project_copy', False):
vals['child_ids'] = []
return super(account_analytic_account, self).create(cr, uid, vals, context=context)
-
+
def unlink(self, cr, uid, ids, *args, **kwargs):
project_obj = self.pool.get('project.project')
analytic_ids = project_obj.search(cr, uid, [('analytic_account_id','in',ids)])
@@ -1084,4 +1122,92 @@ class account_analytic_account(osv.osv):
account_analytic_account()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+#
+# Tasks History, used for cumulative flow charts (Lean/Agile)
+#
+
+class project_task_history(osv.osv):
+ _name = 'project.task.history'
+ _description = 'History of Tasks'
+ _rec_name = 'task_id'
+ _log_access = False
+ def _get_date(self, cr, uid, ids, name, arg, context=None):
+ result = {}
+ for history in self.browse(cr, uid, ids, context=context):
+ if history.state in ('done','cancelled'):
+ result[history.id] = history.date
+ continue
+ cr.execute('''select
+ date
+ from
+ project_task_history
+ where
+ task_id=%s and
+ id>%s
+ order by id limit 1''', (history.task_id.id, history.id))
+ res = cr.fetchone()
+ result[history.id] = res and res[0] or False
+ return result
+
+ def _get_related_date(self, cr, uid, ids, context=None):
+ result = []
+ for history in self.browse(cr, uid, ids, context=context):
+ cr.execute('''select
+ id
+ from
+ project_task_history
+ where
+ task_id=%s and
+ id<%s
+ order by id desc limit 1''', (history.task_id.id, history.id))
+ res = cr.fetchone()
+ if res:
+ result.append(res[0])
+ return result
+
+ _columns = {
+ 'task_id': fields.many2one('project.task', 'Task', ondelete='cascade', required=True, select=True),
+ 'type_id': fields.many2one('project.task.type', 'Stage'),
+ 'state': fields.selection([('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')], 'State'),
+ 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready To Pull')], 'Kanban State', required=False),
+ 'date': fields.date('Date', select=True),
+ 'end_date': fields.function(_get_date, string='End Date', type="date", store={
+ 'project.task.history': (_get_related_date, None, 20)
+ }),
+ 'remaining_hours': fields.float('Remaining Time', digits=(16,2)),
+ 'planned_hours': fields.float('Planned Time', digits=(16,2)),
+ 'user_id': fields.many2one('res.users', 'Responsible'),
+ }
+ _defaults = {
+ 'date': lambda s,c,u,ctx: time.strftime('%Y-%m-%d')
+ }
+project_task_history()
+
+class project_task_history_cumulative(osv.osv):
+ _name = 'project.task.history.cumulative'
+ _table = 'project_task_history_cumulative'
+ _inherit = 'project.task.history'
+ _auto = False
+ _columns = {
+ 'end_date': fields.date('End Date'),
+ 'project_id': fields.related('task_id', 'project_id', string='Project', type='many2one', relation='project.project')
+ }
+ def init(self, cr):
+ cr.execute(""" CREATE OR REPLACE VIEW project_task_history_cumulative AS (
+ SELECT
+ history.date::varchar||'-'||history.history_id::varchar as id,
+ history.date as end_date,
+ *
+ FROM (
+ SELECT
+ id as history_id,
+ date+generate_series(0, CAST((coalesce(end_date,DATE 'tomorrow')::date - date)AS integer)-1) as date,
+ task_id, type_id, user_id, kanban_state, state,
+ remaining_hours, planned_hours
+ FROM
+ project_task_history
+ ) as history
+ )
+ """)
+project_task_history_cumulative()
+