From 76af9027a7c46e9037371bdf41ffe270c2281879 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Thu, 4 Apr 2013 10:48:24 +0200 Subject: [IMP] Add options for privacy_visibility in project bzr revid: jco@openerp.com-20130404084824-notnfhyda1w4q2ig --- addons/project/project.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 0751865d9c4..e4d08d82f16 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -173,6 +173,35 @@ class project(osv.osv): res[id]['progress_rate'] = 0.0 return res + #We want to test this to check if it can avoid whether it has access + def _progress_rate2(self, cr, uid, ids, names, arg, context=None): + child_parent = self._get_project_and_children(cr, uid, ids, context) + tasks = self.pool.get("project.task").search(cr, uid, [('project_id', 'in', child_parent.keys()), ('state','!=','cancel')], context=context) + cr.execute(""" + SELECT project_id, COALESCE(SUM(planned_hours), 0.0), + COALESCE(SUM(total_hours), 0.0), COALESCE(SUM(effective_hours), 0.0) + FROM project_task WHERE id IN %s AND state <> 'cancelled' + GROUP BY project_id + """, (tuple(tasks),)) + # aggregate results into res + res = dict([(id, {'planned_hours':0.0,'total_hours':0.0,'effective_hours':0.0}) for id in ids]) + for id, planned, total, effective in cr.fetchall(): + # add the values specific to id to all parent projects of id in the result + while id: + if id in ids: + res[id]['planned_hours'] += planned + res[id]['total_hours'] += total + res[id]['effective_hours'] += effective + id = child_parent[id] + # compute progress rates + for id in ids: + if res[id]['total_hours']: + res[id]['progress_rate'] = round(100.0 * res[id]['effective_hours'] / res[id]['total_hours'], 2) + else: + res[id]['progress_rate'] = 0.0 + return res + + def unlink(self, cr, uid, ids, context=None): alias_ids = [] mail_alias = self.pool.get('mail.alias') @@ -238,22 +267,22 @@ class project(osv.osv): 'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members', help="Project's members are users who can have an access to the tasks related to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}), 'tasks': fields.one2many('project.task', 'project_id', "Task Activities"), - '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_rate2, multi="progress", string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), }), - '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_rate2, multi="progress", string='Time Spent', help="Sum of spent hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), }), - '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_rate2, multi="progress", string='Total Time', help="Sum of total hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), }), - '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_rate2, multi="progress", string='Progress', type='float', group_operator="avg", help="Percent of tasks closed according to the total of tasks todo.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), @@ -267,7 +296,7 @@ class project(osv.osv): "with Tasks (or optionally Issues if the Issue Tracker module is installed)."), 'alias_model': fields.selection(_alias_models, "Alias Model", select=True, required=True, help="The kind of document created when an email is received on this project's email alias"), - 'privacy_visibility': fields.selection([('public','All Users'), ('followers','Followers Only')], 'Privacy / Visibility', required=True), + 'privacy_visibility': fields.selection([('publicall', 'All Users All Tasks'), ('employees','All Employees'), ('public','All Users'), ('followers','Followers Only')], 'Privacy / Visibility', required=True), 'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','Pending'),('close','Closed')], 'Status', required=True,), 'doc_count':fields.function(_get_attached_docs, string="Number of documents attached", type='int') } -- cgit v1.2.3 From ecbcbdfbb6f830df3896a1b9dc194c1f404c845a Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Thu, 4 Apr 2013 12:04:57 +0200 Subject: [FIX] Progress rate visibility not an issue in trunk bzr revid: jco@openerp.com-20130404100457-5jm3e37ilatoto2n --- addons/project/project.py | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index e4d08d82f16..998060d652c 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -173,34 +173,6 @@ class project(osv.osv): res[id]['progress_rate'] = 0.0 return res - #We want to test this to check if it can avoid whether it has access - def _progress_rate2(self, cr, uid, ids, names, arg, context=None): - child_parent = self._get_project_and_children(cr, uid, ids, context) - tasks = self.pool.get("project.task").search(cr, uid, [('project_id', 'in', child_parent.keys()), ('state','!=','cancel')], context=context) - cr.execute(""" - SELECT project_id, COALESCE(SUM(planned_hours), 0.0), - COALESCE(SUM(total_hours), 0.0), COALESCE(SUM(effective_hours), 0.0) - FROM project_task WHERE id IN %s AND state <> 'cancelled' - GROUP BY project_id - """, (tuple(tasks),)) - # aggregate results into res - res = dict([(id, {'planned_hours':0.0,'total_hours':0.0,'effective_hours':0.0}) for id in ids]) - for id, planned, total, effective in cr.fetchall(): - # add the values specific to id to all parent projects of id in the result - while id: - if id in ids: - res[id]['planned_hours'] += planned - res[id]['total_hours'] += total - res[id]['effective_hours'] += effective - id = child_parent[id] - # compute progress rates - for id in ids: - if res[id]['total_hours']: - res[id]['progress_rate'] = round(100.0 * res[id]['effective_hours'] / res[id]['total_hours'], 2) - else: - res[id]['progress_rate'] = 0.0 - return res - def unlink(self, cr, uid, ids, context=None): alias_ids = [] @@ -267,22 +239,22 @@ class project(osv.osv): 'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members', help="Project's members are users who can have an access to the tasks related to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}), 'tasks': fields.one2many('project.task', 'project_id', "Task Activities"), - 'planned_hours': fields.function(_progress_rate2, 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 = { '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), }), - 'effective_hours': fields.function(_progress_rate2, 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 = { '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), }), - 'total_hours': fields.function(_progress_rate2, 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 = { '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), }), - 'progress_rate': fields.function(_progress_rate2, 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 = { '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), @@ -296,7 +268,7 @@ class project(osv.osv): "with Tasks (or optionally Issues if the Issue Tracker module is installed)."), 'alias_model': fields.selection(_alias_models, "Alias Model", select=True, required=True, help="The kind of document created when an email is received on this project's email alias"), - 'privacy_visibility': fields.selection([('publicall', 'All Users All Tasks'), ('employees','All Employees'), ('public','All Users'), ('followers','Followers Only')], 'Privacy / Visibility', required=True), + 'privacy_visibility': fields.selection([('publicall', 'All users will see all tasks'), ('public','All users'), ('employees','All employees'), ('followers','Followers Only')], 'Privacy / Visibility', required=True), 'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','Pending'),('close','Closed')], 'Status', required=True,), 'doc_count':fields.function(_get_attached_docs, string="Number of documents attached", type='int') } -- cgit v1.2.3 From a3de5c872f7c26ec085dc62b95cfc62382ab970a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 9 Apr 2013 13:11:58 +0200 Subject: [REF] [IMP] mail_alias improvement alias_name is not required anymore crm, hr_job, project, mail_group, res_users: alias creation is now different and done more like other inherits, except an alias_model_name that is given to the context to find the alias alias_model_id. crm, jr_job, project, mail_group, res_users: updated form views using aliases mail_alias: added a filter on 'inactive' aliases (alias_name False) and added a button to redirect to the related document if any bzr revid: tde@openerp.com-20130409111158-bv04n5o01z9l3c17 --- addons/project/project.py | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index eb328007d44..b580965e8f4 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -348,13 +348,11 @@ class project(osv.osv): default['state'] = 'open' default['line_ids'] = [] default['tasks'] = [] - default.pop('alias_name', None) - default.pop('alias_id', None) proj = self.browse(cr, uid, id, context=context) if not default.get('name', False): 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) + self.map_tasks(cr, uid, id, res, context=context) return res def duplicate_template(self, cr, uid, ids, context=None): @@ -505,7 +503,7 @@ def Project(): for project in projects: project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,)) for task in project.tasks: - if task.state in ('done','cancelled'): + if task.state in ('done', 'cancelled'): continue p = getattr(project_gantt, 'Task_%d' % (task.id,)) @@ -525,23 +523,17 @@ def Project(): # ------------------------------------------------ def create(self, cr, uid, vals, context=None): - if context is None: context = {} - # Prevent double project creation when 'use_tasks' is checked! - context = dict(context, project_creation_in_progress=True) - mail_alias = self.pool.get('mail.alias') - if not vals.get('alias_id') and vals.get('name', False): - alias_name = vals.pop('alias_name', None) # prevent errors during copy() - alias_id = mail_alias.create_unique_alias(cr, uid, - # Using '+' allows using subaddressing for those who don't - # have a catchall domain setup. - {'alias_name': alias_name or "project+"+short_name(vals['name'])}, - model_name=vals.get('alias_model', 'project.task'), - context=context) - vals['alias_id'] = alias_id - if vals.get('type', False) not in ('template','contract'): + if context is None: + context = {} + # Prevent double project creation when 'use_tasks' is checked + alias management + create_context = dict(context, project_creation_in_progress=True, alias_model_name=self._name) + + if vals.get('type', False) not in ('template', 'contract'): vals['type'] = 'contract' - project_id = super(project, self).create(cr, uid, vals, context) - mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'project_id': project_id} }, context) + + project_id = super(project, self).create(cr, uid, vals, context=create_context) + project_rec = self.browse(cr, uid, project_id, context=context) + self.pool.get('mail.alias').write(cr, uid, [project_rec.alias_id.id], {'alias_defaults': {'project_id': project_id}}, context) return project_id def write(self, cr, uid, ids, vals, context=None): -- cgit v1.2.3 From 3519e2c19f90002555163c7bae1bd07e14510e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 10 Apr 2013 18:01:39 +0200 Subject: [IMP] project, task, issues: improvement of ir rules. Still a bit WIP. bzr revid: tde@openerp.com-20130410160139-vx9z4rsmfiji1vu9 --- addons/project/project.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 473b4e06fe9..524034aa0bc 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -173,7 +173,6 @@ class project(osv.osv): res[id]['progress_rate'] = 0.0 return res - def unlink(self, cr, uid, ids, context=None): alias_ids = [] mail_alias = self.pool.get('mail.alias') @@ -183,10 +182,10 @@ class project(osv.osv): _('You cannot delete a project containing tasks. You can either delete all the project\'s tasks and then delete the project or simply deactivate the project.')) elif proj.alias_id: alias_ids.append(proj.alias_id.id) - res = super(project, self).unlink(cr, uid, ids, context=context) + res = super(project, self).unlink(cr, uid, ids, context=context) mail_alias.unlink(cr, uid, alias_ids, context=context) return res - + def _get_attached_docs(self, cr, uid, ids, field_name, arg, context): res = {} attachment = self.pool.get('ir.attachment') @@ -197,7 +196,7 @@ class project(osv.osv): task_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)], context=context, count=True) res[id] = (project_attachments or 0) + (task_attachments or 0) return res - + def _task_count(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, 0) task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)]) @@ -206,16 +205,21 @@ class project(osv.osv): return res def _get_alias_models(self, cr, uid, context=None): - """Overriden in project_issue to offer more options""" + """ Overriden in project_issue to offer more options """ return [('project.task', "Tasks")] + def _get_visibility_selection(self, cr, uid, context=None): + """ Overriden in project_issue to offer more options """ + return [('public', 'All Users'), + ('employees', 'Employees Only'), + ('followers', 'Followers Only')] + def attachment_tree_view(self, cr, uid, ids, context): task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)]) domain = [ - '|', + '|', '&', ('res_model', '=', 'project.project'), ('res_id', 'in', ids), - '&', ('res_model', '=', 'project.task'), ('res_id', 'in', task_ids) - ] + '&', ('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)] res_id = ids and ids[0] or False return { 'name': _('Attachments'), @@ -228,8 +232,11 @@ class project(osv.osv): 'limit': 80, 'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, res_id) } + # Lambda indirection method to avoid passing a copy of the overridable method when declaring the field _alias_models = lambda self, *args, **kwargs: self._get_alias_models(*args, **kwargs) + _visibility_selection = lambda self, *args, **kwargs: self._get_visibility_selection(*args, **kwargs) + _columns = { 'complete_name': fields.function(_complete_name, string="Project Name", type='char', size=250), 'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the project without removing it."), @@ -268,7 +275,8 @@ class project(osv.osv): "with Tasks (or optionally Issues if the Issue Tracker module is installed)."), 'alias_model': fields.selection(_alias_models, "Alias Model", select=True, required=True, help="The kind of document created when an email is received on this project's email alias"), - 'privacy_visibility': fields.selection([('publicall', 'All users will see all tasks'), ('public','All users'), ('employees','All employees'), ('followers','Followers Only')], 'Privacy / Visibility', required=True), + 'visibility': fields.selection(_visibility_selection, 'Privacy / Visibility', + select=True, required=True, oldname="privacy_visibility"), 'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','Pending'),('close','Closed')], 'Status', required=True,), 'doc_count':fields.function(_get_attached_docs, string="Number of documents attached", type='int') } @@ -286,7 +294,7 @@ class project(osv.osv): 'sequence': 10, 'type_ids': _get_type_common, 'alias_model': 'project.task', - 'privacy_visibility': 'public', + 'visibility': 'public', } # TODO: Why not using a SQL contraints ? -- cgit v1.2.3 From c7897690e2aafa74649297d06a7f9f538bd15661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 16 Apr 2013 15:39:36 +0200 Subject: [REF] project: removed duplicate files introduced when merging 7 into branch, because of backport of some modifications done in this branch in 7 bzr revid: tde@openerp.com-20130416133936-cr0sno29vk5dyj0e --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index c10d44c498b..c958470064e 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -293,7 +293,7 @@ class project(osv.osv): 'sequence': 10, 'type_ids': _get_type_common, 'alias_model': 'project.task', - 'visibility': 'public', + 'privacy_visibility': 'employees', } # TODO: Why not using a SQL contraints ? -- cgit v1.2.3 From 3b73e2b2a48f0e9b48256f97fa361156f58756c4 Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Mon, 29 Apr 2013 12:45:57 +0530 Subject: [IMP]Removed space before Exclamation marks [!] bzr revid: ggh@tinyerp.com-20130429071557-vnxo5nni03vc886j --- addons/project/project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 0b99356a9de..6435fef0be9 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -436,7 +436,7 @@ class project(osv.osv): for project in projects: if (not project.members) and force_members: - raise osv.except_osv(_('Warning!'),_("You must assign members on the project '%s' !") % (project.name,)) + raise osv.except_osv(_('Warning!'),_("You must assign members on the project '%s'!") % (project.name,)) resource_pool = self.pool.get('resource.resource') @@ -941,7 +941,7 @@ class task(base_stage, osv.osv): if task.child_ids: for child in task.child_ids: if child.state in ['draft', 'open', 'pending']: - 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 def action_close(self, cr, uid, ids, context=None): -- cgit v1.2.3 From a5bb69ec28bad2d86f5559d377862f0f77744f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 7 May 2013 11:36:36 +0200 Subject: [IMP] project: improved privacy_visiliby options labels, improved form view according to new specs. bzr revid: tde@openerp.com-20130507093636-gk9k1rc52u3ats3a --- addons/project/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index c958470064e..5bc09fcfefe 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -210,9 +210,9 @@ class project(osv.osv): def _get_visibility_selection(self, cr, uid, context=None): """ Overriden in portal_project to offer more options """ - return [('public', 'All Users'), - ('employees', 'Employees Only'), - ('followers', 'Followers Only')] + return [('public', 'Public project'), + ('employees', 'Internal project: all employees can access'), + ('followers', 'Private project: followers Only')] def attachment_tree_view(self, cr, uid, ids, context): task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)]) -- cgit v1.2.3 From 8c513eb7e5160986e1b700b6370b7939d2c089fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 May 2013 11:49:54 +0200 Subject: [FIX] project: correct model given to alias when creating a project. bzr revid: tde@openerp.com-20130516094954-4c6i6ql82xohm12r --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 5bc09fcfefe..370cec98970 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -534,7 +534,7 @@ def Project(): if context is None: context = {} # Prevent double project creation when 'use_tasks' is checked + alias management - create_context = dict(context, project_creation_in_progress=True, alias_model_name=self._name) + create_context = dict(context, project_creation_in_progress=True, alias_model_name=vals.get('alias_model', 'project.task')) if vals.get('type', False) not in ('template', 'contract'): vals['type'] = 'contract' -- cgit v1.2.3 From 88e3505554038350ae0274e9359bbffff342b9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 May 2013 18:42:07 +0200 Subject: [IMP] mail_alias: added reference to the parent record. The parent record is the record that holds the alias. It is different from the record updated or created using the alias. For example projects have aliases whose parent is the given projet, and that creates new task inside the project. Updated alias creation and management accordingly. This ownership concept is used to compute the 'followers' contact settings of aliases. bzr revid: tde@openerp.com-20130516164207-1zr0q6abw6a34ndf --- addons/project/project.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 370cec98970..54137da4773 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -534,14 +534,15 @@ def Project(): if context is None: context = {} # Prevent double project creation when 'use_tasks' is checked + alias management - create_context = dict(context, project_creation_in_progress=True, alias_model_name=vals.get('alias_model', 'project.task')) + create_context = dict(context, project_creation_in_progress=True, + alias_model_name=vals.get('alias_model', 'project.task'), alias_parent_model_name=self._name) if vals.get('type', False) not in ('template', 'contract'): vals['type'] = 'contract' project_id = super(project, self).create(cr, uid, vals, context=create_context) project_rec = self.browse(cr, uid, project_id, context=context) - self.pool.get('mail.alias').write(cr, uid, [project_rec.alias_id.id], {'alias_defaults': {'project_id': project_id}}, context) + self.pool.get('mail.alias').write(cr, uid, [project_rec.alias_id.id], {'alias_parent_thread_id': project_id, 'alias_defaults': {'project_id': project_id}}, context) return project_id def write(self, cr, uid, ids, vals, context=None): -- cgit v1.2.3 From 9d9e3d2ef84eb5cc5a5ef4eec11127d17164e485 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Fri, 7 Jun 2013 13:38:29 +0200 Subject: [IMP] Improve typos in warning (Grammar mistake, Capitalize title, Typos) bzr revid: chm@openerp.com-20130607113829-1mi6jk18c2v3jjhn --- addons/project/project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 53606acb6a1..4dd50861509 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -441,7 +441,7 @@ class project(osv.osv): for project in projects: if (not project.members) and force_members: - raise osv.except_osv(_('Warning!'),_("You must assign members on the project '%s' !") % (project.name,)) + raise osv.except_osv(_('Warning!'),_("You must assign members on the project '%s'!") % (project.name,)) resource_pool = self.pool.get('resource.resource') @@ -941,7 +941,7 @@ class task(base_stage, osv.osv): if task.child_ids: for child in task.child_ids: if child.state in ['draft', 'open', 'pending']: - 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 def action_close(self, cr, uid, ids, context=None): -- cgit v1.2.3 From 9005541f99ea2077251d36ebb9563ec51934f5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 19 Jun 2013 13:46:33 +0200 Subject: [FIX] crm, project.task, project.issue, hr_recruitment: fixed quick create in kanban, simplified a bit the code in the various create overrides. bzr revid: tde@openerp.com-20130619114633-pb0rtz0kivlrabcx --- addons/project/project.py | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 4dd50861509..10288f0792b 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -584,6 +584,15 @@ class task(base_stage, osv.osv): }, } + def _get_default_partner(self, cr, uid, context=None): + """ Override of base_stage to add project specific behavior """ + project_id = self._get_default_project_id(cr, uid, context) + if project_id: + partner = self.pool.get('project.project').browse(cr, uid, project_id, context=context).partner_id + if partner: + return partner.id + return super(task, self)._get_default_partner(cr, uid, context=context) + def _get_default_project_id(self, cr, uid, context=None): """ Gives default section by checking if present in the context """ return (self._resolve_project_id_from_context(cr, uid, context=context) or False) @@ -598,7 +607,8 @@ class task(base_stage, osv.osv): context key, or None if it cannot be resolved to a single project. """ - if context is None: context = {} + if context is None: + context = {} if type(context.get('default_project_id')) in (int, long): return context['default_project_id'] if isinstance(context.get('default_project_id'), basestring): @@ -679,13 +689,11 @@ class task(base_stage, osv.osv): def onchange_planned(self, cr, uid, ids, planned=0.0, effective=0.0): return {'value':{'remaining_hours': planned - effective}} - def onchange_project(self, cr, uid, id, project_id): - if not project_id: - return {} - data = self.pool.get('project.project').browse(cr, uid, [project_id]) - partner_id=data and data[0].partner_id - if partner_id: - return {'value':{'partner_id':partner_id.id}} + def onchange_project(self, cr, uid, id, project_id, context=None): + if project_id: + project = self.pool.get('project.project').browse(cr, uid, project_id, context=context) + if project and project.partner_id: + return {'value': {'partner_id': project.partner_id.id}} return {} def duplicate_task(self, cr, uid, map_ids, context=None): @@ -808,8 +816,9 @@ class task(base_stage, osv.osv): 'progress': 0, 'sequence': 10, 'active': True, - 'user_id': lambda obj, cr, uid, context: uid, - 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=c), + 'user_id': lambda obj, cr, uid, ctx=None: uid, + 'company_id': lambda self, cr, uid, ctx=None: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=ctx), + 'partner_id': lambda self, cr, uid, ctx=None: self._get_default_partner(cr, uid, context=ctx), } _order = "priority, sequence, date_start, name, id" @@ -1103,11 +1112,9 @@ class task(base_stage, osv.osv): def create(self, cr, uid, vals, context=None): if context is None: context = {} - if not vals.get('stage_id'): - ctx = context.copy() - if vals.get('project_id'): - ctx['default_project_id'] = vals['project_id'] - vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx) + if vals.get('project_id') and not context.get('default_project_id'): + context['default_project_id'] = vals.get('project_id') + # context: no_log, because subtype already handle this create_context = dict(context, mail_create_nolog=True) task_id = super(task, self).create(cr, uid, vals, context=create_context) -- cgit v1.2.3 From 67e4eff42b1ffbcf5433181bf00bf543f7160ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Jun 2013 11:37:32 +0200 Subject: [CLEAN] Some code cleaning before merging. bzr revid: tde@openerp.com-20130621093732-qc9ltxfiemmi421s --- addons/project/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 10288f0792b..b317091b9a9 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -588,9 +588,9 @@ class task(base_stage, osv.osv): """ Override of base_stage to add project specific behavior """ project_id = self._get_default_project_id(cr, uid, context) if project_id: - partner = self.pool.get('project.project').browse(cr, uid, project_id, context=context).partner_id - if partner: - return partner.id + project = self.pool.get('project.project').browse(cr, uid, project_id, context=context) + if project and project.partner_id: + return project.partner.id return super(task, self)._get_default_partner(cr, uid, context=context) def _get_default_project_id(self, cr, uid, context=None): -- cgit v1.2.3 From 4ee8b2836c74aaf4f3ab35af7030f548061c4235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Jun 2013 12:20:21 +0200 Subject: [FIX] Fixed last commit. bzr revid: tde@openerp.com-20130621102021-mnozkbmz11dg5k9z --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index b317091b9a9..5067e3c96c4 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -590,7 +590,7 @@ class task(base_stage, osv.osv): if project_id: project = self.pool.get('project.project').browse(cr, uid, project_id, context=context) if project and project.partner_id: - return project.partner.id + return project.partner_id.id return super(task, self)._get_default_partner(cr, uid, context=context) def _get_default_project_id(self, cr, uid, context=None): -- cgit v1.2.3 From f95572d649cc1289c6aacd53a9d5d0314542e922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 26 Jun 2013 12:37:56 +0200 Subject: [FIX] project: removed old code that was messing with followers intorduced at revision 8435. bzr revid: tde@openerp.com-20130626103756-kbbrp87gn2h5160h --- addons/project/project.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 5067e3c96c4..e541d96e526 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -1126,11 +1126,6 @@ class task(base_stage, osv.osv): def write(self, cr, uid, ids, vals, context=None): if isinstance(ids, (int, long)): ids = [ids] - if vals.get('project_id'): - project_id = self.pool.get('project.project').browse(cr, uid, vals.get('project_id'), context=context) - if project_id: - vals.setdefault('message_follower_ids', []) - vals['message_follower_ids'] += [(6, 0,[follower.id]) for follower in project_id.message_follower_ids] if vals and not 'kanban_state' in vals and 'stage_id' in vals: new_stage = vals.get('stage_id') vals_reset_kstate = dict(vals, kanban_state='normal') -- cgit v1.2.3 From 962dedda51026ef33b4d615fc4a2944a9414a692 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 17 Jun 2013 15:38:25 +0200 Subject: [FIX] project: defined the write_date field in project.task so that it can be reused in date filters in base_action_rule module bzr revid: qdp-launchpad@openerp.com-20130617133825-2rfo9z27858qalcb --- addons/project/project.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index e541d96e526..933b3c2d8fc 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -768,7 +768,8 @@ class task(base_stage, osv.osv): " * 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", readonly=True, required=False), - 'create_date': fields.datetime('Create Date', readonly=True,select=True), + '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), -- cgit v1.2.3 From 8fbfc997aebb788d79200e711389817e9ce719df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 26 Jun 2013 15:25:19 +0200 Subject: [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 --- addons/project/project.py | 214 ++++++++++++++++------------------------------ 1 file changed, 73 insertions(+), 141 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index cadc4d8afb8..738c512fe16 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -28,10 +28,8 @@ from openerp import tools from openerp.osv import fields, osv from openerp.tools.translate import _ -from openerp.addons.base_status.base_stage import base_stage from openerp.addons.resource.faces import task as Task -_TASK_STATE = [('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')] class project_task_type(osv.osv): _name = 'project.task.type' @@ -44,9 +42,6 @@ class project_task_type(osv.osv): 'case_default': fields.boolean('Default for New Projects', help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."), 'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'), - 'state': fields.selection(_TASK_STATE, 'Related Status', required=True, - help="The status of your document is automatically changed regarding the selected stage. " \ - "For example, if a stage is related to the status 'Close', when your document reaches this stage, it is automatically closed."), 'fold': fields.boolean('Folded by Default', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), } @@ -57,7 +52,6 @@ class project_task_type(osv.osv): return proj _defaults = { 'sequence': 1, - 'state': 'open', 'fold': False, 'case_default': False, 'project_ids': _get_default_project_id @@ -152,11 +146,13 @@ class project(osv.osv): cr.execute(""" SELECT project_id, COALESCE(SUM(planned_hours), 0.0), COALESCE(SUM(total_hours), 0.0), COALESCE(SUM(effective_hours), 0.0) - FROM project_task WHERE project_id IN %s AND state <> 'cancelled' + FROM project_task + LEFT JOIN project_task_type ON project_task.stage_id = project_task_type.id + WHERE project_task.project_id IN %s AND project_task_type.fold = False GROUP BY project_id """, (tuple(child_parent.keys()),)) # aggregate results into res - res = dict([(id, {'planned_hours':0.0,'total_hours':0.0,'effective_hours':0.0}) for id in ids]) + res = dict([(id, {'planned_hours':0.0, 'total_hours':0.0, 'effective_hours':0.0}) for id in ids]) for id, planned, total, effective in cr.fetchall(): # add the values specific to id to all parent projects of id in the result while id: @@ -253,22 +249,22 @@ class project(osv.osv): 'planned_hours': fields.function(_progress_rate, multi="progress", string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'effective_hours': fields.function(_progress_rate, multi="progress", string='Time Spent', help="Sum of spent hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'total_hours': fields.function(_progress_rate, multi="progress", string='Total Time', help="Sum of total hours of all tasks related to this project and its child projects.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'progress_rate': fields.function(_progress_rate, multi="progress", string='Progress', type='float', group_operator="avg", help="Percent of tasks closed according to the total of tasks todo.", store = { 'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10), - 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20), + 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20), }), 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ), 'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}), @@ -327,22 +323,16 @@ class project(osv.osv): return res def set_done(self, cr, uid, ids, context=None): - task_obj = self.pool.get('project.task') - task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', 'not in', ('cancelled', 'done'))]) - task_obj.case_close(cr, uid, task_ids, context=context) - return self.write(cr, uid, ids, {'state':'close'}, context=context) + return self.write(cr, uid, ids, {'state': 'close'}, context=context) def set_cancel(self, cr, uid, ids, context=None): - task_obj = self.pool.get('project.task') - task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', '!=', 'done')]) - task_obj.case_cancel(cr, uid, task_ids, context=context) - return self.write(cr, uid, ids, {'state':'cancelled'}, context=context) + return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context) def set_pending(self, cr, uid, ids, context=None): - return self.write(cr, uid, ids, {'state':'pending'}, context=context) + return self.write(cr, uid, ids, {'state': 'pending'}, context=context) def set_open(self, cr, uid, ids, context=None): - return self.write(cr, uid, ids, {'state':'open'}, context=context) + return self.write(cr, uid, ids, {'state': 'open'}, context=context) def reset_project(self, cr, uid, ids, context=None): return self.setActive(cr, uid, ids, value=True, context=context) @@ -459,7 +449,8 @@ class project(osv.osv): if project.user_id and (project.user_id.id not in u_ids): u_ids.append(project.user_id.id) for task in project.tasks: - if task.state in ('done','cancelled'): + # TDE: be sure about this, was if task.state in ('done','cancelled') + if task.stage_id and task.stage_id.fold: continue if task.user_id and (task.user_id.id not in u_ids): u_ids.append(task.user_id.id) @@ -525,7 +516,8 @@ def Project(): for project in projects: project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,)) for task in project.tasks: - if task.state in ('done', 'cancelled'): + # TDE CHECK: was if task.state in ('done', 'cancelled') + if task.stage_id and task.stage_id.fold: continue p = getattr(project_gantt, 'Task_%d' % (task.id,)) @@ -566,23 +558,20 @@ def Project(): vals.update(alias_model_id=model_ids[0]) return super(project, self).write(cr, uid, ids, vals, context=context) -class task(base_stage, osv.osv): + +class task(osv.osv): _name = "project.task" _description = "Task" _date_name = "date_start" _inherit = ['mail.thread', 'ir.needaction_mixin'] _track = { - 'state': { - 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj['state'] in ['new', 'draft'], - 'project.mt_task_started': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'open', - 'project.mt_task_closed': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done', - }, 'stage_id': { - 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'draft', 'done', 'open'], + 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1, + 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.stage_id.sequence != 1, }, 'kanban_state': { # kanban state: tracked, but only block subtype - 'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj['kanban_state'] == 'blocked', + 'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'blocked', }, } @@ -593,14 +582,15 @@ class task(base_stage, osv.osv): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ project_id = self._get_default_project_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], project_id, [('state', '=', 'draft')], context=context) + return self.stage_find(cr, uid, [], project_id, [('sequence', '=', '1')], context=context) def _resolve_project_id_from_context(self, cr, uid, context=None): """ Returns ID of project based on the value of 'default_project_id' context key, or None if it cannot be resolved to a single project. """ - if context is None: context = {} + if context is None: + context = {} if type(context.get('default_project_id')) in (int, long): return context['default_project_id'] if isinstance(context.get('default_project_id'), basestring): @@ -669,7 +659,8 @@ class task(base_stage, osv.osv): res[task.id]['progress'] = 0.0 if (task.remaining_hours + hours.get(task.id, 0.0)): res[task.id]['progress'] = round(min(100.0 * hours.get(task.id, 0.0) / res[task.id]['total_hours'], 99.99),2) - if task.state in ('done','cancelled'): + # TDE CHECK: if task.state in ('done','cancelled'): + if task.stage_id and task.stage_id.fold: res[task.id]['progress'] = 100.0 return res @@ -690,6 +681,13 @@ class task(base_stage, osv.osv): return {'value':{'partner_id':partner_id.id}} return {} + def onchange_user_id(self, cr, uid, ids, user_id, context=None): + vals = {} + if user_id: + vals['date_start'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) + vals['date_end'] = False + return {'value': vals} + def duplicate_task(self, cr, uid, map_ids, context=None): for new in map_ids.values(): task = self.browse(cr, uid, new, context) @@ -743,17 +741,12 @@ class task(base_stage, osv.osv): 'active': fields.function(_is_template, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."), 'name': fields.char('Task Summary', size=128, required=True, select=True), 'description': fields.text('Description'), - 'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True), + 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), + ('1', 'Important'), ('0', 'Very important')], + string='Priority', select=True), 'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."), 'stage_id': fields.many2one('project.task.type', 'Stage', track_visibility='onchange', domain="[('project_ids', '=', project_id)]"), - 'state': fields.related('stage_id', 'state', type="selection", store=True, - selection=_TASK_STATE, string="Status", readonly=True, - help='The status is set to \'Draft\', when a case is created.\ - If the case is in progress the status is set to \'Open\'.\ - When the case is over, the status is set to \'Done\'.\ - If the case needs to be reviewed then the status is \ - set to \'Pending\'.'), 'categ_ids': fields.many2many('project.category', string='Tags'), 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State', track_visibility='onchange', @@ -766,6 +759,7 @@ class task(base_stage, osv.osv): 'date_start': fields.datetime('Starting Date',select=True), 'date_end': fields.datetime('Ending Date',select=True), 'date_deadline': fields.date('Deadline',select=True), + 'date_last_stage_update': fields.datetime('Last Stage Update', select=True), 'project_id': fields.many2one('project.project', 'Project', ondelete='set null', select="1", track_visibility='onchange'), 'parent_ids': fields.many2many('project.task', 'project_task_parent_rel', 'task_id', 'parent_id', 'Parent Tasks'), 'child_ids': fields.many2many('project.task', 'project_task_parent_rel', 'parent_id', 'task_id', 'Delegated Tasks'), @@ -782,7 +776,7 @@ class task(base_stage, osv.osv): 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), - 'progress': fields.function(_hours_get, string='Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time", + 'progress': fields.function(_hours_get, string='Working Time Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time", store = { 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours','state'], 10), 'project.task.work': (_get_task, ['hours'], 10), @@ -805,6 +799,7 @@ class task(base_stage, osv.osv): _defaults = { 'stage_id': _get_default_stage_id, 'project_id': _get_default_project_id, + 'date_last_stage_update': lambda *a: fields.datetime.now(), 'kanban_state': 'normal', 'priority': '2', 'progress': 0, @@ -931,10 +926,11 @@ class task(base_stage, osv.osv): section_ids.append(task.project_id.id) search_domain = [] if section_ids: - search_domain = [('|')] * (len(section_ids)-1) + search_domain = [('|')] * (len(section_ids) - 1) for section_id in section_ids: search_domain.append(('project_ids', '=', section_id)) - search_domain += list(domain) + if domain: + search_domain += list(domain) # perform search, return the first found stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context) if stage_ids: @@ -948,82 +944,11 @@ class task(base_stage, osv.osv): for task in tasks: if task.child_ids: for child in task.child_ids: - if child.state in ['draft', 'open', 'pending']: + # TDE CHECK: was 'if child.state in ['draft', 'open', 'pending']'' + if child.stage_id and not child.stage_id.fold: raise osv.except_osv(_("Warning!"), _("Child task still open.\nPlease cancel or complete child task first.")) return True - def action_close(self, cr, uid, ids, context=None): - """ This action closes the task - """ - task_id = len(ids) and ids[0] or False - self._check_child_task(cr, uid, ids, context=context) - if not task_id: return False - return self.do_close(cr, uid, [task_id], context=context) - - def do_close(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_close. """ - return self.case_close(cr, uid, ids, context=context) - - def case_close(self, cr, uid, ids, context=None): - """ Closes Task """ - if not isinstance(ids, list): ids = [ids] - for task in self.browse(cr, uid, ids, context=context): - vals = {} - project = task.project_id - for parent_id in task.parent_ids: - if parent_id.state in ('pending','draft'): - reopen = True - for child in parent_id.child_ids: - if child.id != task.id and child.state not in ('done','cancelled'): - reopen = False - if reopen: - self.do_reopen(cr, uid, [parent_id.id], context=context) - # close task - vals['remaining_hours'] = 0.0 - if not task.date_end: - vals['date_end'] = fields.datetime.now() - self.case_set(cr, uid, [task.id], 'done', vals, context=context) - return True - - def do_reopen(self, cr, uid, ids, context=None): - for task in self.browse(cr, uid, ids, context=context): - project = task.project_id - self.case_set(cr, uid, [task.id], 'open', {}, context=context) - return True - - def do_cancel(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_cancel. """ - return self.case_cancel(cr, uid, ids, context=context) - - def case_cancel(self, cr, uid, ids, context=None): - tasks = self.browse(cr, uid, ids, context=context) - self._check_child_task(cr, uid, ids, context=context) - for task in tasks: - self.case_set(cr, uid, [task.id], 'cancelled', {'remaining_hours': 0.0}, context=context) - return True - - def do_open(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_open. """ - return self.case_open(cr, uid, ids, context=context) - - def case_open(self, cr, uid, ids, context=None): - if not isinstance(ids,list): ids = [ids] - return self.case_set(cr, uid, ids, 'open', {'date_start': fields.datetime.now()}, context=context) - - def do_draft(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_draft. """ - return self.case_draft(cr, uid, ids, context=context) - - def case_draft(self, cr, uid, ids, context=None): - return self.case_set(cr, uid, ids, 'draft', {}, context=context) - - def do_pending(self, cr, uid, ids, context=None): - """ Compatibility when changing to case_pending. """ - return self.case_pending(cr, uid, ids, context=context) - - def case_pending(self, cr, uid, ids, context=None): - return self.case_set(cr, uid, ids, 'pending', {}, context=context) - def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None): attachment = self.pool.get('ir.attachment') attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', task_id)], context=context) @@ -1044,6 +969,7 @@ class task(base_stage, osv.osv): delegated_task_id = self.copy(cr, uid, task.id, { 'name': delegate_data['name'], 'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False, + 'stage_id': delegate_data.get('stage_id', [False])[0], 'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False, 'planned_hours': delegate_data['planned_hours'] or 0.0, 'parent_ids': [(6, 0, [task.id])], @@ -1058,16 +984,13 @@ class task(base_stage, osv.osv): 'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0), 'name': newname, }, context=context) - if delegate_data['state'] == 'pending': - self.do_pending(cr, uid, [task.id], context=context) - elif delegate_data['state'] == 'done': - self.do_close(cr, uid, [task.id], context=context) delegated_tasks[task.id] = delegated_task_id return delegated_tasks def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None): for task in self.browse(cr, uid, ids, context=context): - if (task.state=='draft') or (task.planned_hours==0.0): + # TDE CHECK: was (task.state=='draft') + if (task.stage_id and task.stage_id.sequence == 1) or (task.planned_hours == 0.0): self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context) self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context) return True @@ -1102,50 +1025,57 @@ class task(base_stage, osv.osv): 'planned_hours': task.planned_hours, 'kanban_state': task.kanban_state, 'type_id': task.stage_id.id, - 'state': task.state, 'user_id': task.user_id.id }, context=context) return True + # ------------------------------------------------ + # CRUD overrides + # ------------------------------------------------ + def create(self, cr, uid, vals, context=None): if context is None: context = {} + # user_id change: update date_start + if vals.get('user_id'): + vals['date_start'] = fields.datetime.now() + # generate a default stage based on context / given project value if not vals.get('stage_id'): ctx = context.copy() if vals.get('project_id'): ctx['default_project_id'] = vals['project_id'] vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx) + # context: no_log, because subtype already handle this create_context = dict(context, mail_create_nolog=True) task_id = super(task, self).create(cr, uid, vals, context=create_context) self._store_history(cr, uid, [task_id], context=context) return task_id - # Overridden to reset the kanban_state to normal whenever - # the stage (stage_id) of the task changes. def write(self, cr, uid, ids, vals, context=None): if isinstance(ids, (int, long)): ids = [ids] - if vals.get('project_id'): - project_id = self.pool.get('project.project').browse(cr, uid, vals.get('project_id'), context=context) - if project_id: - vals.setdefault('message_follower_ids', []) - vals['message_follower_ids'] += [(6, 0,[follower.id]) for follower in project_id.message_follower_ids] + # stage change: update date_last_stage_update + if 'stage_id' in vals: + vals['date_last_stage_update'] = fields.datetime.now() + # user_id change: update date_start + if vals.get('user_id'): + vals['date_start'] = fields.datetime.now() + + # Overridden to reset the kanban_state to normal whenever + # the stage (stage_id) of the task changes. if vals and not 'kanban_state' in vals and 'stage_id' in vals: new_stage = vals.get('stage_id') vals_reset_kstate = dict(vals, kanban_state='normal') for t in self.browse(cr, uid, ids, context=context): - #TO FIX:Kanban view doesn't raise warning - #stages = [stage.id for stage in t.project_id.type_ids] - #if new_stage not in stages: - #raise osv.except_osv(_('Warning!'), _('Stage is not defined in the project.')) write_vals = vals_reset_kstate if t.stage_id != new_stage else vals super(task, self).write(cr, uid, [t.id], write_vals, context=context) result = True else: result = super(task, self).write(cr, uid, ids, vals, context=context) - if ('stage_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals): + + if any(item in vals for item in ['stage_id', 'remaining_hours', 'user_id', 'kanban_state']): self._store_history(cr, uid, ids, context=context) return result @@ -1161,7 +1091,8 @@ class task(base_stage, osv.osv): result = "" ident = ' '*ident for task in tasks: - if task.state in ('done','cancelled'): + # TDE CHECK: if task.state in ('done','cancelled'): + if task.stage_id and task.stage_id.fold: continue result += ''' %sdef Task_%s(): @@ -1231,13 +1162,14 @@ class task(base_stage, osv.osv): update_vals[field] = float(res.group(2).lower()) except (ValueError, TypeError): pass - elif match.lower() == 'state' \ - and res.group(2).lower() in ['cancel','close','draft','open','pending']: - act = 'do_%s' % res.group(2).lower() + # elif match.lower() == 'state' \ + # and res.group(2).lower() in ['cancel','close','draft','open','pending']: + # act = 'do_%s' % res.group(2).lower() if act: getattr(self,act)(cr, uid, ids, context=context) return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) + # TDE NOTE: FIXME def project_task_reevaluate(self, cr, uid, ids, context=None): if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'): return { -- cgit v1.2.3 From 9e17dd58d819d00fa6c00d7f28355d6c1ba94d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 26 Jun 2013 16:22:42 +0200 Subject: [FIX] project: fixed various report views + some filters. bzr revid: tde@openerp.com-20130626142242-aztr40zazsl20eif --- addons/project/project.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 738c512fe16..2e6e351fefb 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -1301,7 +1301,7 @@ class project_task_history(osv.osv): def _get_date(self, cr, uid, ids, name, arg, context=None): result = {} for history in self.browse(cr, uid, ids, context=context): - if history.state in ('done','cancelled'): + if history.type_id and history.type_id.fold: result[history.id] = history.date continue cr.execute('''select @@ -1335,14 +1335,13 @@ class project_task_history(osv.osv): _columns = { 'task_id': fields.many2one('project.task', 'Task', ondelete='cascade', required=True, select=True), 'type_id': fields.many2one('project.task.type', 'Stage'), - 'state': fields.selection([('draft', 'New'), ('cancelled', 'Cancelled'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done')], 'Status'), - 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State', required=False), + 'kanban_state': fields.selection([('normal', 'Normal'), ('blocked', 'Blocked'), ('done', 'Ready for next stage')], 'Kanban State', required=False), 'date': fields.date('Date', select=True), 'end_date': fields.function(_get_date, string='End Date', type="date", store={ 'project.task.history': (_get_related_date, None, 20) }), - 'remaining_hours': fields.float('Remaining Time', digits=(16,2)), - 'planned_hours': fields.float('Planned Time', digits=(16,2)), + 'remaining_hours': fields.float('Remaining Time', digits=(16, 2)), + 'planned_hours': fields.float('Planned Time', digits=(16, 2)), 'user_id': fields.many2one('res.users', 'Responsible'), } _defaults = { @@ -1372,7 +1371,7 @@ class project_task_history_cumulative(osv.osv): SELECT h.id AS history_id, h.date+generate_series(0, CAST((coalesce(h.end_date, DATE 'tomorrow')::date - h.date) AS integer)-1) AS date, - h.task_id, h.type_id, h.user_id, h.kanban_state, h.state, + h.task_id, h.type_id, h.user_id, h.kanban_state, greatest(h.remaining_hours, 1) AS remaining_hours, greatest(h.planned_hours, 1) AS planned_hours, t.project_id FROM -- cgit v1.2.3 From bf4ada34b4e6bc9793f4870786d579d9dce4c799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 27 Jun 2013 16:46:47 +0200 Subject: [REF] mail_thread: message_track now uses browse records instead of read results. Updated addons accordingly. Updated tests to test corner cases using False / null browse records. bzr revid: tde@openerp.com-20130627144647-swbj77i84vo9ii0v --- addons/project/project.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index cadc4d8afb8..587d60ff86f 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -574,15 +574,15 @@ class task(base_stage, osv.osv): _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', + 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.state in ['new', 'draft'], + 'project.mt_task_started': lambda self, cr, uid, obj, ctx=None: obj.state == 'open', + 'project.mt_task_closed': lambda self, cr, uid, obj, ctx=None: obj.state == 'done', }, 'stage_id': { - 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'draft', 'done', 'open'], + 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.state not in ['new', 'draft', 'done', 'open'], }, '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', }, } -- cgit v1.2.3 From 6310275541f07446e937b58f86e7a7f0cbc78e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 9 Jul 2013 15:38:59 +0200 Subject: [FIX] project, project_issue: fixed get_default_partner not defined anymore, because of the inheritance towards base_stage removal. bzr revid: tde@openerp.com-20130709133859-jy4aqz6tsrtsqv81 --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 32841cde927..3f80a075da9 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -582,7 +582,7 @@ class task(osv.osv): project = self.pool.get('project.project').browse(cr, uid, project_id, context=context) if project and project.partner_id: return project.partner_id.id - return super(task, self)._get_default_partner(cr, uid, context=context) + return False def _get_default_project_id(self, cr, uid, context=None): """ Gives default section by checking if present in the context """ -- cgit v1.2.3 From 4b0baa3615aee3e528ccef0b60142ba7acb7976f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 10 Jul 2013 14:25:26 +0200 Subject: [CLEAN] project, project_issue, project_mrp: misc cleaning of code + fixed bug in project_mrp + re-added commentred tests in project_mrp bzr revid: tde@openerp.com-20130710122526-tf87avul7huqgigg --- addons/project/project.py | 54 ++++++++++------------------------------------- 1 file changed, 11 insertions(+), 43 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 3f80a075da9..7128b188432 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -25,11 +25,10 @@ import time from openerp import SUPERUSER_ID from openerp import tools +from openerp.addons.resource.faces import task as Task from openerp.osv import fields, osv from openerp.tools.translate import _ -from openerp.addons.resource.faces import task as Task - class project_task_type(osv.osv): _name = 'project.task.type' @@ -319,8 +318,7 @@ class project(osv.osv): ] def set_template(self, cr, uid, ids, context=None): - res = self.setActive(cr, uid, ids, value=False, context=context) - return res + return self.setActive(cr, uid, ids, value=False, context=context) def set_done(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'close'}, context=context) @@ -449,7 +447,6 @@ class project(osv.osv): if project.user_id and (project.user_id.id not in u_ids): u_ids.append(project.user_id.id) for task in project.tasks: - # TDE: be sure about this, was if task.state in ('done','cancelled') if task.stage_id and task.stage_id.fold: continue if task.user_id and (task.user_id.id not in u_ids): @@ -516,7 +513,6 @@ def Project(): for project in projects: project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,)) for task in project.tasks: - # TDE CHECK: was if task.state in ('done', 'cancelled') if task.stage_id and task.stage_id.fold: continue @@ -532,10 +528,6 @@ def Project(): }, context=context) return True - # ------------------------------------------------ - # OpenChatter methods and notifications - # ------------------------------------------------ - def create(self, cr, uid, vals, context=None): if context is None: context = {} @@ -570,6 +562,9 @@ class task(osv.osv): '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, }, + 'user_id': { + 'project.mt_task_assigned': lambda self, cr, uid, obj, ctx=None: obj.user_id and obj.user_id.id, + }, 'kanban_state': { # kanban state: tracked, but only block subtype 'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'blocked', }, @@ -675,11 +670,11 @@ class task(osv.osv): def onchange_remaining(self, cr, uid, ids, remaining=0.0, planned=0.0): if remaining and not planned: - return {'value':{'planned_hours': remaining}} + return {'value': {'planned_hours': remaining}} return {} def onchange_planned(self, cr, uid, ids, planned=0.0, effective=0.0): - return {'value':{'remaining_hours': planned - effective}} + return {'value': {'remaining_hours': planned - effective}} def onchange_project(self, cr, uid, id, project_id, context=None): if project_id: @@ -691,7 +686,7 @@ class task(osv.osv): 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_start'] = fields.datetime.now() vals['date_end'] = False return {'value': vals} @@ -748,9 +743,7 @@ class task(osv.osv): 'active': fields.function(_is_template, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."), 'name': fields.char('Task Summary', size=128, required=True, select=True), 'description': fields.text('Description'), - 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), - ('1', 'Important'), ('0', 'Very important')], - string='Priority', select=True), + 'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True), 'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."), 'stage_id': fields.many2one('project.task.type', 'Stage', track_visibility='onchange', domain="[('project_ids', '=', project_id)]"), @@ -937,8 +930,7 @@ class task(osv.osv): search_domain = [('|')] * (len(section_ids) - 1) for section_id in section_ids: search_domain.append(('project_ids', '=', section_id)) - if domain: - search_domain += list(domain) + search_domain += list(domain) # perform search, return the first found stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context) if stage_ids: @@ -952,7 +944,6 @@ class task(osv.osv): for task in tasks: if task.child_ids: for child in task.child_ids: - # TDE CHECK: was 'if child.state in ['draft', 'open', 'pending']'' if child.stage_id and not child.stage_id.fold: raise osv.except_osv(_("Warning!"), _("Child task still open.\nPlease cancel or complete child task first.")) return True @@ -977,7 +968,7 @@ class task(osv.osv): delegated_task_id = self.copy(cr, uid, task.id, { 'name': delegate_data['name'], 'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False, - 'stage_id': delegate_data.get('stage_id', [False])[0], + 'stage_id': delegate_data.get('stage_id') and delegate_data.get('stage_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, 'parent_ids': [(6, 0, [task.id])], @@ -997,7 +988,6 @@ class task(osv.osv): def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None): for task in self.browse(cr, uid, ids, context=context): - # TDE CHECK: was (task.state=='draft') if (task.stage_id and task.stage_id.sequence == 1) or (task.planned_hours == 0.0): self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context) self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context) @@ -1052,12 +1042,6 @@ class task(osv.osv): # user_id change: update date_start if vals.get('user_id'): vals['date_start'] = fields.datetime.now() - # generate a default stage based on context / given project value - if not vals.get('stage_id'): - ctx = context.copy() - if vals.get('project_id'): - ctx['default_project_id'] = vals['project_id'] - vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx) # context: no_log, because subtype already handle this create_context = dict(context, mail_create_nolog=True) @@ -1104,7 +1088,6 @@ class task(osv.osv): result = "" ident = ' '*ident for task in tasks: - # TDE CHECK: if task.state in ('done','cancelled'): if task.stage_id and task.stage_id.fold: continue result += ''' @@ -1175,25 +1158,10 @@ class task(osv.osv): update_vals[field] = float(res.group(2).lower()) except (ValueError, TypeError): pass - # elif match.lower() == 'state' \ - # and res.group(2).lower() in ['cancel','close','draft','open','pending']: - # act = 'do_%s' % res.group(2).lower() if act: getattr(self,act)(cr, uid, ids, context=context) return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) - # TDE NOTE: FIXME - def project_task_reevaluate(self, cr, uid, ids, context=None): - if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'): - return { - 'view_type': 'form', - "view_mode": 'form', - 'res_model': 'project.task.reevaluate', - 'type': 'ir.actions.act_window', - 'target': 'new', - } - return self.do_reopen(cr, uid, ids, context=context) - class project_work(osv.osv): _name = "project.task.work" _description = "Project Task Work" -- cgit v1.2.3 From 85b1d336e38d926789e4569ceafb991bb494bb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 19 Jul 2013 11:00:58 +0200 Subject: [CLEAN] project: misc cleaning before merging bzr revid: tde@openerp.com-20130719090058-wngpyzf7oz3rnftp --- addons/project/project.py | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 7128b188432..59f4a806cbd 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -44,26 +44,15 @@ class project_task_type(osv.osv): '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."), } - def _get_default_project_id(self, cr, uid, ctx={}): - proj = ctx.get('default_project_id', False) - if type(proj) is int: - return [proj] - return proj + _defaults = { 'sequence': 1, 'fold': False, 'case_default': False, - 'project_ids': _get_default_project_id + 'project_ids': lambda self, cr, uid, ctx=None: self.pool['project.project']._get_default_project_id(cr, uid, context=ctx), } _order = 'sequence' -def short_name(name): - """Keep first word(s) of name to make it small enough - but distinctive""" - if not name: return name - # keep 7 chars + end of the last word - keep_words = name[:7].strip().split() - return ' '.join(name.split()[:len(keep_words)]) class project(osv.osv): _name = "project.project" @@ -92,9 +81,9 @@ class project(osv.osv): def onchange_partner_id(self, cr, uid, ids, part=False, context=None): partner_obj = self.pool.get('res.partner') - if not part: - return {'value':{}} val = {} + if not part: + return {'value': val} if 'pricelist_id' in self.fields_get(cr, uid, context=context): pricelist = partner_obj.read(cr, uid, part, ['property_product_pricelist'], context=context) pricelist_id = pricelist.get('property_product_pricelist', False) and pricelist.get('property_product_pricelist')[0] or False @@ -447,8 +436,6 @@ class project(osv.osv): if project.user_id and (project.user_id.id not in u_ids): u_ids.append(project.user_id.id) for task in project.tasks: - if task.stage_id and task.stage_id.fold: - continue if task.user_id and (task.user_id.id not in u_ids): u_ids.append(task.user_id.id) calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False @@ -533,7 +520,8 @@ def Project(): context = {} # Prevent double project creation when 'use_tasks' is checked + alias management create_context = dict(context, project_creation_in_progress=True, - alias_model_name=vals.get('alias_model', 'project.task'), alias_parent_model_name=self._name) + alias_model_name=vals.get('alias_model', 'project.task'), + alias_parent_model_name=self._name) if vals.get('type', False) not in ('template', 'contract'): vals['type'] = 'contract' @@ -565,7 +553,7 @@ class task(osv.osv): 'user_id': { 'project.mt_task_assigned': lambda self, cr, uid, obj, ctx=None: obj.user_id and obj.user_id.id, }, - 'kanban_state': { # kanban state: tracked, but only block subtype + 'kanban_state': { 'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'blocked', }, } @@ -687,7 +675,6 @@ class task(osv.osv): vals = {} if user_id: vals['date_start'] = fields.datetime.now() - vals['date_end'] = False return {'value': vals} def duplicate_task(self, cr, uid, map_ids, context=None): -- cgit v1.2.3 From 573220c2864d718ce07ee1adef1698c7108fcb6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 19 Jul 2013 11:17:33 +0200 Subject: [FIX] project: fixed last commit bzr revid: tde@openerp.com-20130719091733-awl83dlr56fih8wh --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index 59f4a806cbd..c8b900c9e84 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -49,7 +49,7 @@ class project_task_type(osv.osv): 'sequence': 1, 'fold': False, 'case_default': False, - 'project_ids': lambda self, cr, uid, ctx=None: self.pool['project.project']._get_default_project_id(cr, uid, context=ctx), + 'project_ids': lambda self, cr, uid, ctx=None: self.pool['project.task']._get_default_project_id(cr, uid, context=ctx), } _order = 'sequence' -- cgit v1.2.3 From c63c20e0667bcba22bb6b80b613a7b4e366b472b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 19 Jul 2013 12:04:11 +0200 Subject: [REM] Removed base_stage. One last part of 'generic case management' goes away from OpenERP. bzr revid: tde@openerp.com-20130719100411-59dx6c7wi6n3gf00 --- addons/project/project.py | 1 - 1 file changed, 1 deletion(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index c8b900c9e84..edcdcb78a1e 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -559,7 +559,6 @@ class task(osv.osv): } def _get_default_partner(self, cr, uid, context=None): - """ Override of base_stage to add project specific behavior """ project_id = self._get_default_project_id(cr, uid, context) if project_id: project = self.pool.get('project.project').browse(cr, uid, project_id, context=context) -- cgit v1.2.3 From e0e3d985573e0b21c1e5affa57c89d75eb6ef351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 23 Jul 2013 16:45:07 +0200 Subject: [IMP] mail: refactored check_mail_message_access bzr revid: tde@openerp.com-20130723144507-bwwegheqofs7x1ox --- addons/project/project.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'addons/project/project.py') diff --git a/addons/project/project.py b/addons/project/project.py index c8b900c9e84..d09e3476a96 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -545,6 +545,7 @@ class task(osv.osv): _date_name = "date_start" _inherit = ['mail.thread', 'ir.needaction_mixin'] + _mail_post_access = 'read' _track = { 'stage_id': { 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1, @@ -1106,17 +1107,6 @@ class task(osv.osv): return [task.project_id.message_get_reply_to()[0] if task.project_id else False for task in self.browse(cr, uid, ids, context=context)] - def check_mail_message_access(self, cr, uid, mids, operation, model_obj=None, context=None): - """ mail.message document permission rule: can post a new message if can read - because of portal document. """ - if not model_obj: - model_obj = self - if operation == 'create': - model_obj.check_access_rights(cr, uid, 'read') - model_obj.check_access_rule(cr, uid, mids, 'read', context=context) - else: - return super(task, self).check_mail_message_access(cr, uid, mids, operation, model_obj=model_obj, context=context) - def message_new(self, cr, uid, msg, custom_values=None, context=None): """ Override to updates the document according to the email. """ if custom_values is None: custom_values = {} -- cgit v1.2.3