summaryrefslogtreecommitdiff
path: root/addons/project
diff options
context:
space:
mode:
authorRaphael Collet <rco@openerp.com>2014-07-06 16:44:26 +0200
committerAntony Lesuisse <al@openerp.com>2014-07-06 17:05:41 +0200
commitcbe2dbb672a6c55d86f2e515f9d1cdfee426ef80 (patch)
treed6ff62b719fce32392397783c961b734b1e4c50e /addons/project
parentd78192c489d3be66cd6487b39f5ce7ba4733a187 (diff)
[MERGE] new v8 api by rco
A squashed merge is required as the conversion of the apiculture branch from bzr to git was not correctly done. The git history contains irrelevant blobs and commits. This branch brings a lot of changes and fixes, too many to list exhaustively. - New orm api, objects are now used instead of ids - Environements to encapsulates cr uid context while maintaining backward compatibility - Field compute attribute is a new object oriented way to define function fields - Shared browse record cache - New onchange protocol - Optional copy flag on fields - Documentation update - Dead code cleanup - Lots of fixes
Diffstat (limited to 'addons/project')
-rw-r--r--addons/project/project.py81
-rw-r--r--addons/project/project_view.xml12
-rw-r--r--addons/project/tests/test_project_flow.py6
-rw-r--r--addons/project/wizard/project_task_delegate.py2
4 files changed, 47 insertions, 54 deletions
diff --git a/addons/project/project.py b/addons/project/project.py
index f95f3e4517c..78c3904ec07 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -273,7 +273,13 @@ class project(osv.osv):
"- Employees Only: employees see all tasks or issues\n"
"- Followers Only: employees see only the followed tasks or issues; if portal\n"
" is activated, portal users see the followed tasks or issues."),
- 'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','Pending'),('close','Closed')], 'Status', required=True,),
+ 'state': fields.selection([('template', 'Template'),
+ ('draft','New'),
+ ('open','In Progress'),
+ ('cancelled', 'Cancelled'),
+ ('pending','Pending'),
+ ('close','Closed')],
+ 'Status', required=True, copy=False),
'doc_count': fields.function(
_get_attached_docs, string="Number of documents attached", type='integer'
)
@@ -332,36 +338,28 @@ class project(osv.osv):
task_obj = self.pool.get('project.task')
proj = self.browse(cr, uid, old_project_id, context=context)
for task in proj.tasks:
- map_task_id[task.id] = task_obj.copy(cr, uid, task.id, {}, context=context)
+ # preserve task name and stage, normally altered during copy
+ defaults = {'stage_id': task.stage_id.id,
+ 'name': task.name}
+ map_task_id[task.id] = task_obj.copy(cr, uid, task.id, defaults, context=context)
self.write(cr, uid, [new_project_id], {'tasks':[(6,0, map_task_id.values())]})
task_obj.duplicate_task(cr, uid, map_task_id, context=context)
return True
def copy(self, cr, uid, id, default=None, context=None):
- if context is None:
- context = {}
if default is None:
default = {}
-
+ context = dict(context or {})
context['active_test'] = False
- default['state'] = 'open'
- default['line_ids'] = []
- default['tasks'] = []
-
- # Don't prepare (expensive) data to copy children (analytic accounts),
- # they are discarded in analytic.copy(), and handled in duplicate_template()
- default['child_ids'] = []
-
proj = self.browse(cr, uid, id, context=context)
- if not default.get('name', False):
+ if not default.get('name'):
default.update(name=_("%s (copy)") % (proj.name))
res = super(project, self).copy(cr, uid, id, default, context)
self.map_tasks(cr, uid, id, res, context=context)
return res
def duplicate_template(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
+ context = dict(context or {})
data_obj = self.pool.get('ir.model.data')
result = []
for proj in self.browse(cr, uid, ids, context=context):
@@ -696,29 +694,11 @@ class task(osv.osv):
def copy_data(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
- default = default or {}
- default.update({'work_ids':[], 'date_start': False, 'date_end': False, 'date_deadline': False})
- if not default.get('remaining_hours', False):
- default['remaining_hours'] = float(self.read(cr, uid, id, ['planned_hours'])['planned_hours'])
- default['active'] = True
- if not default.get('name', False):
- default['name'] = self.browse(cr, uid, id, context=context).name or ''
- if not context.get('copy',False):
- new_name = _("%s (copy)") % (default.get('name', ''))
- default.update({'name':new_name})
+ if not default.get('name'):
+ current = self.browse(cr, uid, id, context=context)
+ default['name'] = _("%s (copy)") % current.name
return super(task, self).copy_data(cr, uid, id, default, context)
- def copy(self, cr, uid, id, default=None, context=None):
- if context is None:
- context = {}
- if default is None:
- default = {}
- if not context.get('copy', False):
- stage = self._get_default_stage_id(cr, uid, context=context)
- if stage:
- default['stage_id'] = stage
- return super(task, self).copy(cr, uid, id, default, context)
-
def _is_template(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for task in self.browse(cr, uid, ids, context=context):
@@ -741,7 +721,7 @@ class task(osv.osv):
'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], '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', select=True,
- domain="[('project_ids', '=', project_id)]"),
+ domain="[('project_ids', '=', project_id)]", copy=False),
'categ_ids': fields.many2many('project.category', string='Tags'),
'kanban_state': fields.selection([('normal', 'In Progress'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
track_visibility='onchange',
@@ -749,13 +729,13 @@ class task(osv.osv):
" * Normal is the default situation\n"
" * Blocked indicates something is preventing the progress of this task\n"
" * Ready for next stage indicates the task is ready to be pulled to the next stage",
- required=False),
+ required=False, copy=False),
'create_date': fields.datetime('Create Date', readonly=True, select=True),
'write_date': fields.datetime('Last Modification Date', readonly=True, select=True), #not displayed in the view but it might be useful with base_action_rule module (and it needs to be defined first for that)
- '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),
+ 'date_start': fields.datetime('Starting Date', select=True, copy=False),
+ 'date_end': fields.datetime('Ending Date', select=True, copy=False),
+ 'date_deadline': fields.date('Deadline', select=True, copy=False),
+ 'date_last_stage_update': fields.datetime('Last Stage Update', select=True, copy=False),
'project_id': fields.many2one('project.project', 'Project', ondelete='set null', select=True, track_visibility='onchange', change_default=True),
'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'),
@@ -888,6 +868,7 @@ class task(osv.osv):
return res
def get_empty_list_help(self, cr, uid, help, context=None):
+ context = dict(context or {})
context['empty_list_help_id'] = context.get('default_project_id')
context['empty_list_help_model'] = 'project.project'
context['empty_list_help_document_name'] = _("tasks")
@@ -1011,8 +992,7 @@ class task(osv.osv):
# ------------------------------------------------
def create(self, cr, uid, vals, context=None):
- if context is None:
- context = {}
+ context = dict(context or {})
# for default stage
if vals.get('project_id') and not context.get('default_project_id'):
@@ -1044,7 +1024,7 @@ class task(osv.osv):
new_stage = vals.get('stage_id')
vals_reset_kstate = dict(vals, kanban_state='normal')
for t in self.browse(cr, uid, ids, context=context):
- write_vals = vals_reset_kstate if t.stage_id != new_stage else vals
+ write_vals = vals_reset_kstate if t.stage_id.id != new_stage else vals
super(task, self).write(cr, uid, [t.id], write_vals, context=context)
result = True
else:
@@ -1153,24 +1133,29 @@ class project_work(osv.osv):
}
_order = "date desc"
- def create(self, cr, uid, vals, *args, **kwargs):
+ def create(self, cr, uid, vals, context=None):
if 'hours' in vals and (not vals['hours']):
vals['hours'] = 0.00
if 'task_id' in vals:
cr.execute('update project_task set remaining_hours=remaining_hours - %s where id=%s', (vals.get('hours',0.0), vals['task_id']))
- return super(project_work,self).create(cr, uid, vals, *args, **kwargs)
+ self.pool.get('project.task').invalidate_cache(cr, uid, ['remaining_hours'], [vals['task_id']], context=context)
+ return super(project_work,self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
if 'hours' in vals and (not vals['hours']):
vals['hours'] = 0.00
if 'hours' in vals:
+ task_obj = self.pool.get('project.task')
for work in self.browse(cr, uid, ids, context=context):
cr.execute('update project_task set remaining_hours=remaining_hours - %s + (%s) where id=%s', (vals.get('hours',0.0), work.hours, work.task_id.id))
+ task_obj.invalidate_cache(cr, uid, ['remaining_hours'], [work.task_id.id], context=context)
return super(project_work,self).write(cr, uid, ids, vals, context)
def unlink(self, cr, uid, ids, *args, **kwargs):
+ task_obj = self.pool.get('project.task')
for work in self.browse(cr, uid, ids):
cr.execute('update project_task set remaining_hours=remaining_hours + %s where id=%s', (work.hours, work.task_id.id))
+ task_obj.invalidate_cache(cr, uid, ['remaining_hours'], [work.task_id.id], context=context)
return super(project_work,self).unlink(cr, uid, ids,*args, **kwargs)
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index c151464fb5c..41e100cec1f 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -8,8 +8,16 @@
groups="group_project_manager,group_project_user"
sequence="40"/>
- <menuitem id="menu_project_management" name="Project" parent="base.menu_main_pm" sequence="1"/>
- <menuitem id="base.menu_definitions" name="Configuration" parent="base.menu_main_pm" sequence="60"/>
+ <menuitem name="Project"
+ id="menu_project_management"
+ parent="base.menu_main_pm"
+ sequence="1"/>
+
+ <menuitem name="Configuration"
+ id="base.menu_definitions"
+ parent="base.menu_main_pm"
+ groups="group_project_manager"
+ sequence="60"/>
<record id="view_task_search_form" model="ir.ui.view">
<field name="name">project.task.search.form</field>
diff --git a/addons/project/tests/test_project_flow.py b/addons/project/tests/test_project_flow.py
index ecbe66a0cea..58263f6ea8a 100644
--- a/addons/project/tests/test_project_flow.py
+++ b/addons/project/tests/test_project_flow.py
@@ -51,7 +51,7 @@ Integrator at Agrolait"""
class TestProjectFlow(TestProjectBase):
- @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm')
+ @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_project_process(self):
""" Testing project management """
cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id
@@ -131,8 +131,8 @@ class TestProjectFlow(TestProjectBase):
# Test: one task created by mailgateway administrator
self.assertEqual(len(frogs), 1, 'project: message_process: a new project.task should have been created')
task = self.project_task.browse(cr, user_projectuser_id, frogs[0])
- res = self.project_task.perm_read(cr, uid, [task.id], details=False)
- self.assertEqual(res[0].get('create_uid'), uid,
+ res = self.project_task.get_metadata(cr, uid, [task.id])[0].get('create_uid') or [None]
+ self.assertEqual(res[0], uid,
'project: message_process: task should have been created by uid as alias_user_id is False on the alias')
# Test: messages
self.assertEqual(len(task.message_ids), 3,
diff --git a/addons/project/wizard/project_task_delegate.py b/addons/project/wizard/project_task_delegate.py
index a0e137eda0d..e3c935d4f5d 100644
--- a/addons/project/wizard/project_task_delegate.py
+++ b/addons/project/wizard/project_task_delegate.py
@@ -125,7 +125,7 @@ class project_task_delegate(osv.osv_memory):
action_model, action_id = models_data.get_object_reference(cr, uid, 'project', 'action_view_task')
view_model, task_view_form_id = models_data.get_object_reference(cr, uid, 'project', 'view_task_form2')
view_model, task_view_tree_id = models_data.get_object_reference(cr, uid, 'project', 'view_task_tree2')
- action = self.pool[action_model].read(cr, uid, action_id, context=context)
+ action = self.pool[action_model].read(cr, uid, [action_id], context=context)[0]
action['res_id'] = delegated_tasks[task_id]
action['view_id'] = False
action['views'] = [(task_view_form_id, 'form'), (task_view_tree_id, 'tree')]