diff options
| author | Thibault Delavallée <tde@openerp.com> | 2013-06-26 15:25:19 +0200 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2013-06-26 15:25:19 +0200 |
| commit | 8fbfc997aebb788d79200e711389817e9ce719df (patch) | |
| tree | 6ac20665ef2dd12230676cb0fc9ac675ae7d931f /addons | |
| parent | c180afab26171617c1c7c22db5d9836b159e5e7d (diff) | |
[REF] project: stage/status refactoring
Removed concept of state on project.task (and propagated report)
Removed python inheritance towards base_stage (specific code will be re-added)
bzr revid: tde@openerp.com-20130626132519-988nfq8pw8h8c8e8
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/mail/mail_thread.py | 13 | ||||
| -rw-r--r-- | addons/project/__openerp__.py | 2 | ||||
| -rw-r--r-- | addons/project/board_project_view.xml | 3 | ||||
| -rw-r--r-- | addons/project/project.py | 214 | ||||
| -rw-r--r-- | addons/project/project_data.xml | 48 | ||||
| -rw-r--r-- | addons/project/project_demo.xml | 20 | ||||
| -rw-r--r-- | addons/project/project_view.xml | 60 | ||||
| -rw-r--r-- | addons/project/report/project_report.py | 26 | ||||
| -rw-r--r-- | addons/project/report/project_report_view.xml | 40 | ||||
| -rw-r--r-- | addons/project/test/task_process.yml | 11 | ||||
| -rw-r--r-- | addons/project/wizard/__init__.py | 2 | ||||
| -rw-r--r-- | addons/project/wizard/project_task_reevaluate.py | 84 | ||||
| -rw-r--r-- | addons/project/wizard/project_task_reevaluate_view.xml | 32 | ||||
| -rw-r--r-- | addons/project_issue/project_issue.py | 8 |
14 files changed, 162 insertions, 401 deletions
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 403cfab7d61..7181e52e9b6 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -328,8 +328,8 @@ class mail_thread(osv.AbstractModel): # Track initial values of tracked fields tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context) if tracked_fields: - initial = self.read(cr, uid, ids, tracked_fields.keys(), context=context) - initial_values = dict((item['id'], item) for item in initial) + records = self.browse(cr, uid, ids, context=context) + initial_values = dict((this.id, dict((key, getattr(this, key)) for key in tracked_fields.keys())) for this in records) # Perform write, update followers result = super(mail_thread, self).write(cr, uid, ids, values, context=context) @@ -388,7 +388,8 @@ class mail_thread(osv.AbstractModel): if not value: return '' if col_info['type'] == 'many2one': - return value[1] + # return value[1] + return value.name_get()[0][1] if col_info['type'] == 'selection': return dict(col_info['selection'])[value] return value @@ -407,7 +408,9 @@ class mail_thread(osv.AbstractModel): if not tracked_fields: return True - for record in self.read(cr, uid, ids, tracked_fields.keys(), context=context): + for browse_record in self.browse(cr, uid, ids, context=context): + record = dict((key, getattr(browse_record, key)) for key in tracked_fields.keys()) + record['id'] = browse_record.id initial = initial_values[record['id']] changes = [] tracked_values = {} @@ -433,7 +436,7 @@ class mail_thread(osv.AbstractModel): if field not in changes: continue for subtype, method in track_info.items(): - if method(self, cr, uid, record, context): + if method(self, cr, uid, browse_record, context): subtypes.append(subtype) posted = False diff --git a/addons/project/__openerp__.py b/addons/project/__openerp__.py index c0a516cf555..634f79d12ac 100644 --- a/addons/project/__openerp__.py +++ b/addons/project/__openerp__.py @@ -40,7 +40,6 @@ ], 'depends': [ 'base_setup', - 'base_status', 'product', 'analytic', 'board', @@ -66,7 +65,6 @@ Dashboard / Reports for Project Management will include: 'data': [ 'security/project_security.xml', 'wizard/project_task_delegate_view.xml', - 'wizard/project_task_reevaluate_view.xml', 'security/ir.model.access.csv', 'project_data.xml', 'project_view.xml', diff --git a/addons/project/board_project_view.xml b/addons/project/board_project_view.xml index 931c661d211..3a14f7b6274 100644 --- a/addons/project/board_project_view.xml +++ b/addons/project/board_project_view.xml @@ -16,7 +16,6 @@ <field name="effective_hours" widget="float_time"/> <field name="progress" widget="progressbar"/> <field name="stage_id" invisible="context.get('set_visible',False)"/> - <field name="state" invisible="1"/> </tree> </field> </record> @@ -26,7 +25,7 @@ <field name="res_model">project.task</field> <field name="view_type">form</field> <field name="view_mode">tree,form</field> - <field name="domain">[('user_id','=',uid),('state','not in',('cancel','done'))]</field> + <field name="domain">[('user_id', '=', uid), ('stage_id.fold', '!=', True)]</field> <field name="view_id" ref="view_task_tree"/> </record> diff --git a/addons/project/project.py b/addons/project/project.py index cadc4d8afb8..738c512fe16 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -28,10 +28,8 @@ from openerp import tools from openerp.osv import fields, osv from openerp.tools.translate import _ -from openerp.addons.base_status.base_stage import base_stage from openerp.addons.resource.faces import task as Task -_TASK_STATE = [('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')] class project_task_type(osv.osv): _name = 'project.task.type' @@ -44,9 +42,6 @@ class project_task_type(osv.osv): 'case_default': fields.boolean('Default for New Projects', help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."), 'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'), - 'state': fields.selection(_TASK_STATE, 'Related Status', required=True, - help="The status of your document is automatically changed regarding the selected stage. " \ - "For example, if a stage is related to the status 'Close', when your document reaches this stage, it is automatically closed."), 'fold': fields.boolean('Folded by Default', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), } @@ -57,7 +52,6 @@ class project_task_type(osv.osv): return proj _defaults = { 'sequence': 1, - 'state': 'open', 'fold': False, 'case_default': False, 'project_ids': _get_default_project_id @@ -152,11 +146,13 @@ class project(osv.osv): cr.execute(""" SELECT project_id, COALESCE(SUM(planned_hours), 0.0), COALESCE(SUM(total_hours), 0.0), COALESCE(SUM(effective_hours), 0.0) - FROM project_task WHERE project_id IN %s AND state <> 'cancelled' + FROM project_task + LEFT JOIN project_task_type ON project_task.stage_id = project_task_type.id + WHERE project_task.project_id IN %s AND project_task_type.fold = False GROUP BY project_id """, (tuple(child_parent.keys()),)) # aggregate results into res - res = dict([(id, {'planned_hours':0.0,'total_hours':0.0,'effective_hours':0.0}) for id in ids]) + res = dict([(id, {'planned_hours':0.0, 'total_hours':0.0, 'effective_hours':0.0}) for id in ids]) for id, planned, total, effective in cr.fetchall(): # add the values specific to id to all parent projects of id in the result while id: @@ -253,22 +249,22 @@ class project(osv.osv): 'planned_hours': fields.function(_progress_rate, multi="progress", string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'effective_hours': fields.function(_progress_rate, multi="progress", string='Time Spent', help="Sum of spent hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'total_hours': fields.function(_progress_rate, multi="progress", string='Total Time', help="Sum of total hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'progress_rate': fields.function(_progress_rate, multi="progress", string='Progress', type='float', group_operator="avg", help="Percent of tasks closed according to the total of tasks todo.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ), 'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}), @@ -327,22 +323,16 @@ class project(osv.osv): return res def set_done(self, cr, uid, ids, context=None): - task_obj = self.pool.get('project.task') - task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', 'not in', ('cancelled', 'done'))]) - task_obj.case_close(cr, uid, task_ids, context=context) - return self.write(cr, uid, ids, {'state':'close'}, context=context) + return self.write(cr, uid, ids, {'state': 'close'}, context=context) def set_cancel(self, cr, uid, ids, context=None): - task_obj = self.pool.get('project.task') - task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', '!=', 'done')]) - task_obj.case_cancel(cr, uid, task_ids, context=context) - return self.write(cr, uid, ids, {'state':'cancelled'}, context=context) + return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context) def set_pending(self, cr, uid, ids, context=None): - return self.write(cr, uid, ids, {'state':'pending'}, context=context) + return self.write(cr, uid, ids, {'state': 'pending'}, context=context) def set_open(self, cr, uid, ids, context=None): - return self.write(cr, uid, ids, {'state':'open'}, context=context) + return self.write(cr, uid, ids, {'state': 'open'}, context=context) def reset_project(self, cr, uid, ids, context=None): return self.setActive(cr, uid, ids, value=True, context=context) @@ -459,7 +449,8 @@ class project(osv.osv): if project.user_id and (project.user_id.id not in u_ids): u_ids.append(project.user_id.id) for task in project.tasks: - if task.state in ('done','cancelled'): + # TDE: be sure about this, was if task.state in ('done','cancelled') + if task.stage_id and task.stage_id.fold: continue if task.user_id and (task.user_id.id not in u_ids): u_ids.append(task.user_id.id) @@ -525,7 +516,8 @@ def Project(): for project in projects: project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,)) for task in project.tasks: - if task.state in ('done', 'cancelled'): + # TDE CHECK: was if task.state in ('done', 'cancelled') + if task.stage_id and task.stage_id.fold: continue p = getattr(project_gantt, 'Task_%d' % (task.id,)) @@ -566,23 +558,20 @@ def Project(): vals.update(alias_model_id=model_ids[0]) return super(project, self).write(cr, uid, ids, vals, context=context) -class task(base_stage, osv.osv): + +class task(osv.osv): _name = "project.task" _description = "Task" _date_name = "date_start" _inherit = ['mail.thread', 'ir.needaction_mixin'] _track = { - 'state': { - 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj['state'] in ['new', 'draft'], - 'project.mt_task_started': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'open', - 'project.mt_task_closed': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done', - }, 'stage_id': { - 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'draft', 'done', 'open'], + 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1, + 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.stage_id.sequence != 1, }, 'kanban_state': { # kanban state: tracked, but only block subtype - 'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj['kanban_state'] == 'blocked', + 'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'blocked', }, } @@ -593,14 +582,15 @@ class task(base_stage, osv.osv): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ project_id = self._get_default_project_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], project_id, [('state', '=', 'draft')], context=context) + return self.stage_find(cr, uid, [], project_id, [('sequence', '=', '1')], context=context) def _resolve_project_id_from_context(self, cr, uid, context=None): """ Returns ID of project based on the value of 'default_project_id' context key, or None if it cannot be resolved to a single project. """ - if context is None: context = {} + if context is None: + context = {} if type(context.get('default_project_id')) in (int, long): return context['default_project_id'] if isinstance(context.get('default_project_id'), basestring): @@ -669,7 +659,8 @@ class task(base_stage, osv.osv): res[task.id]['progress'] = 0.0 if (task.remaining_hours + hours.get(task.id, 0.0)): res[task.id]['progress'] = round(min(100.0 * hours.get(task.id, 0.0) / res[task.id]['total_hours'], 99.99),2) - if task.state in ('done','cancelled'): + # TDE CHECK: if task.state in ('done','cancelled'): + if task.stage_id and task.stage_id.fold: res[task.id]['progress'] = 100.0 return res @@ -690,6 +681,13 @@ class task(base_stage, osv.osv): return {'value':{'partner_id':partner_id.id}} return {} + def onchange_user_id(self, cr, uid, ids, user_id, context=None): + vals = {} + if user_id: + vals['date_start'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) + vals['date_end'] = False + return {'value': vals} + def duplicate_task(self, cr, uid, map_ids, context=None): for new in map_ids.values(): task = self.browse(cr, uid, new, context) @@ -743,17 +741,12 @@ class task(base_stage, osv.osv): 'active': fields.function(_is_template, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."), 'name': fields.char('Task Summary', size=128, required=True, select=True), 'description': fields.text('Description'), - 'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True), + 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), + ('1', 'Important'), ('0', 'Very important')], + string='Priority', select=True), 'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."), 'stage_id': fields.many2one('project.task.type', 'Stage', track_visibility='onchange', domain="[('project_ids', '=', project_id)]"), - 'state': fields.related('stage_id', 'state', type="selection", store=True, - selection=_TASK_STATE, string="Status", readonly=True, - help='The status is set to \'Draft\', when a case is created.\ - If the case is in progress the status is set to \'Open\'.\ - When the case is over, the status is set to \'Done\'.\ - If the case needs to be reviewed then the status is \ - set to \'Pending\'.'), 'categ_ids': fields.many2many('project.category', string='Tags'), 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State', track_visibility='onchange', @@ -766,6 +759,7 @@ class task(base_stage, osv.osv): 'date_start': fields.datetime('Starting Date',select=True), 'date_end': fields.datetime('Ending Date',select=True), 'date_deadline': fields.date('Deadline',select=True), + 'date_last_stage_update': fields.datetime('Last Stage Update', select=True), 'project_id': fields.many2one('project.project', 'Project', ondelete='set null', select="1", track_visibility='onchange'), 'parent_ids': fields.many2many('project.task', 'project_task_parent_rel', 'task_id', 'parent_id', 'Parent Tasks'), 'child_ids': fields.many2many('project.task', 'project_task_parent_rel', 'parent_id', 'task_id', 'Delegated Tasks'), @@ -782,7 +776,7 @@ class task(base_stage, osv.osv): 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), - 'progress': fields.function(_hours_get, string='Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time", + 'progress': fields.function(_hours_get, string='Working Time Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time", store = { 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours','state'], 10), 'project.task.work': (_get_task, ['hours'], 10), @@ -805,6 +799,7 @@ class task(base_stage, osv.osv): _defaults = { 'stage_id': _get_default_stage_id, 'project_id': _get_default_project_id, + 'date_last_stage_update': lambda *a: fields.datetime.now(), 'kanban_state': 'normal', 'priority': '2', 'progress': 0, @@ -931,10 +926,11 @@ class task(base_stage, osv.osv): section_ids.append(task.project_id.id) search_domain = [] if section_ids: - search_domain = [('|')] * (len(section_ids)-1) + search_domain = [('|')] * (len(section_ids) - 1) for section_id in section_ids: search_domain.append(('project_ids', '=', section_id)) - search_domain += list(domain) + if domain: + search_domain += list(domain) # perform search, return the first found stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context) if stage_ids: @@ -948,82 +944,11 @@ class task(base_stage, osv.osv): for task in tasks: if task.child_ids: for child in task.child_ids: - if child.state in ['draft', 'open', 'pending']: + # TDE CHECK: was 'if child.state in ['draft', 'open', 'pending']'' + if child.stage_id and not child.stage_id.fold: raise osv.except_osv(_("Warning!"), _("Child task still open.\nPlease cancel or complete child task first.")) return True - def action_close(self, cr, uid, ids, context=None): - """ This action closes the task - """ - task_id = len(ids) and ids[0] or False - self._check_child_task(cr, uid, ids, context=context) - if not task_id: return False - return self.do_close(cr, uid, [task_id], context=context) - - def do_close(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_close. """ - return self.case_close(cr, uid, ids, context=context) - - def case_close(self, cr, uid, ids, context=None): - """ Closes Task """ - if not isinstance(ids, list): ids = [ids] - for task in self.browse(cr, uid, ids, context=context): - vals = {} - project = task.project_id - for parent_id in task.parent_ids: - if parent_id.state in ('pending','draft'): - reopen = True - for child in parent_id.child_ids: - if child.id != task.id and child.state not in ('done','cancelled'): - reopen = False - if reopen: - self.do_reopen(cr, uid, [parent_id.id], context=context) - # close task - vals['remaining_hours'] = 0.0 - if not task.date_end: - vals['date_end'] = fields.datetime.now() - self.case_set(cr, uid, [task.id], 'done', vals, context=context) - return True - - def do_reopen(self, cr, uid, ids, context=None): - for task in self.browse(cr, uid, ids, context=context): - project = task.project_id - self.case_set(cr, uid, [task.id], 'open', {}, context=context) - return True - - def do_cancel(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_cancel. """ - return self.case_cancel(cr, uid, ids, context=context) - - def case_cancel(self, cr, uid, ids, context=None): - tasks = self.browse(cr, uid, ids, context=context) - self._check_child_task(cr, uid, ids, context=context) - for task in tasks: - self.case_set(cr, uid, [task.id], 'cancelled', {'remaining_hours': 0.0}, context=context) - return True - - def do_open(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_open. """ - return self.case_open(cr, uid, ids, context=context) - - def case_open(self, cr, uid, ids, context=None): - if not isinstance(ids,list): ids = [ids] - return self.case_set(cr, uid, ids, 'open', {'date_start': fields.datetime.now()}, context=context) - - def do_draft(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_draft. """ - return self.case_draft(cr, uid, ids, context=context) - - def case_draft(self, cr, uid, ids, context=None): - return self.case_set(cr, uid, ids, 'draft', {}, context=context) - - def do_pending(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_pending. """ - return self.case_pending(cr, uid, ids, context=context) - - def case_pending(self, cr, uid, ids, context=None): - return self.case_set(cr, uid, ids, 'pending', {}, context=context) - 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) @@ -1044,6 +969,7 @@ class task(base_stage, osv.osv): 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, + 'stage_id': delegate_data.get('stage_id', [False])[0], 'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False, 'planned_hours': delegate_data['planned_hours'] or 0.0, 'parent_ids': [(6, 0, [task.id])], @@ -1058,16 +984,13 @@ class task(base_stage, osv.osv): 'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0), 'name': newname, }, context=context) - if delegate_data['state'] == 'pending': - self.do_pending(cr, uid, [task.id], context=context) - elif delegate_data['state'] == 'done': - self.do_close(cr, uid, [task.id], context=context) delegated_tasks[task.id] = delegated_task_id return delegated_tasks 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): + # TDE CHECK: was (task.state=='draft') + if (task.stage_id and task.stage_id.sequence == 1) 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 @@ -1102,50 +1025,57 @@ class task(base_stage, osv.osv): 'planned_hours': task.planned_hours, 'kanban_state': task.kanban_state, 'type_id': task.stage_id.id, - 'state': task.state, 'user_id': task.user_id.id }, context=context) return True + # ------------------------------------------------ + # CRUD overrides + # ------------------------------------------------ + def create(self, cr, uid, vals, context=None): if context is None: context = {} + # user_id change: update date_start + if vals.get('user_id'): + vals['date_start'] = fields.datetime.now() + # generate a default stage based on context / given project value if not vals.get('stage_id'): ctx = context.copy() if vals.get('project_id'): ctx['default_project_id'] = vals['project_id'] vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx) + # context: no_log, because subtype already handle this create_context = dict(context, mail_create_nolog=True) task_id = super(task, self).create(cr, uid, vals, context=create_context) self._store_history(cr, uid, [task_id], context=context) return task_id - # Overridden to reset the kanban_state to normal whenever - # the stage (stage_id) of the task changes. def write(self, cr, uid, ids, vals, context=None): if isinstance(ids, (int, long)): ids = [ids] - if vals.get('project_id'): - project_id = self.pool.get('project.project').browse(cr, uid, vals.get('project_id'), context=context) - if project_id: - vals.setdefault('message_follower_ids', []) - vals['message_follower_ids'] += [(6, 0,[follower.id]) for follower in project_id.message_follower_ids] + # stage change: update date_last_stage_update + if 'stage_id' in vals: + vals['date_last_stage_update'] = fields.datetime.now() + # user_id change: update date_start + if vals.get('user_id'): + vals['date_start'] = fields.datetime.now() + + # Overridden to reset the kanban_state to normal whenever + # the stage (stage_id) of the task changes. if vals and not 'kanban_state' in vals and 'stage_id' in vals: new_stage = vals.get('stage_id') vals_reset_kstate = dict(vals, kanban_state='normal') for t in self.browse(cr, uid, ids, context=context): - #TO FIX:Kanban view doesn't raise warning - #stages = [stage.id for stage in t.project_id.type_ids] - #if new_stage not in stages: - #raise osv.except_osv(_('Warning!'), _('Stage is not defined in the project.')) write_vals = vals_reset_kstate if t.stage_id != new_stage else vals super(task, self).write(cr, uid, [t.id], write_vals, context=context) result = True else: result = super(task, self).write(cr, uid, ids, vals, context=context) - if ('stage_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals): + + if any(item in vals for item in ['stage_id', 'remaining_hours', 'user_id', 'kanban_state']): self._store_history(cr, uid, ids, context=context) return result @@ -1161,7 +1091,8 @@ class task(base_stage, osv.osv): result = "" ident = ' '*ident for task in tasks: - if task.state in ('done','cancelled'): + # TDE CHECK: if task.state in ('done','cancelled'): + if task.stage_id and task.stage_id.fold: continue result += ''' %sdef Task_%s(): @@ -1231,13 +1162,14 @@ class task(base_stage, osv.osv): update_vals[field] = float(res.group(2).lower()) except (ValueError, TypeError): pass - elif match.lower() == 'state' \ - and res.group(2).lower() in ['cancel','close','draft','open','pending']: - act = 'do_%s' % res.group(2).lower() + # elif match.lower() == 'state' \ + # and res.group(2).lower() in ['cancel','close','draft','open','pending']: + # act = 'do_%s' % res.group(2).lower() if act: getattr(self,act)(cr, uid, ids, context=context) return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) + # TDE NOTE: FIXME def project_task_reevaluate(self, cr, uid, ids, context=None): if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'): return { diff --git a/addons/project/project_data.xml b/addons/project/project_data.xml index 7bf1a623a2c..0f48dfe9a2b 100644 --- a/addons/project/project_data.xml +++ b/addons/project/project_data.xml @@ -30,51 +30,43 @@ <record id="project_tt_analysis" model="project.task.type"> <field name="sequence">1</field> <field name="name">Analysis</field> - <field name="state">draft</field> - <field name="case_default" eval="False"/> + <field name="case_default" eval="True"/> </record> <record id="project_tt_specification" model="project.task.type"> - <field name="sequence">2</field> + <field name="sequence">10</field> <field name="name">Specification</field> - <field name="state">pending</field> <field name="case_default" eval="True"/> </record> <record id="project_tt_design" model="project.task.type"> - <field name="sequence">2</field> + <field name="sequence">11</field> <field name="name">Design</field> - <field name="state">open</field> <field name="case_default" eval="True"/> </record> <record id="project_tt_development" model="project.task.type"> - <field name="sequence">3</field> + <field name="sequence">12</field> <field name="name">Development</field> - <field name="state">open</field> <field name="case_default" eval="True"/> </record> <record id="project_tt_testing" model="project.task.type"> - <field name="sequence">4</field> + <field name="sequence">13</field> <field name="name">Testing</field> - <field name="state">open</field> <field name="case_default" eval="True"/> </record> <record id="project_tt_merge" model="project.task.type"> - <field name="sequence">5</field> + <field name="sequence">14</field> <field name="name">Merge</field> - <field name="state">open</field> <field name="case_default" eval="False"/> <field name="fold" eval="True"/> </record> <record id="project_tt_deployment" model="project.task.type"> - <field name="sequence">100</field> + <field name="sequence">20</field> <field name="name">Done</field> - <field name="state">done</field> <field name="case_default" eval="True"/> <field name="fold" eval="True"/> </record> <record id="project_tt_cancel" model="project.task.type"> - <field name="sequence">200</field> + <field name="sequence">30</field> <field name="name">Cancelled</field> - <field name="state">cancelled</field> <field name="case_default" eval="True"/> <field name="fold" eval="True"/> </record> @@ -86,11 +78,11 @@ <field name="default" eval="False"/> <field name="description">Task created</field> </record> - <record id="mt_task_started" model="mail.message.subtype"> - <field name="name">Task Started</field> + <record id="mt_task_assigned" model="mail.message.subtype"> + <field name="name">Task Assigned</field> <field name="res_model">project.task</field> <field name="default" eval="False"/> - <field name="description">Task started</field> + <field name="description">Task Assigned</field> </record> <record id="mt_task_blocked" model="mail.message.subtype"> <field name="name">Task Blocked</field> @@ -98,12 +90,6 @@ <field name="default" eval="False"/> <field name="description">Task blocked</field> </record> - <record id="mt_task_closed" model="mail.message.subtype"> - <field name="name">Task Done</field> - <field name="res_model">project.task</field> - <field name="default" eval="False"/> - <field name="description">Task closed</field> - </record> <record id="mt_task_stage" model="mail.message.subtype"> <field name="name">Stage Changed</field> <field name="res_model">project.task</field> @@ -118,11 +104,11 @@ <field name="parent_id" eval="ref('mt_task_new')"/> <field name="relation_field">project_id</field> </record> - <record id="mt_project_task_started" model="mail.message.subtype"> - <field name="name">Task Started</field> + <record id="mt_project_task_assigned" model="mail.message.subtype"> + <field name="name">Task Assigned</field> <field name="res_model">project.project</field> <field name="default" eval="False"/> - <field name="parent_id" eval="ref('mt_task_started')"/> + <field name="parent_id" eval="ref('mt_task_assigned')"/> <field name="relation_field">project_id</field> </record> <record id="mt_project_task_blocked" model="mail.message.subtype"> @@ -131,12 +117,6 @@ <field name="parent_id" eval="ref('mt_task_blocked')"/> <field name="relation_field">project_id</field> </record> - <record id="mt_project_task_closed" model="mail.message.subtype"> - <field name="name">Task Done</field> - <field name="res_model">project.project</field> - <field name="parent_id" eval="ref('mt_task_closed')"/> - <field name="relation_field">project_id</field> - </record> <record id="mt_project_task_stage" model="mail.message.subtype"> <field name="name">Task Stage Changed</field> <field name="res_model">project.project</field> diff --git a/addons/project/project_demo.xml b/addons/project/project_demo.xml index b7e1524c2c8..b53c3bb359f 100644 --- a/addons/project/project_demo.xml +++ b/addons/project/project_demo.xml @@ -225,7 +225,7 @@ ref('project.project_category_04')])]"/> <field name="stage_id" ref="project_tt_merge"/> </record> - <function model="project.task" name="do_close" eval="[ref('project_task_11')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_close" eval="[ref('project_task_11')], {'install_mode': True}"/> --> <record id="project_task_12" model="project.task"> <field name="planned_hours" eval="40.0"/> @@ -237,7 +237,7 @@ <field name="stage_id" ref="project_tt_merge"/> <field name="color">6</field> </record> - <function model="project.task" name="do_close" eval="[ref('project_task_12')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_close" eval="[ref('project_task_12')], {'install_mode': True}"/> --> <record id="project_task_13" model="project.task"> <field name="planned_hours" eval="12.0"/> @@ -248,7 +248,7 @@ <field name="name">Design Use Cases</field> <field name="stage_id" ref="project_tt_analysis"/> </record> - <function model="project.task" name="do_pending" eval="[ref('project_task_13')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_pending" eval="[ref('project_task_13')], {'install_mode': True}"/> --> <record id="project_task_14" model="project.task"> <field name="planned_hours" eval="12.0"/> @@ -282,7 +282,7 @@ <field name="name">Set target for all deparments</field> <field name="stage_id" ref="project_tt_development"/> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_16')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_16')], {'install_mode': True}"/> --> <record id="project_task_17" model="project.task"> <field name="planned_hours" eval="34.0"/> @@ -293,7 +293,7 @@ <field name="name">Integration of core components</field> <field name="stage_id" ref="project_tt_testing"/> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_17')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_17')], {'install_mode': True}"/> --> <record id="project_task_18" model="project.task"> <field name="planned_hours" eval="16.0"/> @@ -315,7 +315,7 @@ <field name="categ_ids" eval="[(6, 0, [ ref('project_category_03')])]"/> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_19')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_19')], {'install_mode': True}"/> --> <record id="project_task_20" model="project.task"> <field name="planned_hours">42.0</field> @@ -325,7 +325,7 @@ <field name="project_id" ref="project.project_project_4"/> <field name="name">Create new components</field> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_20')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_20')], {'install_mode': True}"/> --> <record id="project_task_21" model="project.task"> <field name="planned_hours">14.0</field> @@ -337,7 +337,7 @@ <field name="categ_ids" eval="[(6, 0, [ ref('project_category_04')])]"/> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_21')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_21')], {'install_mode': True}"/> --> <record id="project_task_22" model="project.task"> <field name="planned_hours">12.0</field> @@ -371,7 +371,7 @@ <field name="categ_ids" eval="[(6, 0, [ ref('project_category_01')])]"/> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_24')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_24')], {'install_mode': True}"/> --> <record id="project_task_25" model="project.task"> <field name="sequence">20</field> @@ -382,7 +382,7 @@ <field name="name">Data importation + Doc</field> <field name="stage_id" ref="project_tt_development"/> </record> - <function model="project.task" name="do_open" eval="[ref('project_task_25')], {'install_mode': True}"/> + <!-- <function model="project.task" name="do_open" eval="[ref('project_task_25')], {'install_mode': True}"/> --> <record id="project_task_26" model="project.task"> <field name="sequence">20</field> diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 33842a9a19c..8eafacd3bc0 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -18,23 +18,20 @@ <search string="Tasks"> <field name="name" string="Tasks"/> <field name="categ_ids"/> + <field name="partner_id"/> + <field name="project_id"/> + <field name="user_id"/> + <filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/> + <filter string="New" name="draft" domain="[('stage_id.sequence', '=', 1)]"/> <separator/> - <filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/> - <separator/> - <filter name="draft" string="New" domain="[('state','=','draft')]" help="New Tasks" icon="terp-check"/> - <filter name="open" string="In Progress" domain="[('state','=','open')]" help="In Progress Tasks" icon="terp-camera_test"/> - <filter string="Pending" domain="[('state','=','pending')]" context="{'show_delegated':False}" help="Pending Tasks" icon="terp-gtk-media-pause"/> + <filter name="My project" string="Project" domain="[('project_id.user_id','=',uid)]"/> <separator/> - <filter name="My project" string="Project" domain="[('project_id.user_id','=',uid)]" help="My Projects" icon="terp-check"/> + <filter string="My Tasks" domain="[('user_id','=',uid)]"/> <separator/> - <filter string="My Tasks" domain="[('user_id','=',uid)]" help="My Tasks" icon="terp-personal"/> - <filter string="Unassigned Tasks" domain="[('user_id','=',False)]" help="Unassigned Tasks" icon="terp-personal-"/> + <filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/> <separator/> <filter string="Deadlines" context="{'deadline_visible': False}" domain="[('date_deadline','<>',False)]" - help="Show only tasks having a deadline" icon="terp-gnome-cpu-frequency-applet+"/> - <field name="partner_id"/> - <field name="project_id"/> - <field name="user_id"/> + help="Show only tasks having a deadline"/> <group expand="0" string="Group By..."> <filter string="Users" name="group_user_id" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/> <filter string="Project" name="group_project_id" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/> @@ -371,18 +368,6 @@ <field name="arch" type="xml"> <form string="Project" version="7.0"> <header> - <!-- - <button name="do_open" string="Start Task" type="object" - states="draft,pending" class="oe_highlight"/> - <button name="do_draft" string="Draft" type="object" - states="cancel,done"/> - --> - <button name="project_task_reevaluate" string="Reactivate" type="object" - states="cancelled,done" context="{'button_reactivate':True}" groups="base.group_user"/> - <button name="action_close" string="Done" type="object" - states="draft,open,pending" groups="base.group_user"/> - <button name="do_cancel" string="Cancel Task" type="object" - states="draft,open,pending" groups="base.group_user"/> <field name="stage_id" widget="statusbar" clickable="True"/> </header> <sheet string="Task"> @@ -396,8 +381,7 @@ <group> <group> <field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/> - <field name="user_id" - attrs="{'readonly':[('state','in',['done', 'cancelled'])]}" + <field name="user_id" options='{"no_open": True}' context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/> <field name="planned_hours" widget="float_time" @@ -405,15 +389,15 @@ on_change="onchange_planned(planned_hours, effective_hours)"/> </group> <group> - <field name="date_deadline" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/> + <field name="date_deadline"/> <field name="categ_ids" widget="many2many_tags"/> <field name="progress" widget="progressbar" - groups="project.group_time_work_estimation_tasks" attrs="{'invisible':[('state','=','cancelled')]}"/> + groups="project.group_time_work_estimation_tasks"/> </group> </group> <notebook> <page string="Description"> - <field name="description" attrs="{'readonly':[('state','=','done')]}" placeholder="Add a Description..."/> + <field name="description" placeholder="Add a Description..."/> <field name="work_ids" groups="project.group_tasks_work_on_tasks"> <tree string="Task Work" editable="top"> <field name="name"/> @@ -427,7 +411,7 @@ <field name="effective_hours" widget="float_time"/> <label for="remaining_hours" string="Remaining" groups="project.group_time_work_estimation_tasks"/> <div> - <field name="remaining_hours" widget="float_time" attrs="{'readonly':[('state','in',('done','cancelled'))]}" groups="project.group_time_work_estimation_tasks"/> + <field name="remaining_hours" widget="float_time" groups="project.group_time_work_estimation_tasks"/> </div> <field name="total_hours" widget="float_time" class="oe_subtotal_footer_separator"/> </group> @@ -436,7 +420,7 @@ </page> <page string="Delegation" groups="project.group_delegate_task"> <button name="%(action_project_task_delegate)d" string="Delegate" type="action" - states="pending,open,draft" groups="project.group_delegate_task"/> + groups="project.group_delegate_task"/> <separator string="Parent Tasks"/> <field name="parent_ids"/> <separator string="Delegated tasks"/> @@ -445,7 +429,6 @@ <field name="name"/> <field name="user_id"/> <field name="stage_id"/> - <field name="state" invisible="1"/> <field name="effective_hours" widget="float_time"/> <field name="progress" widget="progressbar"/> <field name="remaining_hours" widget="float_time"/> @@ -453,12 +436,11 @@ </tree> </field> </page> - <page string="Extra Info" attrs="{'readonly':[('state','=','done')]}"> + <page string="Extra Info"> <group col="4"> <field name="priority" groups="base.group_user"/> <field name="sequence"/> <field name="partner_id"/> - <field name="state" invisible="1"/> <field name="company_id" groups="base.group_multi_company" widget="selection"/> </group> <group> @@ -467,6 +449,7 @@ <field name="date_end"/> </group> <group> + <field name="date_last_stage_update" groups="base.group_no_one"/> </group> </group> </page> @@ -493,7 +476,6 @@ <field name="user_email"/> <field name="description"/> <field name="sequence"/> - <field name="state" groups="base.group_no_one"/> <field name="kanban_state"/> <field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/> <field name="date_deadline"/> @@ -513,7 +495,7 @@ <li><a name="set_remaining_time_2" type="object" class="oe_kanban_button">2</a></li> <li><a name="set_remaining_time_5" type="object" class="oe_kanban_button">5</a></li> <li><a name="set_remaining_time_10" type="object" class="oe_kanban_button">10</a></li> - <li><a name="do_open" states="draft" string="Validate planned time" type="object" class="oe_kanban_button oe_kanban_button_active">!</a></li> + <!-- <li><a name="do_open" states="draft" string="Validate planned time" type="object" class="oe_kanban_button oe_kanban_button_active">!</a></li> --> </ul> </li> <br/> @@ -562,7 +544,7 @@ <field name="model">project.task</field> <field eval="2" name="priority"/> <field name="arch" type="xml"> - <tree fonts="bold:message_unread==True" colors="grey:state in ('cancelled','done');blue:state == 'pending';red:date_deadline and (date_deadline<current_date) and (state in ('draft','pending','open'))" string="Tasks"> + <tree fonts="bold:message_unread==True" colors="red:date_deadline and (date_deadline<current_date)" string="Tasks"> <field name="message_unread" invisible="1"/> <field name="sequence" invisible="not context.get('seq_visible', False)"/> <field name="name"/> @@ -575,7 +557,6 @@ <field name="remaining_hours" widget="float_time" sum="Remaining Hours" on_change="onchange_remaining(remaining_hours,planned_hours)" invisible="context.get('set_visible',False)" groups="project.group_time_work_estimation_tasks"/> <field name="date_deadline" invisible="context.get('deadline_visible',True)"/> <field name="stage_id" invisible="context.get('set_visible',False)"/> - <field name="state" invisible="1"/> <field name="date_start" groups="base.group_no_one"/> <field name="date_end" groups="base.group_no_one"/> <field name="progress" widget="progressbar" invisible="context.get('set_visible',False)"/> @@ -706,7 +687,6 @@ <field name="case_default"/> </group> <group> - <field name="state"/> <field name="sequence"/> <field name="fold"/> </group> @@ -723,7 +703,7 @@ <tree string="Task Stage"> <field name="sequence" widget="handle"/> <field name="name"/> - <field name="state"/> + <field name="fold"/> </tree> </field> </record> diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py index 006aae1085c..a14ca10dfce 100644 --- a/addons/project/report/project_report.py +++ b/addons/project/report/project_report.py @@ -19,7 +19,7 @@ # ############################################################################## -from openerp.osv import fields,osv +from openerp.osv import fields, osv from openerp import tools class report_project_task_user(osv.osv): @@ -31,10 +31,12 @@ class report_project_task_user(osv.osv): 'day': fields.char('Day', size=128, readonly=True), 'year': fields.char('Year', size=64, required=False, readonly=True), 'user_id': fields.many2one('res.users', 'Assigned To', readonly=True), - 'date_start': fields.date('Starting Date',readonly=True), + 'date_start': fields.date('Assignation Date', readonly=True), 'no_of_days': fields.integer('# of Days', size=128, readonly=True), 'date_end': fields.date('Ending Date', readonly=True), 'date_deadline': fields.date('Deadline', readonly=True), + 'date_last_stage_update': fields.date('Last Stage Update', readonly=True), + 'month_last_stage_update': fields.date('Month of Last Stage Update', readonly=True), 'project_id': fields.many2one('project.project', 'Project', readonly=True), 'hours_planned': fields.float('Planned Hours', readonly=True), 'hours_effective': fields.float('Effective Hours', readonly=True), @@ -44,16 +46,17 @@ class report_project_task_user(osv.osv): 'total_hours': fields.float('Total Hours', readonly=True), 'closing_days': fields.float('Days to Close', digits=(16,2), readonly=True, group_operator="avg", help="Number of Days to close the task"), - 'opening_days': fields.float('Days to Open', digits=(16,2), readonly=True, group_operator="avg", + 'opening_days': fields.float('Days to Assign', digits=(16,2), readonly=True, group_operator="avg", help="Number of Days to Open the task"), 'delay_endings_days': fields.float('Overpassed Deadline', digits=(16,2), readonly=True), 'nbr': fields.integer('# of tasks', readonly=True), - 'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), -('0','Very urgent')], 'Priority', readonly=True), + 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), ('1', 'Urgent'), ('0', 'Very urgent')], + string='Priority', readonly=True), 'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True), 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'partner_id': fields.many2one('res.partner', 'Contact', readonly=True), + 'stage_id': fields.many2one('project.task.type', 'Stage'), } _order = 'name desc, project_id' @@ -69,19 +72,20 @@ class report_project_task_user(osv.osv): to_char(date_start, 'YYYY-MM-DD') as day, date_trunc('day',t.date_start) as date_start, date_trunc('day',t.date_end) as date_end, + date_trunc('day',t.date_last_stage_update) as date_last_stage_update, + to_char(date_last_stage_update, 'MM') as month_last_stage_update, to_date(to_char(t.date_deadline, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_deadline, -- sum(cast(to_char(date_trunc('day',t.date_end) - date_trunc('day',t.date_start),'DD') as int)) as no_of_days, abs((extract('epoch' from (t.date_end-t.date_start)))/(3600*24)) as no_of_days, t.user_id, progress as progress, t.project_id, - t.state, t.effective_hours as hours_effective, t.priority, t.name as name, t.company_id, t.partner_id, - t.stage_id, + t.stage_id as stage_id, remaining_hours as remaining_hours, total_hours as total_hours, t.delay_hours as hours_delay, @@ -106,15 +110,13 @@ class report_project_task_user(osv.osv): date_start, date_end, date_deadline, + date_last_stage_update, + month_last_stage_update, t.user_id, t.project_id, - t.state, t.priority, name, t.company_id, t.partner_id, - t.stage_id - + stage_id """) - - diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml index d9650e165ce..38107ab9bcf 100644 --- a/addons/project/report/project_report_view.xml +++ b/addons/project/report/project_report_view.xml @@ -15,9 +15,10 @@ <field name="project_id" invisible="1"/> <field name="user_id" invisible="1"/> <field name="date_deadline" invisible="1"/> - <field name="state" invisible="1"/> <field name="date_start" invisible="1"/> <field name="date_end" invisible="1"/> + <field name="date_last_stage_update" invisible="1"/> + <field name="month_last_stage_update" invisible="1"/> <field name="company_id" invisible="1" groups="base.group_multi_company"/> <field name="partner_id" invisible="1"/> <field name="day" invisible="1"/> @@ -44,7 +45,7 @@ <field name="arch" type="xml"> <graph string="Tasks Analysis" type="bar"> <field name="name"/> - <field name="state" group="True"/> + <field name="stage_id" group="True"/> <field name="no_of_days" operator="+"/> </graph> </field> @@ -58,31 +59,32 @@ <field name="date_start"/> <field name="date_end"/> <field name="date_deadline"/> - <filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help = "New tasks"/> - <filter string="In progress" icon="terp-check" domain="[('state', '=' ,'open')]" help = "In progress tasks"/> - <filter string="Pending" icon="terp-gtk-media-pause" domain="[('state','=','pending')]" help = "Pending tasks"/> - <filter string="Done" icon="terp-dialog-close" name="done" domain="[('state','=','done')]"/> - <separator/> - <filter icon="terp-folder-violet" string="My Projects" help="My Projects" domain="[('project_id.user_id','=',uid)]"/> - <separator/> - <filter icon="terp-personal" string="My Task" help = "My tasks" domain="[('user_id','=',uid)]" /> - <filter icon="terp-personal-" string="Non Assigned Tasks to users" help="Non Assigned Tasks to users" domain="[('user_id','=',False)]"/> + <field name="date_last_stage_update"/> <field name="project_id"/> <field name="user_id"/> <field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/> + <filter string="Unassigned" name="unassigned" domain="[('user_id','=',False)]"/> + <filter string="New" name="new" domain="[('stage_id.sequence', '=', 1)]"/> + <filter string="Done" name="done" domain="[('stage_id.fold', '=', True)]" + help="Tasks beloging to a folded stage"/> + <separator/> + <filter string="My Projects" domain="[('project_id.user_id','=',uid)]"/> + <separator/> + <filter string="My Task" domain="[('user_id','=',uid)]" /> <group expand="0" string="Extended Filters..."> <field name="priority"/> <field name="company_id" groups="base.group_multi_company"/> </group> <group expand="1" string="Group By..."> - <filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}"/> - <filter string="Task" icon="terp-stock_align_left_24" context="{'group_by':'name'}" /> - <filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" /> - <filter string="Assigned to" name="User" icon="terp-personal" context="{'group_by':'user_id'}" /> - <filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/> - <filter string="Day" icon="terp-go-today" context="{'group_by':'day'}" help="Creation Date"/> - <filter string="Month" icon="terp-go-month" context="{'group_by':'month'}" help="Creation Date"/> - <filter string="Year" icon="terp-go-year" context="{'group_by':'year'}" help="Creation Date"/> + <filter string="Project" name="project" context="{'group_by':'project_id'}"/> + <filter string="Task" context="{'group_by':'name'}" /> + <filter string="Contact" context="{'group_by':'partner_id'}" /> + <filter string="Assigned to" name="User" context="{'group_by':'user_id'}" /> + <filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/> + <filter string="Day" context="{'group_by':'day'}" help="Creation Date"/> + <filter string="Month" context="{'group_by':'month'}" help="Creation Date"/> + <filter string="Year" context="{'group_by':'year'}" help="Creation Date"/> + <filter string="Last Stage Update" context="{'group_by':'month_last_stage_update'}" help="Month of Last Stage Update"/> </group> </search> </field> diff --git a/addons/project/test/task_process.yml b/addons/project/test/task_process.yml index e37b2116714..471642610a1 100644 --- a/addons/project/test/task_process.yml +++ b/addons/project/test/task_process.yml @@ -1,14 +1,5 @@ - - I put task in pending due to specification is not clear. -- - !python {model: project.task}: | - self.do_pending(cr, uid, [ref("project_task_1")]) - context.update({"active_id": ref("project_task_1")}) -- - I check state of task after put in pending. -- - !assert {model: project.task, id: project_task_1, severity: error, string: task should be in pending state}: - - state == "pending" + I open a delegation wizard. - !record {model: project.task.delegate, id: delegate_id}: user_id: base.user_demo diff --git a/addons/project/wizard/__init__.py b/addons/project/wizard/__init__.py index 7a9a734b2bd..24017d9cbe8 100644 --- a/addons/project/wizard/__init__.py +++ b/addons/project/wizard/__init__.py @@ -20,7 +20,5 @@ ############################################################################## import project_task_delegate -import project_task_reevaluate # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/addons/project/wizard/project_task_reevaluate.py b/addons/project/wizard/project_task_reevaluate.py deleted file mode 100644 index eeb8cccc5d2..00000000000 --- a/addons/project/wizard/project_task_reevaluate.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). -# -# 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 <http://www.gnu.org/licenses/>. -# -############################################################################## - -from lxml import etree -from openerp.osv import fields, osv -from openerp.tools.translate import _ - -class project_task_reevaluate(osv.osv_memory): - _name = 'project.task.reevaluate' - - def _get_remaining(self, cr, uid, context=None): - if context is None: - context = {} - active_id = context.get('active_id', False) - res = False - if active_id: - res = self.pool.get('project.task').browse(cr, uid, active_id, context=context).remaining_hours - return res - - _columns = { - 'remaining_hours' : fields.float('Remaining Hours', digits=(16,2), help="Put here the remaining hours required to close the task."), - } - - _defaults = { - 'remaining_hours': _get_remaining, - } - - def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): - res = super(project_task_reevaluate, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu=submenu) - users_pool = self.pool.get('res.users') - time_mode = users_pool.browse(cr, uid, uid, context).company_id.project_time_mode_id - time_mode_name = time_mode and time_mode.name or 'Hours' - if time_mode_name in ['Hours','Hour']: - return res - - eview = etree.fromstring(res['arch']) - - def _check_rec(eview): - if eview.attrib.get('widget','') == 'float_time': - eview.set('widget','float') - for child in eview: - _check_rec(child) - return True - - _check_rec(eview) - - res['arch'] = etree.tostring(eview) - - for field in res['fields']: - if 'Hours' in res['fields'][field]['string']: - res['fields'][field]['string'] = res['fields'][field]['string'].replace('Hours',time_mode_name) - return res - - def compute_hours(self, cr, uid, ids, context=None): - if context is None: - context = {} - data = self.browse(cr, uid, ids, context=context)[0] - task_id = context.get('active_id') - if task_id: - task_pool = self.pool.get('project.task') - task_pool.write(cr, uid, task_id, {'remaining_hours': data.remaining_hours}) - if context.get('button_reactivate'): - task_pool.do_reopen(cr, uid, [task_id], context=context) - return {'type': 'ir.actions.act_window_close'} - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/project/wizard/project_task_reevaluate_view.xml b/addons/project/wizard/project_task_reevaluate_view.xml deleted file mode 100644 index 6dfe58e8cfd..00000000000 --- a/addons/project/wizard/project_task_reevaluate_view.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<openerp> - <data> - - <record id="view_project_task_reevaluate" model="ir.ui.view"> - <field name="name">Re-evaluate Task</field> - <field name="model">project.task.reevaluate</field> - <field name="arch" type="xml"> - <form string="Reevaluate Task" version="7.0"> - <separator string="Reevaluation Task"/> - <group> - <field name="remaining_hours" widget="float_time"/> - </group> - <footer> - <button name="compute_hours" string="_Evaluate" type="object" default_focus="1" class="oe_highlight"/> - or - <button string="Cancel" class="oe_link" special="cancel" /> - </footer> - </form> - </field> - </record> - - <record id="action_project_task_reevaluate" model="ir.actions.act_window"> - <field name="name">Re-evaluate Task</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">project.task.reevaluate</field> - <field name="view_type">form</field> - <field name="view_mode">form</field> - <field name="target">new</field> - </record> - </data> -</openerp> diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 33e4fcb409c..4c89c4def60 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -21,7 +21,6 @@ from openerp import SUPERUSER_ID from openerp.addons.base_status.base_stage import base_stage -from openerp.addons.project.project import _TASK_STATE from openerp.addons.crm import crm from datetime import datetime from openerp.osv import fields, osv, orm @@ -247,13 +246,6 @@ class project_issue(base_stage, osv.osv): 'partner_id': fields.many2one('res.partner', 'Contact', select=1), 'company_id': fields.many2one('res.company', 'Company'), 'description': fields.text('Private Note'), - 'state': fields.related('stage_id', 'state', type="selection", store=True, - selection=_TASK_STATE, string="Status", readonly=True, - help='The status is set to \'Draft\', when a case is created.\ - If the case is in progress the status is set to \'Open\'.\ - When the case is over, the status is set to \'Done\'.\ - If the case needs to be reviewed then the status is \ - set to \'Pending\'.'), 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State', track_visibility='onchange', help="A Issue's kanban state indicates special situations affecting it:\n" |
