diff options
Diffstat (limited to 'addons/project/project.py')
| -rw-r--r-- | addons/project/project.py | 160 |
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() + |
