summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorThibault Delavallée <tde@openerp.com>2013-06-26 15:25:19 +0200
committerThibault Delavallée <tde@openerp.com>2013-06-26 15:25:19 +0200
commit8fbfc997aebb788d79200e711389817e9ce719df (patch)
tree6ac20665ef2dd12230676cb0fc9ac675ae7d931f /addons
parentc180afab26171617c1c7c22db5d9836b159e5e7d (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.py13
-rw-r--r--addons/project/__openerp__.py2
-rw-r--r--addons/project/board_project_view.xml3
-rw-r--r--addons/project/project.py214
-rw-r--r--addons/project/project_data.xml48
-rw-r--r--addons/project/project_demo.xml20
-rw-r--r--addons/project/project_view.xml60
-rw-r--r--addons/project/report/project_report.py26
-rw-r--r--addons/project/report/project_report_view.xml40
-rw-r--r--addons/project/test/task_process.yml11
-rw-r--r--addons/project/wizard/__init__.py2
-rw-r--r--addons/project/wizard/project_task_reevaluate.py84
-rw-r--r--addons/project/wizard/project_task_reevaluate_view.xml32
-rw-r--r--addons/project_issue/project_issue.py8
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','&lt;&gt;',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&lt;current_date) and (state in ('draft','pending','open'))" string="Tasks">
+ <tree fonts="bold:message_unread==True" colors="red:date_deadline and (date_deadline&lt;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"