[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
This commit is contained in:
Thibault Delavallée 2013-06-26 15:25:19 +02:00
parent c180afab26
commit 8fbfc997ae
14 changed files with 164 additions and 403 deletions

View File

@ -328,8 +328,8 @@ class mail_thread(osv.AbstractModel):
# Track initial values of tracked fields # Track initial values of tracked fields
tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context) tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context)
if tracked_fields: if tracked_fields:
initial = self.read(cr, uid, ids, tracked_fields.keys(), context=context) records = self.browse(cr, uid, ids, context=context)
initial_values = dict((item['id'], item) for item in initial) initial_values = dict((this.id, dict((key, getattr(this, key)) for key in tracked_fields.keys())) for this in records)
# Perform write, update followers # Perform write, update followers
result = super(mail_thread, self).write(cr, uid, ids, values, context=context) result = super(mail_thread, self).write(cr, uid, ids, values, context=context)
@ -388,7 +388,8 @@ class mail_thread(osv.AbstractModel):
if not value: if not value:
return '' return ''
if col_info['type'] == 'many2one': if col_info['type'] == 'many2one':
return value[1] # return value[1]
return value.name_get()[0][1]
if col_info['type'] == 'selection': if col_info['type'] == 'selection':
return dict(col_info['selection'])[value] return dict(col_info['selection'])[value]
return value return value
@ -407,7 +408,9 @@ class mail_thread(osv.AbstractModel):
if not tracked_fields: if not tracked_fields:
return True 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']] initial = initial_values[record['id']]
changes = [] changes = []
tracked_values = {} tracked_values = {}
@ -433,7 +436,7 @@ class mail_thread(osv.AbstractModel):
if field not in changes: if field not in changes:
continue continue
for subtype, method in track_info.items(): 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) subtypes.append(subtype)
posted = False posted = False

View File

@ -40,7 +40,6 @@
], ],
'depends': [ 'depends': [
'base_setup', 'base_setup',
'base_status',
'product', 'product',
'analytic', 'analytic',
'board', 'board',
@ -66,7 +65,6 @@ Dashboard / Reports for Project Management will include:
'data': [ 'data': [
'security/project_security.xml', 'security/project_security.xml',
'wizard/project_task_delegate_view.xml', 'wizard/project_task_delegate_view.xml',
'wizard/project_task_reevaluate_view.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'project_data.xml', 'project_data.xml',
'project_view.xml', 'project_view.xml',

View File

@ -16,7 +16,6 @@
<field name="effective_hours" widget="float_time"/> <field name="effective_hours" widget="float_time"/>
<field name="progress" widget="progressbar"/> <field name="progress" widget="progressbar"/>
<field name="stage_id" invisible="context.get('set_visible',False)"/> <field name="stage_id" invisible="context.get('set_visible',False)"/>
<field name="state" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -26,7 +25,7 @@
<field name="res_model">project.task</field> <field name="res_model">project.task</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,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"/> <field name="view_id" ref="view_task_tree"/>
</record> </record>

View File

@ -28,10 +28,8 @@ from openerp import tools
from openerp.osv import fields, osv from openerp.osv import fields, osv
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp.addons.base_status.base_stage import base_stage
from openerp.addons.resource.faces import task as Task 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): class project_task_type(osv.osv):
_name = 'project.task.type' _name = 'project.task.type'
@ -44,9 +42,6 @@ class project_task_type(osv.osv):
'case_default': fields.boolean('Default for New Projects', '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."), 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'), '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', '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."), 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 return proj
_defaults = { _defaults = {
'sequence': 1, 'sequence': 1,
'state': 'open',
'fold': False, 'fold': False,
'case_default': False, 'case_default': False,
'project_ids': _get_default_project_id 'project_ids': _get_default_project_id
@ -152,11 +146,13 @@ class project(osv.osv):
cr.execute(""" cr.execute("""
SELECT project_id, COALESCE(SUM(planned_hours), 0.0), SELECT project_id, COALESCE(SUM(planned_hours), 0.0),
COALESCE(SUM(total_hours), 0.0), COALESCE(SUM(effective_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 GROUP BY project_id
""", (tuple(child_parent.keys()),)) """, (tuple(child_parent.keys()),))
# aggregate results into res # 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(): for id, planned, total, effective in cr.fetchall():
# add the values specific to id to all parent projects of id in the result # add the values specific to id to all parent projects of id in the result
while id: 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.", '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 = { store = {
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), '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.", '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 = { store = {
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), '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.", '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 = { store = {
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), '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.", '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 = { store = {
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), '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)]} ), '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)]}), '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 return res
def set_done(self, cr, uid, ids, context=None): def set_done(self, cr, uid, ids, context=None):
task_obj = self.pool.get('project.task') return self.write(cr, uid, ids, {'state': 'close'}, context=context)
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)
def set_cancel(self, cr, uid, ids, context=None): def set_cancel(self, cr, uid, ids, context=None):
task_obj = self.pool.get('project.task') return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context)
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)
def set_pending(self, cr, uid, ids, context=None): 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): 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): def reset_project(self, cr, uid, ids, context=None):
return self.setActive(cr, uid, ids, value=True, context=context) 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): if project.user_id and (project.user_id.id not in u_ids):
u_ids.append(project.user_id.id) u_ids.append(project.user_id.id)
for task in project.tasks: 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 continue
if task.user_id and (task.user_id.id not in u_ids): if task.user_id and (task.user_id.id not in u_ids):
u_ids.append(task.user_id.id) u_ids.append(task.user_id.id)
@ -525,7 +516,8 @@ def Project():
for project in projects: for project in projects:
project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,)) project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,))
for task in project.tasks: 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 continue
p = getattr(project_gantt, 'Task_%d' % (task.id,)) p = getattr(project_gantt, 'Task_%d' % (task.id,))
@ -566,23 +558,20 @@ def Project():
vals.update(alias_model_id=model_ids[0]) vals.update(alias_model_id=model_ids[0])
return super(project, self).write(cr, uid, ids, vals, context=context) return super(project, self).write(cr, uid, ids, vals, context=context)
class task(base_stage, osv.osv):
class task(osv.osv):
_name = "project.task" _name = "project.task"
_description = "Task" _description = "Task"
_date_name = "date_start" _date_name = "date_start"
_inherit = ['mail.thread', 'ir.needaction_mixin'] _inherit = ['mail.thread', 'ir.needaction_mixin']
_track = { _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': { '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 '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): def _get_default_stage_id(self, cr, uid, context=None):
""" Gives default stage_id """ """ Gives default stage_id """
project_id = self._get_default_project_id(cr, uid, context=context) 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): def _resolve_project_id_from_context(self, cr, uid, context=None):
""" Returns ID of project based on the value of 'default_project_id' """ Returns ID of project based on the value of 'default_project_id'
context key, or None if it cannot be resolved to a single context key, or None if it cannot be resolved to a single
project. project.
""" """
if context is None: context = {} if context is None:
context = {}
if type(context.get('default_project_id')) in (int, long): if type(context.get('default_project_id')) in (int, long):
return context['default_project_id'] return context['default_project_id']
if isinstance(context.get('default_project_id'), basestring): if isinstance(context.get('default_project_id'), basestring):
@ -669,7 +659,8 @@ class task(base_stage, osv.osv):
res[task.id]['progress'] = 0.0 res[task.id]['progress'] = 0.0
if (task.remaining_hours + hours.get(task.id, 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) 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 res[task.id]['progress'] = 100.0
return res return res
@ -690,6 +681,13 @@ class task(base_stage, osv.osv):
return {'value':{'partner_id':partner_id.id}} return {'value':{'partner_id':partner_id.id}}
return {} 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): def duplicate_task(self, cr, uid, map_ids, context=None):
for new in map_ids.values(): for new in map_ids.values():
task = self.browse(cr, uid, new, context) 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."), '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), 'name': fields.char('Task Summary', size=128, required=True, select=True),
'description': fields.text('Description'), '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."), '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', 'stage_id': fields.many2one('project.task.type', 'Stage', track_visibility='onchange',
domain="[('project_ids', '=', project_id)]"), 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'), 'categ_ids': fields.many2many('project.category', string='Tags'),
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State', 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
track_visibility='onchange', track_visibility='onchange',
@ -766,6 +759,7 @@ class task(base_stage, osv.osv):
'date_start': fields.datetime('Starting Date',select=True), 'date_start': fields.datetime('Starting Date',select=True),
'date_end': fields.datetime('Ending Date',select=True), 'date_end': fields.datetime('Ending Date',select=True),
'date_deadline': fields.date('Deadline',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'), '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'), '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'), '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': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10),
'project.task.work': (_get_task, ['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 = { store = {
'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours','state'], 10), 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours','state'], 10),
'project.task.work': (_get_task, ['hours'], 10), 'project.task.work': (_get_task, ['hours'], 10),
@ -805,6 +799,7 @@ class task(base_stage, osv.osv):
_defaults = { _defaults = {
'stage_id': _get_default_stage_id, 'stage_id': _get_default_stage_id,
'project_id': _get_default_project_id, 'project_id': _get_default_project_id,
'date_last_stage_update': lambda *a: fields.datetime.now(),
'kanban_state': 'normal', 'kanban_state': 'normal',
'priority': '2', 'priority': '2',
'progress': 0, 'progress': 0,
@ -931,10 +926,11 @@ class task(base_stage, osv.osv):
section_ids.append(task.project_id.id) section_ids.append(task.project_id.id)
search_domain = [] search_domain = []
if section_ids: if section_ids:
search_domain = [('|')] * (len(section_ids)-1) search_domain = [('|')] * (len(section_ids) - 1)
for section_id in section_ids: for section_id in section_ids:
search_domain.append(('project_ids', '=', section_id)) search_domain.append(('project_ids', '=', section_id))
search_domain += list(domain) if domain:
search_domain += list(domain)
# perform search, return the first found # perform search, return the first found
stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context) stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
if stage_ids: if stage_ids:
@ -948,82 +944,11 @@ class task(base_stage, osv.osv):
for task in tasks: for task in tasks:
if task.child_ids: if task.child_ids:
for child in 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.")) raise osv.except_osv(_("Warning!"), _("Child task still open.\nPlease cancel or complete child task first."))
return True 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): def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None):
attachment = self.pool.get('ir.attachment') attachment = self.pool.get('ir.attachment')
attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', task_id)], context=context) 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, { delegated_task_id = self.copy(cr, uid, task.id, {
'name': delegate_data['name'], 'name': delegate_data['name'],
'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False, '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, 'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False,
'planned_hours': delegate_data['planned_hours'] or 0.0, 'planned_hours': delegate_data['planned_hours'] or 0.0,
'parent_ids': [(6, 0, [task.id])], '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), 'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0),
'name': newname, 'name': newname,
}, context=context) }, 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 delegated_tasks[task.id] = delegated_task_id
return delegated_tasks return delegated_tasks
def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None): def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None):
for task in self.browse(cr, uid, ids, context=context): 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, [task.id], {'planned_hours': remaining_time}, context=context)
self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context) self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context)
return True return True
@ -1102,50 +1025,57 @@ class task(base_stage, osv.osv):
'planned_hours': task.planned_hours, 'planned_hours': task.planned_hours,
'kanban_state': task.kanban_state, 'kanban_state': task.kanban_state,
'type_id': task.stage_id.id, 'type_id': task.stage_id.id,
'state': task.state,
'user_id': task.user_id.id 'user_id': task.user_id.id
}, context=context) }, context=context)
return True return True
# ------------------------------------------------
# CRUD overrides
# ------------------------------------------------
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
if context is None: if context is None:
context = {} 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'): if not vals.get('stage_id'):
ctx = context.copy() ctx = context.copy()
if vals.get('project_id'): if vals.get('project_id'):
ctx['default_project_id'] = vals['project_id'] ctx['default_project_id'] = vals['project_id']
vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx) vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
# context: no_log, because subtype already handle this # context: no_log, because subtype already handle this
create_context = dict(context, mail_create_nolog=True) create_context = dict(context, mail_create_nolog=True)
task_id = super(task, self).create(cr, uid, vals, context=create_context) task_id = super(task, self).create(cr, uid, vals, context=create_context)
self._store_history(cr, uid, [task_id], context=context) self._store_history(cr, uid, [task_id], context=context)
return task_id 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): def write(self, cr, uid, ids, vals, context=None):
if isinstance(ids, (int, long)): if isinstance(ids, (int, long)):
ids = [ids] ids = [ids]
if vals.get('project_id'): # stage change: update date_last_stage_update
project_id = self.pool.get('project.project').browse(cr, uid, vals.get('project_id'), context=context) if 'stage_id' in vals:
if project_id: vals['date_last_stage_update'] = fields.datetime.now()
vals.setdefault('message_follower_ids', []) # user_id change: update date_start
vals['message_follower_ids'] += [(6, 0,[follower.id]) for follower in project_id.message_follower_ids] 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: if vals and not 'kanban_state' in vals and 'stage_id' in vals:
new_stage = vals.get('stage_id') new_stage = vals.get('stage_id')
vals_reset_kstate = dict(vals, kanban_state='normal') vals_reset_kstate = dict(vals, kanban_state='normal')
for t in self.browse(cr, uid, ids, context=context): 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 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) super(task, self).write(cr, uid, [t.id], write_vals, context=context)
result = True result = True
else: else:
result = super(task, self).write(cr, uid, ids, vals, context=context) 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) self._store_history(cr, uid, ids, context=context)
return result return result
@ -1161,7 +1091,8 @@ class task(base_stage, osv.osv):
result = "" result = ""
ident = ' '*ident ident = ' '*ident
for task in tasks: 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 continue
result += ''' result += '''
%sdef Task_%s(): %sdef Task_%s():
@ -1231,13 +1162,14 @@ class task(base_stage, osv.osv):
update_vals[field] = float(res.group(2).lower()) update_vals[field] = float(res.group(2).lower())
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
elif match.lower() == 'state' \ # elif match.lower() == 'state' \
and res.group(2).lower() in ['cancel','close','draft','open','pending']: # and res.group(2).lower() in ['cancel','close','draft','open','pending']:
act = 'do_%s' % res.group(2).lower() # act = 'do_%s' % res.group(2).lower()
if act: if act:
getattr(self,act)(cr, uid, ids, context=context) getattr(self,act)(cr, uid, ids, context=context)
return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, 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): 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'): if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'):
return { return {

View File

@ -30,51 +30,43 @@
<record id="project_tt_analysis" model="project.task.type"> <record id="project_tt_analysis" model="project.task.type">
<field name="sequence">1</field> <field name="sequence">1</field>
<field name="name">Analysis</field> <field name="name">Analysis</field>
<field name="state">draft</field> <field name="case_default" eval="True"/>
<field name="case_default" eval="False"/>
</record> </record>
<record id="project_tt_specification" model="project.task.type"> <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="name">Specification</field>
<field name="state">pending</field>
<field name="case_default" eval="True"/> <field name="case_default" eval="True"/>
</record> </record>
<record id="project_tt_design" model="project.task.type"> <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="name">Design</field>
<field name="state">open</field>
<field name="case_default" eval="True"/> <field name="case_default" eval="True"/>
</record> </record>
<record id="project_tt_development" model="project.task.type"> <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="name">Development</field>
<field name="state">open</field>
<field name="case_default" eval="True"/> <field name="case_default" eval="True"/>
</record> </record>
<record id="project_tt_testing" model="project.task.type"> <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="name">Testing</field>
<field name="state">open</field>
<field name="case_default" eval="True"/> <field name="case_default" eval="True"/>
</record> </record>
<record id="project_tt_merge" model="project.task.type"> <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="name">Merge</field>
<field name="state">open</field>
<field name="case_default" eval="False"/> <field name="case_default" eval="False"/>
<field name="fold" eval="True"/> <field name="fold" eval="True"/>
</record> </record>
<record id="project_tt_deployment" model="project.task.type"> <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="name">Done</field>
<field name="state">done</field>
<field name="case_default" eval="True"/> <field name="case_default" eval="True"/>
<field name="fold" eval="True"/> <field name="fold" eval="True"/>
</record> </record>
<record id="project_tt_cancel" model="project.task.type"> <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="name">Cancelled</field>
<field name="state">cancelled</field>
<field name="case_default" eval="True"/> <field name="case_default" eval="True"/>
<field name="fold" eval="True"/> <field name="fold" eval="True"/>
</record> </record>
@ -86,11 +78,11 @@
<field name="default" eval="False"/> <field name="default" eval="False"/>
<field name="description">Task created</field> <field name="description">Task created</field>
</record> </record>
<record id="mt_task_started" model="mail.message.subtype"> <record id="mt_task_assigned" model="mail.message.subtype">
<field name="name">Task Started</field> <field name="name">Task Assigned</field>
<field name="res_model">project.task</field> <field name="res_model">project.task</field>
<field name="default" eval="False"/> <field name="default" eval="False"/>
<field name="description">Task started</field> <field name="description">Task Assigned</field>
</record> </record>
<record id="mt_task_blocked" model="mail.message.subtype"> <record id="mt_task_blocked" model="mail.message.subtype">
<field name="name">Task Blocked</field> <field name="name">Task Blocked</field>
@ -98,12 +90,6 @@
<field name="default" eval="False"/> <field name="default" eval="False"/>
<field name="description">Task blocked</field> <field name="description">Task blocked</field>
</record> </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"> <record id="mt_task_stage" model="mail.message.subtype">
<field name="name">Stage Changed</field> <field name="name">Stage Changed</field>
<field name="res_model">project.task</field> <field name="res_model">project.task</field>
@ -118,11 +104,11 @@
<field name="parent_id" eval="ref('mt_task_new')"/> <field name="parent_id" eval="ref('mt_task_new')"/>
<field name="relation_field">project_id</field> <field name="relation_field">project_id</field>
</record> </record>
<record id="mt_project_task_started" model="mail.message.subtype"> <record id="mt_project_task_assigned" model="mail.message.subtype">
<field name="name">Task Started</field> <field name="name">Task Assigned</field>
<field name="res_model">project.project</field> <field name="res_model">project.project</field>
<field name="default" eval="False"/> <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> <field name="relation_field">project_id</field>
</record> </record>
<record id="mt_project_task_blocked" model="mail.message.subtype"> <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="parent_id" eval="ref('mt_task_blocked')"/>
<field name="relation_field">project_id</field> <field name="relation_field">project_id</field>
</record> </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"> <record id="mt_project_task_stage" model="mail.message.subtype">
<field name="name">Task Stage Changed</field> <field name="name">Task Stage Changed</field>
<field name="res_model">project.project</field> <field name="res_model">project.project</field>

View File

@ -225,7 +225,7 @@
ref('project.project_category_04')])]"/> ref('project.project_category_04')])]"/>
<field name="stage_id" ref="project_tt_merge"/> <field name="stage_id" ref="project_tt_merge"/>
</record> </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"> <record id="project_task_12" model="project.task">
<field name="planned_hours" eval="40.0"/> <field name="planned_hours" eval="40.0"/>
@ -237,7 +237,7 @@
<field name="stage_id" ref="project_tt_merge"/> <field name="stage_id" ref="project_tt_merge"/>
<field name="color">6</field> <field name="color">6</field>
</record> </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"> <record id="project_task_13" model="project.task">
<field name="planned_hours" eval="12.0"/> <field name="planned_hours" eval="12.0"/>
@ -248,7 +248,7 @@
<field name="name">Design Use Cases</field> <field name="name">Design Use Cases</field>
<field name="stage_id" ref="project_tt_analysis"/> <field name="stage_id" ref="project_tt_analysis"/>
</record> </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"> <record id="project_task_14" model="project.task">
<field name="planned_hours" eval="12.0"/> <field name="planned_hours" eval="12.0"/>
@ -282,7 +282,7 @@
<field name="name">Set target for all deparments</field> <field name="name">Set target for all deparments</field>
<field name="stage_id" ref="project_tt_development"/> <field name="stage_id" ref="project_tt_development"/>
</record> </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"> <record id="project_task_17" model="project.task">
<field name="planned_hours" eval="34.0"/> <field name="planned_hours" eval="34.0"/>
@ -293,7 +293,7 @@
<field name="name">Integration of core components</field> <field name="name">Integration of core components</field>
<field name="stage_id" ref="project_tt_testing"/> <field name="stage_id" ref="project_tt_testing"/>
</record> </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"> <record id="project_task_18" model="project.task">
<field name="planned_hours" eval="16.0"/> <field name="planned_hours" eval="16.0"/>
@ -315,7 +315,7 @@
<field name="categ_ids" eval="[(6, 0, [ <field name="categ_ids" eval="[(6, 0, [
ref('project_category_03')])]"/> ref('project_category_03')])]"/>
</record> </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"> <record id="project_task_20" model="project.task">
<field name="planned_hours">42.0</field> <field name="planned_hours">42.0</field>
@ -325,7 +325,7 @@
<field name="project_id" ref="project.project_project_4"/> <field name="project_id" ref="project.project_project_4"/>
<field name="name">Create new components</field> <field name="name">Create new components</field>
</record> </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"> <record id="project_task_21" model="project.task">
<field name="planned_hours">14.0</field> <field name="planned_hours">14.0</field>
@ -337,7 +337,7 @@
<field name="categ_ids" eval="[(6, 0, [ <field name="categ_ids" eval="[(6, 0, [
ref('project_category_04')])]"/> ref('project_category_04')])]"/>
</record> </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"> <record id="project_task_22" model="project.task">
<field name="planned_hours">12.0</field> <field name="planned_hours">12.0</field>
@ -371,7 +371,7 @@
<field name="categ_ids" eval="[(6, 0, [ <field name="categ_ids" eval="[(6, 0, [
ref('project_category_01')])]"/> ref('project_category_01')])]"/>
</record> </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"> <record id="project_task_25" model="project.task">
<field name="sequence">20</field> <field name="sequence">20</field>
@ -382,7 +382,7 @@
<field name="name">Data importation + Doc</field> <field name="name">Data importation + Doc</field>
<field name="stage_id" ref="project_tt_development"/> <field name="stage_id" ref="project_tt_development"/>
</record> </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"> <record id="project_task_26" model="project.task">
<field name="sequence">20</field> <field name="sequence">20</field>

View File

@ -18,23 +18,20 @@
<search string="Tasks"> <search string="Tasks">
<field name="name" string="Tasks"/> <field name="name" string="Tasks"/>
<field name="categ_ids"/> <field name="categ_ids"/>
<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"/>
<separator/>
<filter name="My project" string="Project" domain="[('project_id.user_id','=',uid)]" help="My Projects" icon="terp-check"/>
<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-"/>
<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="partner_id"/>
<field name="project_id"/> <field name="project_id"/>
<field name="user_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 name="My project" string="Project" domain="[('project_id.user_id','=',uid)]"/>
<separator/>
<filter string="My Tasks" domain="[('user_id','=',uid)]"/>
<separator/>
<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"/>
<group expand="0" string="Group By..."> <group expand="0" string="Group By...">
<filter string="Users" name="group_user_id" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/> <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'}"/> <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"> <field name="arch" type="xml">
<form string="Project" version="7.0"> <form string="Project" version="7.0">
<header> <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"/> <field name="stage_id" widget="statusbar" clickable="True"/>
</header> </header>
<sheet string="Task"> <sheet string="Task">
@ -396,8 +381,7 @@
<group> <group>
<group> <group>
<field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/> <field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
<field name="user_id" <field name="user_id"
attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"
options='{"no_open": True}' options='{"no_open": True}'
context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/> context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/>
<field name="planned_hours" widget="float_time" <field name="planned_hours" widget="float_time"
@ -405,15 +389,15 @@
on_change="onchange_planned(planned_hours, effective_hours)"/> on_change="onchange_planned(planned_hours, effective_hours)"/>
</group> </group>
<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="categ_ids" widget="many2many_tags"/>
<field name="progress" widget="progressbar" <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>
</group> </group>
<notebook> <notebook>
<page string="Description"> <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"> <field name="work_ids" groups="project.group_tasks_work_on_tasks">
<tree string="Task Work" editable="top"> <tree string="Task Work" editable="top">
<field name="name"/> <field name="name"/>
@ -427,7 +411,7 @@
<field name="effective_hours" widget="float_time"/> <field name="effective_hours" widget="float_time"/>
<label for="remaining_hours" string="Remaining" groups="project.group_time_work_estimation_tasks"/> <label for="remaining_hours" string="Remaining" groups="project.group_time_work_estimation_tasks"/>
<div> <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> </div>
<field name="total_hours" widget="float_time" class="oe_subtotal_footer_separator"/> <field name="total_hours" widget="float_time" class="oe_subtotal_footer_separator"/>
</group> </group>
@ -436,7 +420,7 @@
</page> </page>
<page string="Delegation" groups="project.group_delegate_task"> <page string="Delegation" groups="project.group_delegate_task">
<button name="%(action_project_task_delegate)d" string="Delegate" type="action" <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"/> <separator string="Parent Tasks"/>
<field name="parent_ids"/> <field name="parent_ids"/>
<separator string="Delegated tasks"/> <separator string="Delegated tasks"/>
@ -445,7 +429,6 @@
<field name="name"/> <field name="name"/>
<field name="user_id"/> <field name="user_id"/>
<field name="stage_id"/> <field name="stage_id"/>
<field name="state" invisible="1"/>
<field name="effective_hours" widget="float_time"/> <field name="effective_hours" widget="float_time"/>
<field name="progress" widget="progressbar"/> <field name="progress" widget="progressbar"/>
<field name="remaining_hours" widget="float_time"/> <field name="remaining_hours" widget="float_time"/>
@ -453,12 +436,11 @@
</tree> </tree>
</field> </field>
</page> </page>
<page string="Extra Info" attrs="{'readonly':[('state','=','done')]}"> <page string="Extra Info">
<group col="4"> <group col="4">
<field name="priority" groups="base.group_user"/> <field name="priority" groups="base.group_user"/>
<field name="sequence"/> <field name="sequence"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="state" invisible="1"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/> <field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group> </group>
<group> <group>
@ -467,6 +449,7 @@
<field name="date_end"/> <field name="date_end"/>
</group> </group>
<group> <group>
<field name="date_last_stage_update" groups="base.group_no_one"/>
</group> </group>
</group> </group>
</page> </page>
@ -493,7 +476,6 @@
<field name="user_email"/> <field name="user_email"/>
<field name="description"/> <field name="description"/>
<field name="sequence"/> <field name="sequence"/>
<field name="state" groups="base.group_no_one"/>
<field name="kanban_state"/> <field name="kanban_state"/>
<field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/> <field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/>
<field name="date_deadline"/> <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_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_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="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> </ul>
</li> </li>
<br/> <br/>
@ -562,7 +544,7 @@
<field name="model">project.task</field> <field name="model">project.task</field>
<field eval="2" name="priority"/> <field eval="2" name="priority"/>
<field name="arch" type="xml"> <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="message_unread" invisible="1"/>
<field name="sequence" invisible="not context.get('seq_visible', False)"/> <field name="sequence" invisible="not context.get('seq_visible', False)"/>
<field name="name"/> <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="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="date_deadline" invisible="context.get('deadline_visible',True)"/>
<field name="stage_id" invisible="context.get('set_visible',False)"/> <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_start" groups="base.group_no_one"/>
<field name="date_end" 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)"/> <field name="progress" widget="progressbar" invisible="context.get('set_visible',False)"/>
@ -706,7 +687,6 @@
<field name="case_default"/> <field name="case_default"/>
</group> </group>
<group> <group>
<field name="state"/>
<field name="sequence"/> <field name="sequence"/>
<field name="fold"/> <field name="fold"/>
</group> </group>
@ -723,7 +703,7 @@
<tree string="Task Stage"> <tree string="Task Stage">
<field name="sequence" widget="handle"/> <field name="sequence" widget="handle"/>
<field name="name"/> <field name="name"/>
<field name="state"/> <field name="fold"/>
</tree> </tree>
</field> </field>
</record> </record>

View File

@ -19,7 +19,7 @@
# #
############################################################################## ##############################################################################
from openerp.osv import fields,osv from openerp.osv import fields, osv
from openerp import tools from openerp import tools
class report_project_task_user(osv.osv): 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), 'day': fields.char('Day', size=128, readonly=True),
'year': fields.char('Year', size=64, required=False, readonly=True), 'year': fields.char('Year', size=64, required=False, readonly=True),
'user_id': fields.many2one('res.users', 'Assigned To', 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), 'no_of_days': fields.integer('# of Days', size=128, readonly=True),
'date_end': fields.date('Ending Date', readonly=True), 'date_end': fields.date('Ending Date', readonly=True),
'date_deadline': fields.date('Deadline', 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), 'project_id': fields.many2one('project.project', 'Project', readonly=True),
'hours_planned': fields.float('Planned Hours', readonly=True), 'hours_planned': fields.float('Planned Hours', readonly=True),
'hours_effective': fields.float('Effective 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), 'total_hours': fields.float('Total Hours', readonly=True),
'closing_days': fields.float('Days to Close', digits=(16,2), readonly=True, group_operator="avg", 'closing_days': fields.float('Days to Close', digits=(16,2), readonly=True, group_operator="avg",
help="Number of Days to close the task"), 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"), help="Number of Days to Open the task"),
'delay_endings_days': fields.float('Overpassed Deadline', digits=(16,2), readonly=True), 'delay_endings_days': fields.float('Overpassed Deadline', digits=(16,2), readonly=True),
'nbr': fields.integer('# of tasks', readonly=True), 'nbr': fields.integer('# of tasks', readonly=True),
'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), ('1', 'Urgent'), ('0', 'Very urgent')],
('0','Very urgent')], 'Priority', readonly=True), 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), '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), '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), 'company_id': fields.many2one('res.company', 'Company', readonly=True),
'partner_id': fields.many2one('res.partner', 'Contact', readonly=True), 'partner_id': fields.many2one('res.partner', 'Contact', readonly=True),
'stage_id': fields.many2one('project.task.type', 'Stage'),
} }
_order = 'name desc, project_id' _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, to_char(date_start, 'YYYY-MM-DD') as day,
date_trunc('day',t.date_start) as date_start, date_trunc('day',t.date_start) as date_start,
date_trunc('day',t.date_end) as date_end, 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, 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, -- 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, abs((extract('epoch' from (t.date_end-t.date_start)))/(3600*24)) as no_of_days,
t.user_id, t.user_id,
progress as progress, progress as progress,
t.project_id, t.project_id,
t.state,
t.effective_hours as hours_effective, t.effective_hours as hours_effective,
t.priority, t.priority,
t.name as name, t.name as name,
t.company_id, t.company_id,
t.partner_id, t.partner_id,
t.stage_id, t.stage_id as stage_id,
remaining_hours as remaining_hours, remaining_hours as remaining_hours,
total_hours as total_hours, total_hours as total_hours,
t.delay_hours as hours_delay, t.delay_hours as hours_delay,
@ -106,15 +110,13 @@ class report_project_task_user(osv.osv):
date_start, date_start,
date_end, date_end,
date_deadline, date_deadline,
date_last_stage_update,
month_last_stage_update,
t.user_id, t.user_id,
t.project_id, t.project_id,
t.state,
t.priority, t.priority,
name, name,
t.company_id, t.company_id,
t.partner_id, t.partner_id,
t.stage_id stage_id
""") """)

View File

@ -15,9 +15,10 @@
<field name="project_id" invisible="1"/> <field name="project_id" invisible="1"/>
<field name="user_id" invisible="1"/> <field name="user_id" invisible="1"/>
<field name="date_deadline" invisible="1"/> <field name="date_deadline" invisible="1"/>
<field name="state" invisible="1"/>
<field name="date_start" invisible="1"/> <field name="date_start" invisible="1"/>
<field name="date_end" 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="company_id" invisible="1" groups="base.group_multi_company"/>
<field name="partner_id" invisible="1"/> <field name="partner_id" invisible="1"/>
<field name="day" invisible="1"/> <field name="day" invisible="1"/>
@ -44,7 +45,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<graph string="Tasks Analysis" type="bar"> <graph string="Tasks Analysis" type="bar">
<field name="name"/> <field name="name"/>
<field name="state" group="True"/> <field name="stage_id" group="True"/>
<field name="no_of_days" operator="+"/> <field name="no_of_days" operator="+"/>
</graph> </graph>
</field> </field>
@ -58,31 +59,32 @@
<field name="date_start"/> <field name="date_start"/>
<field name="date_end"/> <field name="date_end"/>
<field name="date_deadline"/> <field name="date_deadline"/>
<filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help = "New tasks"/> <field name="date_last_stage_update"/>
<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="project_id"/> <field name="project_id"/>
<field name="user_id"/> <field name="user_id"/>
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/> <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..."> <group expand="0" string="Extended Filters...">
<field name="priority"/> <field name="priority"/>
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company"/>
</group> </group>
<group expand="1" string="Group By..."> <group expand="1" string="Group By...">
<filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}"/> <filter string="Project" name="project" context="{'group_by':'project_id'}"/>
<filter string="Task" icon="terp-stock_align_left_24" context="{'group_by':'name'}" /> <filter string="Task" context="{'group_by':'name'}" />
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" /> <filter string="Contact" context="{'group_by':'partner_id'}" />
<filter string="Assigned to" name="User" icon="terp-personal" context="{'group_by':'user_id'}" /> <filter string="Assigned to" name="User" context="{'group_by':'user_id'}" />
<filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/> <filter string="Company" 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="Day" context="{'group_by':'day'}" help="Creation Date"/>
<filter string="Month" icon="terp-go-month" context="{'group_by':'month'}" help="Creation Date"/> <filter string="Month" context="{'group_by':'month'}" help="Creation Date"/>
<filter string="Year" icon="terp-go-year" context="{'group_by':'year'}" 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> </group>
</search> </search>
</field> </field>

View File

@ -1,14 +1,5 @@
- -
I put task in pending due to specification is not clear. I open a delegation wizard.
-
!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"
- -
!record {model: project.task.delegate, id: delegate_id}: !record {model: project.task.delegate, id: delegate_id}:
user_id: base.user_demo user_id: base.user_demo

View File

@ -20,7 +20,5 @@
############################################################################## ##############################################################################
import project_task_delegate import project_task_delegate
import project_task_reevaluate
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -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:

View File

@ -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>

View File

@ -21,7 +21,6 @@
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp.addons.base_status.base_stage import base_stage 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 openerp.addons.crm import crm
from datetime import datetime from datetime import datetime
from openerp.osv import fields, osv, orm 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), 'partner_id': fields.many2one('res.partner', 'Contact', select=1),
'company_id': fields.many2one('res.company', 'Company'), 'company_id': fields.many2one('res.company', 'Company'),
'description': fields.text('Private Note'), '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', 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
track_visibility='onchange', track_visibility='onchange',
help="A Issue's kanban state indicates special situations affecting it:\n" help="A Issue's kanban state indicates special situations affecting it:\n"