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