From 94051b9812f444add364621a117cd74ec68ad2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 13 Mar 2012 13:23:51 +0100 Subject: [PATCH 01/43] [ADD] base_needaction file, holding the base.needaction mixin class. bzr revid: tde@openerp.com-20120313122351-fw8e4gk3zuhaqr18 --- openerp/addons/base/base_needaction.py | 67 ++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 openerp/addons/base/base_needaction.py diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py new file mode 100644 index 00000000000..b9dd9c65826 --- /dev/null +++ b/openerp/addons/base/base_needaction.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2009-Today OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see +# +############################################################################## + +from osv import osv, fields +from tools.translate import _ + +class base_needaction(osv.osv): + '''Mixin class for object implementing the need action mechanism. + + Need action mechanism can be used by objects that have to be able to + signal that an action is required on a particular record. If in the + business logic an action must be performed by somebody, for instance + validation by a manager, this mechanism allows to set a field with + the user_id of the user requested to perform the action. + + Technically, this class adds a need_action_user_id field; when + set to false, no action is required; when an user_id is set, + this user has an action to perform. This field is a function field. + Setting an user_id is done through redefining the get_needaction_user_id method. + Therefore by redefining only one method, you can specify + the cases in which an action will be required on a particular record. + + This mechanism is used for instance to display the number of pending actions + in menus, such as Leads (12). + ''' + _name = 'base.needaction' + _description = 'Need action mechanism' + + def get_needaction_user_id(self, cr, uid, ids, name, arg, context=None): + if context is None: + context = {} + result = {} + for id in ids: + result[id] = False + return result + + ''' Wrapper: in 6.1 the reference to a method is given to a function + field, not the function name. Inheritance is therefore not directly + possible.''' + def get_needaction_user_id_wrapper(self, cr, uid, ids, name, arg, context=None): + return self.get_needaction_user_id(cr, uid, ids, name, arg, context=context) + + _columns = { + 'need_action_user_id': fields.function(get_needaction_user_id_wrapper, + type='many2one', relation='res.users', store=True, + select=1, string='User'), + } + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 059cc5bef3a4eb60768be9f9a750a468b87d57a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 13 Mar 2012 13:29:39 +0100 Subject: [PATCH 02/43] [ADD] Added documentation for merge proposal, related to the need_action mixin class. bzr revid: tde@openerp.com-20120313122939-239ae3ftask1rrmb --- doc/api/need_action_specs.rst | 8 ++++++++ doc/index.rst.inc | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 doc/api/need_action_specs.rst diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst new file mode 100644 index 00000000000..5d5d94cf903 --- /dev/null +++ b/doc/api/need_action_specs.rst @@ -0,0 +1,8 @@ +Need action mixin class +======================= + +This revision adds a mixin class for object implementing the need action mechanism. Need action mechanism can be used by objects that have to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance validation by a manager, this mechanism allows to set a field with the user_id of the user requested to perform the action. + +Technically, this class adds a need_action_user_id field; when set to false, no action is required; when an user_id is set, this user has an action to perform. This field is a function field. Setting an user_id is done through redefining the get_needaction_user_id method. Therefore by redefining only one method, you can specify the cases in which an action will be required on a particular record. + +This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12). diff --git a/doc/index.rst.inc b/doc/index.rst.inc index 05c4a53640b..f6c4f6dbf20 100644 --- a/doc/index.rst.inc +++ b/doc/index.rst.inc @@ -6,3 +6,11 @@ OpenERP Server :maxdepth: 1 test-framework + +New feature merges +++++++++++++++++++ + +.. toctree:: + :maxdepth: 1 + + api/need_action_specs From dbd4f6dfcee98442b41fe53d10f303cc73daadd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 13 Mar 2012 16:53:39 +0100 Subject: [PATCH 03/43] [FIX] Added base_needaction import bzr revid: tde@openerp.com-20120313155339-eqifoe0celu5n43b --- openerp/addons/base/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/__init__.py b/openerp/addons/base/__init__.py index 16a61521fb4..af551e60c1e 100644 --- a/openerp/addons/base/__init__.py +++ b/openerp/addons/base/__init__.py @@ -25,6 +25,7 @@ import res import publisher_warranty import report import test +import base_needaction # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 5ef1483f933d18fe5af55ed2ff6bda9872a7b15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 13 Mar 2012 16:54:25 +0100 Subject: [PATCH 04/43] [IMP] base.needaction: clened code bzr revid: tde@openerp.com-20120313155425-vkmzmobas76re0x4 --- openerp/addons/base/base_needaction.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index b9dd9c65826..eb953125cd4 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -45,11 +45,7 @@ class base_needaction(osv.osv): _description = 'Need action mechanism' def get_needaction_user_id(self, cr, uid, ids, name, arg, context=None): - if context is None: - context = {} - result = {} - for id in ids: - result[id] = False + result = dict.fromkeys[ids, False] return result ''' Wrapper: in 6.1 the reference to a method is given to a function From bf3d2cd284a2f2f7309bc14ff2945c03c237af40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 14 Mar 2012 15:26:05 +0100 Subject: [PATCH 05/43] [REF] Refactored base_needaction class. bzr revid: tde@openerp.com-20120314142605-hhii6p976zrdwmw3 --- openerp/addons/base/base_needaction.py | 108 ++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 11 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index eb953125cd4..20f32c947c2 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -22,6 +22,29 @@ from osv import osv, fields from tools.translate import _ +class base_needaction_users_rel(osv.osv): + ''' + base_needaction_users_rel holds the data related to the needaction + mechanism inside OpenERP. A needaction is characterized by: + - res_model: model of the followed objects + - res_id: ID of resource + - user_id: foreign key to the res.users table, to the user that + has to perform an action + ''' + + _name = 'base.needaction_users_rel' + _rec_name = 'id' + _order = 'res_model asc' + _columns = { + 'res_model': fields.char('Related Document Model', size=128, + select=1, required=True), + 'res_id': fields.integer('Related Document ID', + select=1, required=True), + 'user_id': fields.many2one('res.users', string='Related User ID', + ondelete='cascade', select=1, required=True), + } + + class base_needaction(osv.osv): '''Mixin class for object implementing the need action mechanism. @@ -44,20 +67,83 @@ class base_needaction(osv.osv): _name = 'base.needaction' _description = 'Need action mechanism' - def get_needaction_user_id(self, cr, uid, ids, name, arg, context=None): - result = dict.fromkeys[ids, False] - return result + #------------------------------------------------------ + # base_needaction_users_rel API + #------------------------------------------------------ + + def needaction_create(self, cr, uid, ids, user_ids, context=None): + if context is None: + context = {} + needact_rel_obj = self.pool.get('base.needaction_users_rel') + for id in ids: + for user_id in user_ids: + needact_rel_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) + return True + + def needaction_unlink_users(self, cr, uid, ids, context=None): + if context is None: + context = {} + needact_rel_obj = self.pool.get('base.needaction_users_rel') + to_del_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + return needact_rel_obj.unlink(cr, uid, to_del_ids, context=context) + + def needaction_write_users(self, cr, uid, ids, user_ids, context=None): + if context is None: + context = {} + # unlink old records + self.needaction_unlink_users(cr, uid, ids, context=context) + # link new records + for res_id in ids: + self.needaction_create(cr, uid, ids, user_ids, context=context) + return True + + #------------------------------------------------------ + # Addon API + #------------------------------------------------------ - ''' Wrapper: in 6.1 the reference to a method is given to a function - field, not the function name. Inheritance is therefore not directly - possible.''' - def get_needaction_user_id_wrapper(self, cr, uid, ids, name, arg, context=None): - return self.get_needaction_user_id(cr, uid, ids, name, arg, context=context) + def get_needaction_user_ids(self, cr, uid, ids, context=None): + needact_rel_obj = self.pool.get('base.needaction_users_rel') + needact_rel_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + needact_rel_objs = needact_rel_obj.read(cr, uid, needact_rel_ids, ['user_id'], context=context) + return [needact_rel_obj['user_id'][0] for needact_rel_obj in needact_rel_objs] + + def set_needaction_user_ids(self, cr, uid, ids, context=None): + result = dict.fromkeys(ids, []) + return result + + def write(self, cr, uid, ids, values, context=None): + if context is None: + context = {} + # get and update needaction_user_ids + needaction_user_ids = self.set_needaction_user_ids(cr, uid, ids, context=context) + for id in ids: + self.needaction_write_users(cr, uid, [id], needaction_user_ids[id], context=context) + # perform write + return super(base_needaction, self).write(cr, uid, ids, values, context=context) _columns = { - 'need_action_user_id': fields.function(get_needaction_user_id_wrapper, - type='many2one', relation='res.users', store=True, - select=1, string='User'), } + + + #------------------------------------------------------ + # General API + #------------------------------------------------------ + + def get_user_needaction_ids(self, cr, uid, user_id, offset=0, limit=None, order=None, count=False, context=None): + if context is None: + context = {} + needact_rel_obj = self.pool.get('base.needaction_users_rel') + search_res = needact_rel_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, count=count, context=context) + return search_res + + def get_record_references(self, cr, uid, user_id, offset=0, limit=None, order=None, context=None): + if context is None: + context = {} + needact_rel_obj = self.pool.get('base.needaction_users_rel') + search_res = self.get_user_needaction_ids(cr, uid, user_id, offset=offset, limit=limit, order=order, context=context) + needact_objs = needact_rel_obj.browse(cr, uid, search_res, context=context) + record_references = [(needact_obj.res_model, needact_obj.res_id) for needact_obj in needact_objs] + return record_references + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 0aa3125ce77db964cebd45bd2f7ab740cbabbdd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 14 Mar 2012 18:14:46 +0100 Subject: [PATCH 06/43] [IMP] Cleaned code bzr revid: tde@openerp.com-20120314171446-75rf519voc4hwuw7 --- openerp/addons/base/base_needaction.py | 57 +++++++++++++++----------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 20f32c947c2..68f8d27b017 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -67,11 +67,14 @@ class base_needaction(osv.osv): _name = 'base.needaction' _description = 'Need action mechanism' + _columns = { + } + #------------------------------------------------------ - # base_needaction_users_rel API + # need action relationship management #------------------------------------------------------ - def needaction_create(self, cr, uid, ids, user_ids, context=None): + def _link_users(self, cr, uid, ids, user_ids, context=None): if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') @@ -80,68 +83,76 @@ class base_needaction(osv.osv): needact_rel_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) return True - def needaction_unlink_users(self, cr, uid, ids, context=None): + def _unlink_users(self, cr, uid, ids, context=None): if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') to_del_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) return needact_rel_obj.unlink(cr, uid, to_del_ids, context=context) - def needaction_write_users(self, cr, uid, ids, user_ids, context=None): + def _update_users(self, cr, uid, ids, user_ids, context=None): if context is None: context = {} # unlink old records - self.needaction_unlink_users(cr, uid, ids, context=context) + self._unlink_users(cr, uid, ids, context=context) # link new records for res_id in ids: - self.needaction_create(cr, uid, ids, user_ids, context=context) + self._link_users(cr, uid, ids, user_ids, context=context) return True #------------------------------------------------------ # Addon API #------------------------------------------------------ - - def get_needaction_user_ids(self, cr, uid, ids, context=None): - needact_rel_obj = self.pool.get('base.needaction_users_rel') - needact_rel_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) - needact_rel_objs = needact_rel_obj.read(cr, uid, needact_rel_ids, ['user_id'], context=context) - return [needact_rel_obj['user_id'][0] for needact_rel_obj in needact_rel_objs] - def set_needaction_user_ids(self, cr, uid, ids, context=None): + def get_needaction_user_ids(self, cr, uid, ids, context=None): result = dict.fromkeys(ids, []) return result + def create(self, cr, uid, values, context=None): + if context is None: + context = {} + # perform create + obj_id = super(base_needaction, self).create(cr, uid, ids, values, context=context) + # link user_ids + needaction_user_ids = self.get_needaction_user_ids(cr, uid, [obj_id], context=context) + self._update_users(cr, uid, [id], needaction_user_ids[obj_id], context=context) + return obj_id + def write(self, cr, uid, ids, values, context=None): if context is None: context = {} - # get and update needaction_user_ids - needaction_user_ids = self.set_needaction_user_ids(cr, uid, ids, context=context) + # get and update user_ids + needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) for id in ids: - self.needaction_write_users(cr, uid, [id], needaction_user_ids[id], context=context) + self._update_users(cr, uid, [id], needaction_user_ids[id], context=context) # perform write return super(base_needaction, self).write(cr, uid, ids, values, context=context) - - _columns = { - } + def unlink(self, cr, uids, ids, context=None): + if context is None: + context = {} + # unlink user_ids + self._unlink_users(cr, uid, ids, context=context) + # perform unlink + return super(base_needaction, self).unlink(cr, uid, ids, values, context=context) #------------------------------------------------------ # General API #------------------------------------------------------ - def get_user_needaction_ids(self, cr, uid, user_id, offset=0, limit=None, order=None, count=False, context=None): + def needaction_get_user_needaction_ids(self, cr, uid, user_id, offset=0, limit=None, order=None, count=False, context=None): if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') search_res = needact_rel_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, count=count, context=context) return search_res - def get_record_references(self, cr, uid, user_id, offset=0, limit=None, order=None, context=None): + def needaction_get_record_references(self, cr, uid, user_id, offset=0, limit=None, order=None, context=None): if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') - search_res = self.get_user_needaction_ids(cr, uid, user_id, offset=offset, limit=limit, order=order, context=context) - needact_objs = needact_rel_obj.browse(cr, uid, search_res, context=context) + needact_obj_ids = self.get_user_needaction_ids(cr, uid, user_id, offset=offset, limit=limit, order=order, context=context) + needact_objs = needact_rel_obj.browse(cr, uid, needact_obj_ids, context=context) record_references = [(needact_obj.res_model, needact_obj.res_id) for needact_obj in needact_objs] return record_references From 8d627fc8a646f9e6b1a6677fc110a7b634b61c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 14 Mar 2012 18:59:35 +0100 Subject: [PATCH 07/43] [FIX] bugs in unlink bzr revid: tde@openerp.com-20120314175935-aylkpt8ejcxqmu82 --- openerp/addons/base/base_needaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 68f8d27b017..6df6d077a6b 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -128,13 +128,13 @@ class base_needaction(osv.osv): # perform write return super(base_needaction, self).write(cr, uid, ids, values, context=context) - def unlink(self, cr, uids, ids, context=None): + def unlink(self, cr, uid, ids, context=None): if context is None: context = {} # unlink user_ids self._unlink_users(cr, uid, ids, context=context) # perform unlink - return super(base_needaction, self).unlink(cr, uid, ids, values, context=context) + return super(base_needaction, self).unlink(cr, uid, ids, context=context) #------------------------------------------------------ # General API From 67d5a3f42593479d5ddbbf5e402e2299e94aa55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 15 Mar 2012 10:08:29 +0100 Subject: [PATCH 08/43] [FIX] Check of need_action_user_ids is now done after updating the object, not before bzr revid: tde@openerp.com-20120315090829-1be3yba7yhcw8qxu --- openerp/addons/base/base_needaction.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 6df6d077a6b..8d9724e70d1 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -121,12 +121,13 @@ class base_needaction(osv.osv): def write(self, cr, uid, ids, values, context=None): if context is None: context = {} + # perform write + write_res = super(base_needaction, self).write(cr, uid, ids, values, context=context) # get and update user_ids needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) for id in ids: self._update_users(cr, uid, [id], needaction_user_ids[id], context=context) - # perform write - return super(base_needaction, self).write(cr, uid, ids, values, context=context) + return write_res def unlink(self, cr, uid, ids, context=None): if context is None: From 0f32742ff054fb7fce0bc4aa2e0ef60799b701f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 15 Mar 2012 10:12:57 +0100 Subject: [PATCH 09/43] [FIX] Fixed bug in object create bzr revid: tde@openerp.com-20120315091257-7h04fdhmjr9gczzy --- openerp/addons/base/base_needaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 8d9724e70d1..2deeec64492 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -112,10 +112,10 @@ class base_needaction(osv.osv): if context is None: context = {} # perform create - obj_id = super(base_needaction, self).create(cr, uid, ids, values, context=context) + obj_id = super(base_needaction, self).create(cr, uid, values, context=context) # link user_ids needaction_user_ids = self.get_needaction_user_ids(cr, uid, [obj_id], context=context) - self._update_users(cr, uid, [id], needaction_user_ids[obj_id], context=context) + self._update_users(cr, uid, [obj_id], needaction_user_ids[obj_id], context=context) return obj_id def write(self, cr, uid, ids, values, context=None): From 632c5e3036b39fdee58b442aff72e7a50baa7496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 15 Mar 2012 10:52:03 +0100 Subject: [PATCH 10/43] [DOC] Updated code and server documentation. bzr revid: tde@openerp.com-20120315095203-8g7drwdz9axjexwj --- doc/api/need_action_specs.rst | 28 +++++++++++++-- openerp/addons/base/base_needaction.py | 47 ++++++++++++++++---------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst index 5d5d94cf903..d33536a347d 100644 --- a/doc/api/need_action_specs.rst +++ b/doc/api/need_action_specs.rst @@ -1,8 +1,32 @@ Need action mixin class ======================= -This revision adds a mixin class for object implementing the need action mechanism. Need action mechanism can be used by objects that have to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance validation by a manager, this mechanism allows to set a field with the user_id of the user requested to perform the action. +This revision adds a mixin class for objects using the need action feature. Need action mechanism can be used by objects that have to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance validation by a manager, this mechanism allows to set a field with the user_id of the user requested to perform the action. -Technically, this class adds a need_action_user_id field; when set to false, no action is required; when an user_id is set, this user has an action to perform. This field is a function field. Setting an user_id is done through redefining the get_needaction_user_id method. Therefore by redefining only one method, you can specify the cases in which an action will be required on a particular record. +This class wraps a table (base.needaction_users_rel) that behaves like a many2many field. However, no field is added to the model inheriting from base.needaction. The mixin class manages the low-level considerations of updating relationships. Every change made on the record calls a method that updates the relationships. + +Objects using the need_action feature should override the ``get_needaction_user_ids`` method. This methods returns a dictionary whose keys are record ids, and values a list of user ids, like in a many2many relationship. Therefore by defining only one method, you can specify if an action is required by defining the users that have to do it, in every possible situation. + +This class also offers several global services,: + - ``needaction_get_user_record_references``: for a given uid, get all the records that asks this user to perform an action. Records are given as references, a list of tuples (model_name, record_id). This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12). + +Addon implementation example +++++++++++++++++++++++++++++ + +In your ``foo`` module, you want to specify that when it is in state ``confirmed``, it has to be validated by a manager, given by the field ``manager_id``. After making ``foo`` inheriting from ``base.needaction``, you override the ``get_needaction_user_ids`` method: + +:: + + [...] + _inherit = [base.needaction] + [...] + def get_needaction_user_ids(self, cr, uid, ids, context=None): + # set the list void by default + result = dict.fromkeys(ids, []) + for foo_obj in self.browse(cr, uid, ids, context=context): + # if foo_obj is confirmed: manager is required to perform an action + if foo_obj.state == 'confirmed': + result[foo_obj.id] = [foo_obj.manager_id] + return result diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 2deeec64492..62a36162e89 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -24,12 +24,12 @@ from tools.translate import _ class base_needaction_users_rel(osv.osv): ''' - base_needaction_users_rel holds the data related to the needaction + base_needaction_users_rel holds data related to the needaction mechanism inside OpenERP. A needaction is characterized by: - - res_model: model of the followed objects - - res_id: ID of resource + - res_model: model of the record requiring an action + - res_id: ID of the record requiring an action - user_id: foreign key to the res.users table, to the user that - has to perform an action + has to perform the action ''' _name = 'base.needaction_users_rel' @@ -46,23 +46,33 @@ class base_needaction_users_rel(osv.osv): class base_needaction(osv.osv): - '''Mixin class for object implementing the need action mechanism. + '''Mixin class for objects using the need action feature. - Need action mechanism can be used by objects that have to be able to + Need action feature can be used by objects willing to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance - validation by a manager, this mechanism allows to set a field with - the user_id of the user requested to perform the action. + validation by a manager, this mechanism allows to set a list of + users asked ot perform an action. - Technically, this class adds a need_action_user_id field; when - set to false, no action is required; when an user_id is set, - this user has an action to perform. This field is a function field. - Setting an user_id is done through redefining the get_needaction_user_id method. - Therefore by redefining only one method, you can specify - the cases in which an action will be required on a particular record. + This class wraps a table (base.needaction_users_rel) that behaves + like a many2many field. However, no field is added to the model + inheriting from base.needaction. The mixin class manages the low-level + considerations of updating relationships. Every change made on the + record calls a method that updates the relationships. - This mechanism is used for instance to display the number of pending actions - in menus, such as Leads (12). + Objects using the need_action feature should override the + ``get_needaction_user_ids`` method. This methods returns a dictionary + whose keys are record ids, and values a list of user ids, like + in a many2many relationship. Therefore by defining only one method, + you can specify if an action is required by defining the users + that have to do it, in every possible situation. + + This class also offers several global services,: + - ``needaction_get_user_record_references``: for a given uid, get all + the records that asks this user to perform an action. Records + are given as references, a list of tuples (model_name, record_id). + This mechanism is used for instance to display the number of pending + actions in menus, such as Leads (12). ''' _name = 'base.needaction' _description = 'Need action mechanism' @@ -148,7 +158,10 @@ class base_needaction(osv.osv): search_res = needact_rel_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, count=count, context=context) return search_res - def needaction_get_record_references(self, cr, uid, user_id, offset=0, limit=None, order=None, context=None): + def needaction_get_user_record_references(self, cr, uid, user_id, offset=0, limit=None, order=None, context=None): + '''for a given uid, get all the records that asks this user to + perform an action. Records are given as references, a list of + tuples (model_name, record_id).''' if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') From 6808cd7e5321d73e47fa2e75c8d50da061fc7389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 15 Mar 2012 11:05:42 +0100 Subject: [PATCH 11/43] [ADD] Added a menu entry in Settings/Users, along with a tree view definition. bzr revid: tde@openerp.com-20120315100542-xhlvb43lda9d3a0m --- doc/api/need_action_specs.rst | 2 ++ openerp/addons/base/__openerp__.py | 1 + openerp/addons/base/base_needaction_view.xml | 29 ++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 openerp/addons/base/base_needaction_view.xml diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst index d33536a347d..5cffe05be2c 100644 --- a/doc/api/need_action_specs.rst +++ b/doc/api/need_action_specs.rst @@ -12,6 +12,8 @@ This class also offers several global services,: This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12). +A menu in Settings/Users has been added to allows having a quick look to need_action_user_ids. + Addon implementation example ++++++++++++++++++++++++++++ diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 802a0510e28..67920c7239a 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -40,6 +40,7 @@ ], 'update_xml': [ 'base_update.xml', + 'base_needaction_view.xml', 'ir/wizard/wizard_menu_view.xml', 'ir/ir.xml', 'ir/ir_config_parameter_view.xml', diff --git a/openerp/addons/base/base_needaction_view.xml b/openerp/addons/base/base_needaction_view.xml new file mode 100644 index 00000000000..84f7612cac9 --- /dev/null +++ b/openerp/addons/base/base_needaction_view.xml @@ -0,0 +1,29 @@ + + + + + + base.needaction_users_rel.tree + base.needaction_users_rel + tree + 10 + + + + + + + + + + + Need action relationships + base.needaction_users_rel + form + tree,form + + + + + + From 23ce37bd736221b6f663e43c9ecf91c5bd564a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 22 Mar 2012 12:01:44 +0100 Subject: [PATCH 12/43] [IMP] Code cleaning; rename methods; added needaction_get_records_user_ids, to have all users for a set of records. bzr revid: tde@openerp.com-20120322110144-0e30w63q3yl9ettu --- openerp/addons/base/base_needaction.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 62a36162e89..b37033fdf6b 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -148,24 +148,37 @@ class base_needaction(osv.osv): return super(base_needaction, self).unlink(cr, uid, ids, context=context) #------------------------------------------------------ - # General API + # Need action API #------------------------------------------------------ - def needaction_get_user_needaction_ids(self, cr, uid, user_id, offset=0, limit=None, order=None, count=False, context=None): + def needaction_get_records_user_ids(self, cr, uid, ids, context=None): + """Find all users that have to perform an action related to + records, given their ids""" + all_user_ids = [] + needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) + for recird_id, record_user_ids in needaction_user_ids: + all_user_ids += record_user_ids + return all_user_ids + + def _needaction_get_user_table_ids(self, cr, uid, ids, user_id, offset=0, limit=None, order=None, count=False, context=None): + """General method + Given an user_id, get all base.needaction_users_rel ids""" if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') search_res = needact_rel_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, count=count, context=context) return search_res - def needaction_get_user_record_references(self, cr, uid, user_id, offset=0, limit=None, order=None, context=None): - '''for a given uid, get all the records that asks this user to + def needaction_get_user_record_references(self, cr, uid, ids, user_id, offset=0, limit=None, order=None, context=None): + """General method + For a given uid, get all the records that asks this user to perform an action. Records are given as references, a list of - tuples (model_name, record_id).''' + tuples (model_name, record_id). + This method is trans-model.""" if context is None: context = {} needact_rel_obj = self.pool.get('base.needaction_users_rel') - needact_obj_ids = self.get_user_needaction_ids(cr, uid, user_id, offset=offset, limit=limit, order=order, context=context) + needact_obj_ids = self._needaction_get_user_table_ids(cr, uid, user_id, offset=offset, limit=limit, order=order, context=context) needact_objs = needact_rel_obj.browse(cr, uid, needact_obj_ids, context=context) record_references = [(needact_obj.res_model, needact_obj.res_id) for needact_obj in needact_objs] return record_references From 84e6d424695a6d799214471b1569c4260b7de1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 22 Mar 2012 13:38:16 +0100 Subject: [PATCH 13/43] [FIX] Fixed last commit bzr revid: tde@openerp.com-20120322123816-0zde1hqp7dc2dneu --- openerp/addons/base/base_needaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index b37033fdf6b..ae1dfacfedf 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -156,7 +156,7 @@ class base_needaction(osv.osv): records, given their ids""" all_user_ids = [] needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) - for recird_id, record_user_ids in needaction_user_ids: + for record_id, record_user_ids in needaction_user_ids.iteritems(): all_user_ids += record_user_ids return all_user_ids From b1f53deade2da546731a64423dd1ffd6b786a0b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 23 Mar 2012 18:14:18 +0100 Subject: [PATCH 14/43] [REF] Refactored code and API. TODO: more cleaning. bzr revid: tde@openerp.com-20120323171418-liiguk4juvqlwsks --- openerp/addons/base/base_needaction.py | 55 +++++++++++++++++--------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index ae1dfacfedf..2888c6b6746 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -19,6 +19,7 @@ # ############################################################################## +import openerp.pooler as pooler from osv import osv, fields from tools.translate import _ @@ -84,30 +85,41 @@ class base_needaction(osv.osv): # need action relationship management #------------------------------------------------------ - def _link_users(self, cr, uid, ids, user_ids, context=None): + def _get_user_ids(self, cr, uid, ids, context=None): + """Given ids of model self._name, find the user_ids that have an action to perform""" if context is None: context = {} - needact_rel_obj = self.pool.get('base.needaction_users_rel') + action_obj = self.pool.get('base.needaction_users_rel') + action_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._nanme), ('res_id', 'in', ids)], context=context) + actions = needact_rel_obj.read(cr, uid, action_ids, context=context) + return [action['user_id'] for action in actions] + + def _link_users(self, cr, uid, ids, user_ids, context=None): + """Given ids of model self._name, add user_ids to the relationship table""" + if context is None: + context = {} + action_obj = self.pool.get('base.needaction_users_rel') for id in ids: for user_id in user_ids: - needact_rel_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) + action_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) return True def _unlink_users(self, cr, uid, ids, context=None): + """Given ids of model self._name, delete all entries in the relationship table""" if context is None: context = {} - needact_rel_obj = self.pool.get('base.needaction_users_rel') - to_del_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) - return needact_rel_obj.unlink(cr, uid, to_del_ids, context=context) + action_obj = self.pool.get('base.needaction_users_rel') + to_del_ids = action_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + return action_obj.unlink(cr, uid, to_del_ids, context=context) def _update_users(self, cr, uid, ids, user_ids, context=None): + """Given ids of model self._name, update their entries in the relationship table to user_ids""" if context is None: context = {} # unlink old records self._unlink_users(cr, uid, ids, context=context) # link new records - for res_id in ids: - self._link_users(cr, uid, ids, user_ids, context=context) + self._link_users(cr, uid, ids, user_ids, context=context) return True #------------------------------------------------------ @@ -115,8 +127,7 @@ class base_needaction(osv.osv): #------------------------------------------------------ def get_needaction_user_ids(self, cr, uid, ids, context=None): - result = dict.fromkeys(ids, []) - return result + return dict.fromkeys(ids, []) def create(self, cr, uid, values, context=None): if context is None: @@ -151,14 +162,22 @@ class base_needaction(osv.osv): # Need action API #------------------------------------------------------ - def needaction_get_records_user_ids(self, cr, uid, ids, context=None): - """Find all users that have to perform an action related to - records, given their ids""" - all_user_ids = [] - needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) - for record_id, record_user_ids in needaction_user_ids.iteritems(): - all_user_ids += record_user_ids - return all_user_ids + @classmethod + def needaction_get_user_ids(cld, cr, uid, model, context=None): + """Given a model + get the user_ids that have to perform at least one action""" + requ_act_obj = self.pool.get('base.needaction_users_rel') + requ_act_ids = requ_act_obj.search(cr, uid, [('res_model', '=', model)], context=context) + requ_act_objs = requ_act_obj.read(cr, uid, requ_act_ids, context=context) + return list(set([requ_act_obj['user_id'] for requ_act_obj in requ_act_objs])) + + @classmethod + def needaction_get_action_count(cls, cr, uid, model, user_id, context=None): + """Given a model and a user_id + get the number of actions it has to perform""" + print cls._name + requ_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') + return requ_act_obj.search(cr, uid, [('res_model', '=', model), ('user_id', '=', user_id)], count=True, context=context) def _needaction_get_user_table_ids(self, cr, uid, ids, user_id, offset=0, limit=None, order=None, count=False, context=None): """General method From f11caea8e2b0e639d73c9db7b2b48f3f4a2e00b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 26 Mar 2012 10:20:19 +0200 Subject: [PATCH 15/43] [IMP] Cleaned and updated code. Updated var name. bzr revid: tde@openerp.com-20120326082019-n9ibqzq79y425qc9 --- openerp/addons/base/base_needaction.py | 55 ++++++++++++-------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 2888c6b6746..41cd1c42b3b 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -89,28 +89,28 @@ class base_needaction(osv.osv): """Given ids of model self._name, find the user_ids that have an action to perform""" if context is None: context = {} - action_obj = self.pool.get('base.needaction_users_rel') - action_ids = needact_rel_obj.search(cr, uid, [('res_model', '=', self._nanme), ('res_id', 'in', ids)], context=context) - actions = needact_rel_obj.read(cr, uid, action_ids, context=context) - return [action['user_id'] for action in actions] + needact_obj = self.pool.get('base.needaction_users_rel') + needact_ids = needact_obj.search(cr, uid, [('res_model', '=', self._nanme), ('res_id', 'in', ids)], context=context) + needacts = needact_obj.read(cr, uid, needact_ids, context=context) + return [needact['user_id'] for needact in needacts] def _link_users(self, cr, uid, ids, user_ids, context=None): """Given ids of model self._name, add user_ids to the relationship table""" if context is None: context = {} - action_obj = self.pool.get('base.needaction_users_rel') + needact_obj = self.pool.get('base.needaction_users_rel') for id in ids: for user_id in user_ids: - action_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) + needact_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) return True def _unlink_users(self, cr, uid, ids, context=None): """Given ids of model self._name, delete all entries in the relationship table""" if context is None: context = {} - action_obj = self.pool.get('base.needaction_users_rel') - to_del_ids = action_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) - return action_obj.unlink(cr, uid, to_del_ids, context=context) + needact_obj = self.pool.get('base.needaction_users_rel') + to_del_ids = needact_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + return needact_obj.unlink(cr, uid, to_del_ids, context=context) def _update_users(self, cr, uid, ids, user_ids, context=None): """Given ids of model self._name, update their entries in the relationship table to user_ids""" @@ -163,43 +163,38 @@ class base_needaction(osv.osv): #------------------------------------------------------ @classmethod - def needaction_get_user_ids(cld, cr, uid, model, context=None): + def needaction_get_user_ids(cls, cr, uid, model, context=None): """Given a model get the user_ids that have to perform at least one action""" - requ_act_obj = self.pool.get('base.needaction_users_rel') - requ_act_ids = requ_act_obj.search(cr, uid, [('res_model', '=', model)], context=context) - requ_act_objs = requ_act_obj.read(cr, uid, requ_act_ids, context=context) - return list(set([requ_act_obj['user_id'] for requ_act_obj in requ_act_objs])) + if context is None: + context = {} + need_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') + need_act_ids = need_act_obj.search(cr, uid, [('res_model', '=', model)], context=context) + need_acts = need_act_obj.read(cr, uid, need_act_ids, context=context) + return list(set([need_act['user_id'] for need_act in need_acts])) @classmethod def needaction_get_action_count(cls, cr, uid, model, user_id, context=None): """Given a model and a user_id get the number of actions it has to perform""" - print cls._name - requ_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') - return requ_act_obj.search(cr, uid, [('res_model', '=', model), ('user_id', '=', user_id)], count=True, context=context) - - def _needaction_get_user_table_ids(self, cr, uid, ids, user_id, offset=0, limit=None, order=None, count=False, context=None): - """General method - Given an user_id, get all base.needaction_users_rel ids""" if context is None: context = {} - needact_rel_obj = self.pool.get('base.needaction_users_rel') - search_res = needact_rel_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, count=count, context=context) - return search_res + need_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') + return need_act_obj.search(cr, uid, [('res_model', '=', model), ('user_id', '=', user_id)], count=True, context=context) - def needaction_get_user_record_references(self, cr, uid, ids, user_id, offset=0, limit=None, order=None, context=None): + @classmethod + def needaction_get_record_references(cls, cr, uid, user_id, offset=None, limit=None, order=None, context=None): """General method - For a given uid, get all the records that asks this user to + For a given user_id, get all the records that asks this user to perform an action. Records are given as references, a list of tuples (model_name, record_id). This method is trans-model.""" if context is None: context = {} - needact_rel_obj = self.pool.get('base.needaction_users_rel') - needact_obj_ids = self._needaction_get_user_table_ids(cr, uid, user_id, offset=offset, limit=limit, order=order, context=context) - needact_objs = needact_rel_obj.browse(cr, uid, needact_obj_ids, context=context) - record_references = [(needact_obj.res_model, needact_obj.res_id) for needact_obj in needact_objs] + need_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') + need_act_ids = need_act_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, context=context) + need_acts = need_act_obj.browse(cr, uid, need_act_ids, context=context) + record_references = [(need_act.res_model, need_act.res_id) for need_act in need_acts] return record_references From 8196c9e1b1c866b317ded9432f3cb42c35673241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 28 Mar 2012 18:35:49 +0200 Subject: [PATCH 16/43] [REF] Refactored needaction mechanism. Added functional fields in ir.ui.menu so the web client only has to manage the values. bzr revid: tde@openerp.com-20120328163549-4g3dc5mwdagenrq1 --- openerp/addons/base/base_needaction.py | 16 +++++++++++++--- openerp/addons/base/ir/ir.xml | 3 +++ openerp/addons/base/ir/ir_ui_menu.py | 15 +++++++++++++++ openerp/osv/orm.py | 22 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 41cd1c42b3b..7d5dbcd85fa 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -163,7 +163,7 @@ class base_needaction(osv.osv): #------------------------------------------------------ @classmethod - def needaction_get_user_ids(cls, cr, uid, model, context=None): + def needaction_get_user_ids(cls, cr, uid, model_name, user_id, context=None): """Given a model get the user_ids that have to perform at least one action""" if context is None: @@ -174,13 +174,23 @@ class base_needaction(osv.osv): return list(set([need_act['user_id'] for need_act in need_acts])) @classmethod - def needaction_get_action_count(cls, cr, uid, model, user_id, context=None): + def needaction_get_record_ids(cls, cr, uid, model_name, user_id, limit=80, context=None): """Given a model and a user_id get the number of actions it has to perform""" if context is None: context = {} need_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') - return need_act_obj.search(cr, uid, [('res_model', '=', model), ('user_id', '=', user_id)], count=True, context=context) + need_act_ids = need_act_obj.search(cr, uid, [('res_model', '=', model_name), ('user_id', '=', user_id)], limit=limit, context=context) + return [need_act['res_id'] for need_act in need_act_obj.read(cr, uid, need_act_ids, context=context)] + + @classmethod + def needaction_get_action_count(cls, cr, uid, model_name, user_id, context=None): + """Given a model and a user_id + get the number of actions it has to perform""" + if context is None: + context = {} + need_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') + return need_act_obj.search(cr, uid, [('res_model', '=', model_name), ('user_id', '=', user_id)], count=True, context=context) @classmethod def needaction_get_record_references(cls, cr, uid, user_id, offset=None, limit=None, order=None, context=None): diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 6a845b35602..136a7c7eff1 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -1397,6 +1397,9 @@
+ + + diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index fb346c06ae4..344457db863 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -255,6 +255,19 @@ class ir_ui_menu(osv.osv): return res + def _get_needaction(self, cr, uid, ids, field_names, args, context=None): + if context is None: + context = {} + res = dict.fromkeys(ids, {}) + for menu in self.browse(cr, uid, ids, context=context): + if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: + menu_needaction_res = osv.osv.get_needaction_info(cr, uid, menu.action.res_model, uid, domain=menu.action.domain, context=context) + else: + menu_needaction_res = [False, 0] + res[menu.id]['has_needaction'] = menu_needaction_res[0] + res[menu.id]['needaction_ctr'] = menu_needaction_res[1] + return res + _columns = { 'name': fields.char('Menu', size=64, required=True, translate=True), 'sequence': fields.integer('Sequence'), @@ -271,6 +284,8 @@ class ir_ui_menu(osv.osv): 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), + 'has_needaction': fields.function(_get_needaction, string='User has actions to perform', type='boolean', help='', multi='has_action'), + 'needaction_ctr': fields.function(_get_needaction, string='Action counter', type='integer', help='', multi='has_action'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 31a433855af..86eed18ff6b 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -57,6 +57,7 @@ from lxml import etree import fields import openerp import openerp.netsvc as netsvc +import openerp.pooler as pooler import openerp.tools as tools from openerp.tools.config import config from openerp.tools.safe_eval import safe_eval as eval @@ -716,6 +717,27 @@ class BaseModel(object): context=context ) + @staticmethod + def get_needaction_info(cr, uid, model_name, user_id, limit=None, order=None, domain=False, context=None): + """Base method for needaction mechanism + - see base.needaction for actual implementation + - this method returns default values + :return: [has_needaction=False, needaction_ctr=0] + """ + model_obj = pooler.get_pool(cr.dbname).get(model_name) + if hasattr(model_obj, 'needaction_get_record_ids'): + ids = model_obj.needaction_get_record_ids(cr, uid, model_name, user_id, context=context) + if not ids: + return [True, 0] + if domain: + domain = eval(domain) + new_domain = domain + [('id', 'in', ids)] + else: + new_domain = [('ids', 'in', ids)] + return [True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True)] + else: + return [False, 0] + def view_init(self, cr, uid, fields_list, context=None): """Override this method to do specific things when a view on the object is opened.""" pass From 13fa7f1a4ba60e1f0b94e228ea092df8457b11a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 29 Mar 2012 09:25:39 +0200 Subject: [PATCH 17/43] [IMP] Added optional limit arg in base.needaction bzr revid: tde@openerp.com-20120329072539-zi42lnsxs1fupehz --- openerp/addons/base/base_needaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 7d5dbcd85fa..657cf8f5d55 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -184,13 +184,13 @@ class base_needaction(osv.osv): return [need_act['res_id'] for need_act in need_act_obj.read(cr, uid, need_act_ids, context=context)] @classmethod - def needaction_get_action_count(cls, cr, uid, model_name, user_id, context=None): + def needaction_get_action_count(cls, cr, uid, model_name, user_id, limit=80, context=None): """Given a model and a user_id get the number of actions it has to perform""" if context is None: context = {} need_act_obj = pooler.get_pool(cr.dbname).get('base.needaction_users_rel') - return need_act_obj.search(cr, uid, [('res_model', '=', model_name), ('user_id', '=', user_id)], count=True, context=context) + return need_act_obj.search(cr, uid, [('res_model', '=', model_name), ('user_id', '=', user_id)], limit=limit, count=True, context=context) @classmethod def needaction_get_record_references(cls, cr, uid, user_id, offset=None, limit=None, order=None, context=None): From 349f5c82b392f595a4eade6d334630b423576840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 29 Mar 2012 09:26:34 +0200 Subject: [PATCH 18/43] [REM] Removed fields added for debug purpose bzr revid: tde@openerp.com-20120329072634-y432oy9k3wboxvlc --- openerp/addons/base/ir/ir.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 136a7c7eff1..6a845b35602 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -1397,9 +1397,6 @@ - - - From 1834f6924342b4d5bacf2162aec8e1a1339d5267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 29 Mar 2012 15:53:07 +0200 Subject: [PATCH 19/43] [FIX] Added rights on base_needaction_users_rel, otherwise users were restricted. bzr revid: tde@openerp.com-20120329135307-jdmegk07s39grpzt --- openerp/addons/base/security/ir.model.access.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index 59ebafb2f99..416d5c54053 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -125,3 +125,4 @@ "access_ir_mail_server_all","ir_mail_server","model_ir_mail_server",,1,0,0,0 "access_ir_actions_todo_category","ir_actions_todo_category","model_ir_actions_todo_category","group_system",1,1,1,1 "access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0 +"access_base_needaction_users_rel","base_needaction_users_rel all","model_base_needaction_users_rel",,1,1,1,1 From 03cd5c47b288b36075da27cba597f4b8bb93e271 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Fri, 30 Mar 2012 10:40:38 +0530 Subject: [PATCH 20/43] [IMP] store functional fields in database bzr revid: tpa@tinyerp.com-20120330051038-y7b1vdamhdp4pj3n --- openerp/addons/base/ir/ir_ui_menu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 344457db863..01e11ffc8bb 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -284,8 +284,8 @@ class ir_ui_menu(osv.osv): 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), - 'has_needaction': fields.function(_get_needaction, string='User has actions to perform', type='boolean', help='', multi='has_action'), - 'needaction_ctr': fields.function(_get_needaction, string='Action counter', type='integer', help='', multi='has_action'), + 'has_needaction': fields.function(_get_needaction,store=True,string='User has actions to perform', type='boolean', help='', multi='has_action'), + 'needaction_ctr': fields.function(_get_needaction,store=True, string='Action counter', type='integer', help='', multi='has_action'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ From 2f97bcdf7d95d52e52dc70e0652b4da6c2094488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 12:03:37 +0200 Subject: [PATCH 21/43] [FIX] Removed the store=True (too much access to DB), as this is not necessary. Fixed dict of dict: inner dict instantiation is done for each iteration, because argument management in python made all dicts pointers to the same dict bzr revid: tde@openerp.com-20120330100337-miqra4q5sjokt7en --- openerp/addons/base/ir/ir_ui_menu.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 01e11ffc8bb..18d390e8ae9 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -258,8 +258,9 @@ class ir_ui_menu(osv.osv): def _get_needaction(self, cr, uid, ids, field_names, args, context=None): if context is None: context = {} - res = dict.fromkeys(ids, {}) + res = dict.fromkeys(ids) for menu in self.browse(cr, uid, ids, context=context): + res[menu.id] = {} if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: menu_needaction_res = osv.osv.get_needaction_info(cr, uid, menu.action.res_model, uid, domain=menu.action.domain, context=context) else: @@ -284,8 +285,8 @@ class ir_ui_menu(osv.osv): 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), - 'has_needaction': fields.function(_get_needaction,store=True,string='User has actions to perform', type='boolean', help='', multi='has_action'), - 'needaction_ctr': fields.function(_get_needaction,store=True, string='Action counter', type='integer', help='', multi='has_action'), + 'has_needaction': fields.function(_get_needaction, string='User has actions to perform', type='boolean', help='', multi='has_action'), + 'needaction_ctr': fields.function(_get_needaction, string='Action counter', type='integer', help='', multi='has_action'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ From 3ee9f70343ca0eb571f5ec9eb01eccb89c09dc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 12:19:29 +0200 Subject: [PATCH 22/43] [IMP] Renamed added fields. Added comments and improved help. bzr revid: tde@openerp.com-20120330101929-18opxctcz1eeyl4u --- openerp/addons/base/ir/ir_ui_menu.py | 8 ++++---- openerp/osv/orm.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 18d390e8ae9..205d44b0363 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -265,8 +265,8 @@ class ir_ui_menu(osv.osv): menu_needaction_res = osv.osv.get_needaction_info(cr, uid, menu.action.res_model, uid, domain=menu.action.domain, context=context) else: menu_needaction_res = [False, 0] - res[menu.id]['has_needaction'] = menu_needaction_res[0] - res[menu.id]['needaction_ctr'] = menu_needaction_res[1] + res[menu.id]['uses_needaction'] = menu_needaction_res[0] + res[menu.id]['needaction_uid_ctr'] = menu_needaction_res[1] return res _columns = { @@ -285,8 +285,8 @@ class ir_ui_menu(osv.osv): 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), - 'has_needaction': fields.function(_get_needaction, string='User has actions to perform', type='boolean', help='', multi='has_action'), - 'needaction_ctr': fields.function(_get_needaction, string='Action counter', type='integer', help='', multi='has_action'), + 'uses_needaction': fields.function(_get_needaction, string='Related model uses the need action mechanism', type='boolean', help='If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'), + 'needaction_uid_ctr': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the related model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 86eed18ff6b..6d6d6dd0d38 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -722,7 +722,7 @@ class BaseModel(object): """Base method for needaction mechanism - see base.needaction for actual implementation - this method returns default values - :return: [has_needaction=False, needaction_ctr=0] + :return: [uses_needaction=False, needaction_uid_ctr=0] """ model_obj = pooler.get_pool(cr.dbname).get(model_name) if hasattr(model_obj, 'needaction_get_record_ids'): From 94075df78e347c051e5f7ef85b3d23d9848e0259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 12:24:19 +0200 Subject: [PATCH 23/43] [DOC] Added comments. bzr revid: tde@openerp.com-20120330102419-n2co6dwf00q0muue --- openerp/osv/orm.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 6d6d6dd0d38..da424611dd9 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -721,8 +721,18 @@ class BaseModel(object): def get_needaction_info(cr, uid, model_name, user_id, limit=None, order=None, domain=False, context=None): """Base method for needaction mechanism - see base.needaction for actual implementation + - if the model uses the need action mechanism + (hasattr(model_obj, 'needaction_get_record_ids'): + - get the record ids on which the user has actions to perform + - evaluate the menu domain + - compose a new domain: menu domain, limited to ids of + records requesting an action + - count the number of records maching that domain, that + is the number of actions the user has to perform - this method returns default values - :return: [uses_needaction=False, needaction_uid_ctr=0] + :param: model_name: the name of the model (ex: hr.holidays) + :param: user_id: the id of user + :return: [uses_needaction=True/False, needaction_uid_ctr=%d] """ model_obj = pooler.get_pool(cr.dbname).get(model_name) if hasattr(model_obj, 'needaction_get_record_ids'): @@ -730,8 +740,7 @@ class BaseModel(object): if not ids: return [True, 0] if domain: - domain = eval(domain) - new_domain = domain + [('id', 'in', ids)] + new_domain = eval(domain) + [('id', 'in', ids)] else: new_domain = [('ids', 'in', ids)] return [True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True)] From 3d726e1d4d6ad20d6db211fe511e74e091cad406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 12:38:22 +0200 Subject: [PATCH 24/43] [DOC] Improved comments bzr revid: tde@openerp.com-20120330103822-3esas0shsvoidb90 --- openerp/addons/base/base_needaction.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 657cf8f5d55..08a0452ebab 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -34,6 +34,7 @@ class base_needaction_users_rel(osv.osv): ''' _name = 'base.needaction_users_rel' + _description = 'Relationships between records and users, for need action mechanism' _rec_name = 'id' _order = 'res_model asc' _columns = { @@ -41,7 +42,7 @@ class base_needaction_users_rel(osv.osv): select=1, required=True), 'res_id': fields.integer('Related Document ID', select=1, required=True), - 'user_id': fields.many2one('res.users', string='Related User ID', + 'user_id': fields.many2one('res.users', string='Related User', ondelete='cascade', select=1, required=True), } @@ -70,13 +71,18 @@ class base_needaction(osv.osv): This class also offers several global services,: - ``needaction_get_user_record_references``: for a given uid, get all - the records that asks this user to perform an action. Records - are given as references, a list of tuples (model_name, record_id). - This mechanism is used for instance to display the number of pending - actions in menus, such as Leads (12). + the records that ask this user to perform an action. Records + are given as references, a list of tuples (model_name, record_id). + - ``needaction_get_record_ids``: for a given model_name and uid, get + all record ids that ask this user to perform an action. This + mechanism is used for instance to display the number of pending + actions in menus, such as Leads (12). + - ``needaction_get_action_count``: as ``needaction_get_record_ids`` + but returns only the number of action, not the ids (performs a + search with count=True) ''' _name = 'base.needaction' - _description = 'Need action mechanism' + _description = 'Need action of users on records API' _columns = { } From c2e1b6a3840ca1bcad5b77279a7d4dc2d6ef42c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 12:42:42 +0200 Subject: [PATCH 25/43] [DOC] Improved documentation. bzr revid: tde@openerp.com-20120330104242-h68fy7zsnueaod9m --- doc/api/need_action_specs.rst | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst index 5cffe05be2c..8efd548845a 100644 --- a/doc/api/need_action_specs.rst +++ b/doc/api/need_action_specs.rst @@ -1,5 +1,8 @@ -Need action mixin class -======================= +Need action mechanism +===================== + +base.needaction mixin class ++++++++++++++++++++++++++++ This revision adds a mixin class for objects using the need action feature. Need action mechanism can be used by objects that have to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance validation by a manager, this mechanism allows to set a field with the user_id of the user requested to perform the action. @@ -8,11 +11,20 @@ This class wraps a table (base.needaction_users_rel) that behaves like a many2ma Objects using the need_action feature should override the ``get_needaction_user_ids`` method. This methods returns a dictionary whose keys are record ids, and values a list of user ids, like in a many2many relationship. Therefore by defining only one method, you can specify if an action is required by defining the users that have to do it, in every possible situation. This class also offers several global services,: - - ``needaction_get_user_record_references``: for a given uid, get all the records that asks this user to perform an action. Records are given as references, a list of tuples (model_name, record_id). + - ``needaction_get_user_record_references``: for a given uid, get all the records that ask this user to perform an action. Records are given as references, a list of tuples (model_name, record_id). + - ``needaction_get_record_ids``: for a given model_name and uid, get all record ids that ask this user to perform an action. This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12). + - ``needaction_get_action_count``: as ``needaction_get_record_ids`` but returns only the number of action, not the ids (performs a search with count=True) -This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12). +A menu in Settings/Users has been added to allow having a quick look to need_action_user_ids. -A menu in Settings/Users has been added to allows having a quick look to need_action_user_ids. +Menu modification ++++++++++++++++++ + +This revision adds two functional fields to ``ir.ui.menu`` model : + - ``uses_needaction``: boolean field. If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false. + - ``needaction_uid_ctr``: integer field. If the related model uses the need action mechanism, this field gives the number of actions the current user has to perform. + +Those fields are functional, because they must be recalculated for each user, and each time menus are displayed. ``needaction_uid_ctr`` takes into account the domain of the action, in order to display accurate numbers. Addon implementation example ++++++++++++++++++++++++++++ @@ -26,8 +38,9 @@ In your ``foo`` module, you want to specify that when it is in state ``confirmed [...] def get_needaction_user_ids(self, cr, uid, ids, context=None): # set the list void by default - result = dict.fromkeys(ids, []) + result = dict.fromkeys(ids) for foo_obj in self.browse(cr, uid, ids, context=context): + result[foo_obj.id] = [] # if foo_obj is confirmed: manager is required to perform an action if foo_obj.state == 'confirmed': result[foo_obj.id] = [foo_obj.manager_id] From f57efbb152db29db2a0652f8ea55691a3202915e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 12:49:36 +0200 Subject: [PATCH 26/43] [FIX] Too long model description bzr revid: tde@openerp.com-20120330104936-p2cnbtua1znie6et --- openerp/addons/base/base_needaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/base_needaction.py b/openerp/addons/base/base_needaction.py index 08a0452ebab..69f620d7379 100644 --- a/openerp/addons/base/base_needaction.py +++ b/openerp/addons/base/base_needaction.py @@ -34,7 +34,7 @@ class base_needaction_users_rel(osv.osv): ''' _name = 'base.needaction_users_rel' - _description = 'Relationships between records and users, for need action mechanism' + _description = 'Needaction relationship table' _rec_name = 'id' _order = 'res_model asc' _columns = { From 508d257bcf83dfff0606f5a69cfc9f22e3447ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 14:59:00 +0200 Subject: [PATCH 27/43] [IMP] Renamed ir.ui.menu fields, uses_needaction -> needaction_enabled; needaction_uid_ctr -> needaction_counter bzr revid: tde@openerp.com-20120330125900-0jtpztxk336ugae0 --- openerp/addons/base/ir/ir_ui_menu.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 205d44b0363..01d420d943d 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -265,8 +265,8 @@ class ir_ui_menu(osv.osv): menu_needaction_res = osv.osv.get_needaction_info(cr, uid, menu.action.res_model, uid, domain=menu.action.domain, context=context) else: menu_needaction_res = [False, 0] - res[menu.id]['uses_needaction'] = menu_needaction_res[0] - res[menu.id]['needaction_uid_ctr'] = menu_needaction_res[1] + res[menu.id]['needaction_enabled'] = menu_needaction_res[0] + res[menu.id]['needaction_counter'] = menu_needaction_res[1] return res _columns = { @@ -285,8 +285,8 @@ class ir_ui_menu(osv.osv): 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), - 'uses_needaction': fields.function(_get_needaction, string='Related model uses the need action mechanism', type='boolean', help='If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'), - 'needaction_uid_ctr': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the related model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), + 'needaction_enabled': fields.function(_get_needaction, string='Related model uses the need action mechanism', type='boolean', help='If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'),+ + 'needaction_counter': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the related model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ From 519ebfdd499ec03e68702e9b048c7096eb4ef28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 15:02:32 +0200 Subject: [PATCH 28/43] [FIX] removed a '+' that probably came from outerspace bzr revid: tde@openerp.com-20120330130232-u61vt96fl23ss69z --- openerp/addons/base/ir/ir_ui_menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 01d420d943d..219fa7a8702 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -285,7 +285,7 @@ class ir_ui_menu(osv.osv): 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), - 'needaction_enabled': fields.function(_get_needaction, string='Related model uses the need action mechanism', type='boolean', help='If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'),+ + 'needaction_enabled': fields.function(_get_needaction, string='Related model uses the need action mechanism', type='boolean', help='If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'), 'needaction_counter': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the related model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', From 0f09c8eb917500c95f91ecc51401b6058590d922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 30 Mar 2012 15:24:52 +0200 Subject: [PATCH 29/43] [REF] Refactoring: moved from base to ir; renamed from base.needaction->ir.needaction; updated files accordingly bzr revid: tde@openerp.com-20120330132452-ww57gzp8ggx1pfj2 --- openerp/addons/base/__init__.py | 1 - openerp/addons/base/__openerp__.py | 1 - openerp/addons/base/base_needaction_view.xml | 29 ------------------- openerp/addons/base/ir/__init__.py | 1 + openerp/addons/base/ir/ir.xml | 24 +++++++++++++++ .../ir_needaction.py} | 28 +++++++++--------- .../addons/base/security/ir.model.access.csv | 2 +- 7 files changed, 40 insertions(+), 46 deletions(-) delete mode 100644 openerp/addons/base/base_needaction_view.xml rename openerp/addons/base/{base_needaction.py => ir/ir_needaction.py} (90%) diff --git a/openerp/addons/base/__init__.py b/openerp/addons/base/__init__.py index af551e60c1e..16a61521fb4 100644 --- a/openerp/addons/base/__init__.py +++ b/openerp/addons/base/__init__.py @@ -25,7 +25,6 @@ import res import publisher_warranty import report import test -import base_needaction # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 67920c7239a..802a0510e28 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -40,7 +40,6 @@ ], 'update_xml': [ 'base_update.xml', - 'base_needaction_view.xml', 'ir/wizard/wizard_menu_view.xml', 'ir/ir.xml', 'ir/ir_config_parameter_view.xml', diff --git a/openerp/addons/base/base_needaction_view.xml b/openerp/addons/base/base_needaction_view.xml deleted file mode 100644 index 84f7612cac9..00000000000 --- a/openerp/addons/base/base_needaction_view.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - base.needaction_users_rel.tree - base.needaction_users_rel - tree - 10 - - - - - - - - - - - Need action relationships - base.needaction_users_rel - form - tree,form - - - - - - diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py index 4a6bd3c614c..a2a4b999ed8 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -21,6 +21,7 @@ import ir_model import ir_sequence +import ir_needaction import ir_ui_menu import ir_ui_view import ir_default diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 6a845b35602..26af4365f58 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -661,6 +661,30 @@ + + + ir.needaction_users_rel.tree + ir.needaction_users_rel + tree + 10 + + + + + + + + + + + Need action relationships + ir.needaction_users_rel + form + tree,form + + + + Date: Mon, 2 Apr 2012 10:35:17 +0200 Subject: [PATCH 31/43] [ADD] Added 'needaction_record_ids' field to menu: ids of record requesting the user to perform an action. bzr revid: tde@openerp.com-20120402083517-1kzxxylr6niczhgw --- openerp/addons/base/ir/ir_needaction.py | 2 +- openerp/addons/base/ir/ir_ui_menu.py | 4 +++- openerp/osv/orm.py | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 6492f6662f3..2db37475c6c 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -37,7 +37,7 @@ class ir_needaction_users_rel(osv.osv): _name = 'ir.needaction_users_rel' _description = 'Needaction relationship table' _rec_name = 'id' - _order = 'res_model asc' + _order = 'id desc' _columns = { 'res_model': fields.char('Related Document Model', size=128, select=1, required=True), diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 0e07f91302a..2e3667c5339 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -264,9 +264,10 @@ class ir_ui_menu(osv.osv): if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: menu_needaction_res = osv.osv.get_needaction_info(cr, uid, menu.action.res_model, uid, domain=menu.action.domain, context=context) else: - menu_needaction_res = [False, 0] + menu_needaction_res = [False, 0, ()] res[menu.id]['needaction_enabled'] = menu_needaction_res[0] res[menu.id]['needaction_counter'] = menu_needaction_res[1] + res[menu.id]['needaction_record_ids'] = menu_needaction_res[2] return res _columns = { @@ -287,6 +288,7 @@ class ir_ui_menu(osv.osv): 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), 'needaction_enabled': fields.function(_get_needaction, string='Target model uses the need action mechanism', type='boolean', help='If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'), 'needaction_counter': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the target model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), + 'needaction_record_ids': fields.function(_get_needaction, string='Ids of records requesting an action from the user', type='many2many', help='', multi='_get_needaction'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 6914dd87d6e..ee4e424968e 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -741,16 +741,16 @@ class BaseModel(object): """ model_obj = pooler.get_pool(cr.dbname).get(model_name) if hasattr(model_obj, 'needaction_get_record_ids'): - ids = model_obj.needaction_get_record_ids(cr, uid, model_name, user_id, context=context) + ids = model_obj.needaction_get_record_ids(cr, uid, model_name, user_id, limit=8096, context=context) if not ids: return [True, 0] if domain: new_domain = eval(domain) + [('id', 'in', ids)] else: new_domain = [('ids', 'in', ids)] - return [True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True)] + return [True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True), ids] else: - return [False, 0] + return [False, 0, []] def view_init(self, cr, uid, fields_list, context=None): """Override this method to do specific things when a view on the object is opened.""" From c4333fe170bcf9933c0cec5f0da15152f8b09925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Apr 2012 10:36:05 +0200 Subject: [PATCH 32/43] [FIX] Added missing item in return bzr revid: tde@openerp.com-20120402083605-cb5w8sxtxcpexwry --- openerp/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index ee4e424968e..05a9309bf5a 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -743,7 +743,7 @@ class BaseModel(object): if hasattr(model_obj, 'needaction_get_record_ids'): ids = model_obj.needaction_get_record_ids(cr, uid, model_name, user_id, limit=8096, context=context) if not ids: - return [True, 0] + return [True, 0, []] if domain: new_domain = eval(domain) + [('id', 'in', ids)] else: From 6b443509f9c3b7a7b74c3a3065899f6d857c0ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Apr 2012 10:39:39 +0200 Subject: [PATCH 33/43] [FIX] Removed unnecessary arg bzr revid: tde@openerp.com-20120402083939-tah7cdqlmdzarl10 --- openerp/addons/base/ir/ir_needaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 2db37475c6c..c1d56cac3f4 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -92,7 +92,7 @@ class ir_needaction(osv.osv): # need action relationship management #------------------------------------------------------ - def _get_users(self, cr, uid, ids, user_ids, context=None): + def _get_users(self, cr, uid, ids, context=None): if context is None: context = {} needact_obj = self.pool.get('ir.needaction_users_rel') From ecb5b81933df547269b0832d2f4c208b265629ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Apr 2012 10:45:26 +0200 Subject: [PATCH 34/43] [IMP] Small code cleaning bzr revid: tde@openerp.com-20120402084526-il0wh3urnemb019g --- openerp/osv/orm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 05a9309bf5a..de11be9c749 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -743,14 +743,14 @@ class BaseModel(object): if hasattr(model_obj, 'needaction_get_record_ids'): ids = model_obj.needaction_get_record_ids(cr, uid, model_name, user_id, limit=8096, context=context) if not ids: - return [True, 0, []] + return (True, 0, []) if domain: new_domain = eval(domain) + [('id', 'in', ids)] else: new_domain = [('ids', 'in', ids)] - return [True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True), ids] + return (True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True), ids) else: - return [False, 0, []] + return (False, 0, []) def view_init(self, cr, uid, fields_list, context=None): """Override this method to do specific things when a view on the object is opened.""" From 87fd9521dd86ed1ed1127b80a2de95d297fea414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Apr 2012 10:50:42 +0200 Subject: [PATCH 35/43] [DOC] Improved help tootips and documentation. bzr revid: tde@openerp.com-20120402085042-e65y8nsqey1vlvxv --- doc/api/need_action_specs.rst | 7 ++++--- openerp/addons/base/ir/ir_ui_menu.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst index a2829b7873a..1be92586e7f 100644 --- a/doc/api/need_action_specs.rst +++ b/doc/api/need_action_specs.rst @@ -20,9 +20,10 @@ This class also offers several global services,: Menu modification +++++++++++++++++ -This revision adds two functional fields to ``ir.ui.menu`` model : - - ``uses_needaction``: boolean field. If the menu entry is related to a act_window action, and this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false. - - ``needaction_uid_ctr``: integer field. If the related model uses the need action mechanism, this field gives the number of actions the current user has to perform. +This revision adds three functional fields to ``ir.ui.menu`` model : + - ``uses_needaction``: boolean field. If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false. + - ``needaction_uid_ctr``: integer field. If the target model uses the need action mechanism, this field gives the number of actions the current user has to perform. + - ``needaction_record_ids``: many2many field. If the target model uses the need action mechanism, this field holds the ids of the record requesting the user to perform an action. Those fields are functional, because they must be recalculated for each user, and each time menus are displayed. ``needaction_uid_ctr`` takes into account the domain of the action, in order to display accurate numbers. diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 2e3667c5339..fe31d80b99f 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -288,7 +288,7 @@ class ir_ui_menu(osv.osv): 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), 'needaction_enabled': fields.function(_get_needaction, string='Target model uses the need action mechanism', type='boolean', help='If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'), 'needaction_counter': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the target model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), - 'needaction_record_ids': fields.function(_get_needaction, string='Ids of records requesting an action from the user', type='many2many', help='', multi='_get_needaction'), + 'needaction_record_ids': fields.function(_get_needaction, string='Ids of records requesting an action from the user', type='many2many', help='If the target model uses the need action mechanism, this field holds the ids of the record requesting the user to perform an action.', multi='_get_needaction'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ From b2f5e9fac01b97e06256184ba6637a2110ba9931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Apr 2012 11:01:22 +0200 Subject: [PATCH 36/43] [FIX] Wrong var name bzr revid: tde@openerp.com-20120402090122-3blvpf9eudy6e154 --- openerp/addons/base/ir/ir_needaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index c1d56cac3f4..beef291d775 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -97,7 +97,7 @@ class ir_needaction(osv.osv): context = {} needact_obj = self.pool.get('ir.needaction_users_rel') needact_ids = needact_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) - return needact_obj.read(cr, uid, cur_needact_ids, context=context) + return needact_obj.read(cr, uid, needact_ids, context=context) def _link_users(self, cr, uid, ids, user_ids, context=None): """Given ids of model self._name, add user_ids to the relationship table""" From 157506ef69874647e2a50ee9899c1ac1a9fe74dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 3 Apr 2012 09:54:34 +0200 Subject: [PATCH 37/43] [FIX] id instead of ids in domain bzr revid: tde@openerp.com-20120403075434-585pd5j93jeurelr --- openerp/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index de11be9c749..e34aa7c568e 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -747,7 +747,7 @@ class BaseModel(object): if domain: new_domain = eval(domain) + [('id', 'in', ids)] else: - new_domain = [('ids', 'in', ids)] + new_domain = [('id', 'in', ids)] return (True, model_obj.search(cr, uid, new_domain, limit=limit, order=order, count=True), ids) else: return (False, 0, []) From aa0205c8498a0b3f25c5ab28e1a4f907c3f8c3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 3 Apr 2012 16:54:26 +0200 Subject: [PATCH 38/43] [REF] Cleaned model and code: removed classmethods, moved some code to needaction_users, cleaned models. bzr revid: tde@openerp.com-20120403145426-gjhdwhxb44bme8mi --- openerp/addons/base/ir/ir.xml | 12 +- openerp/addons/base/ir/ir_needaction.py | 127 ++++++++---------- openerp/addons/base/ir/ir_ui_menu.py | 2 +- .../addons/base/security/ir.model.access.csv | 2 +- openerp/osv/orm.py | 60 ++++----- 5 files changed, 96 insertions(+), 107 deletions(-) diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 26af4365f58..877de335dcc 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -662,9 +662,9 @@ - - ir.needaction_users_rel.tree - ir.needaction_users_rel + + ir.needaction_users.tree + ir.needaction_users tree 10 @@ -676,14 +676,14 @@ - + Need action relationships - ir.needaction_users_rel + ir.needaction_users form tree,form - + Date: Tue, 3 Apr 2012 16:57:44 +0200 Subject: [PATCH 39/43] [DOC] Updated documentation. bzr revid: tde@openerp.com-20120403145744-xxibrjlzhersfmkb --- doc/api/need_action_specs.rst | 6 +++--- openerp/addons/base/ir/ir_needaction.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst index 1be92586e7f..c5c44419362 100644 --- a/doc/api/need_action_specs.rst +++ b/doc/api/need_action_specs.rst @@ -1,14 +1,14 @@ Need action mechanism ===================== -base.needaction mixin class -+++++++++++++++++++++++++++ +ir.needaction mixin class +++++++++++++++++++++++++++ This revision adds a mixin class for objects using the need action feature. Need action feature can be used by objects willing to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance validation by a manager, this mechanism allows to set a list of users asked to perform an action. -This class wraps a table (base.needaction_users_rel) that behaves like a many2many field. However, no field is added to the model inheriting from base.needaction. The mixin class manages the low-level considerations of updating relationships. Every change made on the record calls a method that updates the relationships. +This class wraps a class (ir.needaction_users) that behaves like a many2many field. However, no field is added to the model inheriting from base.needaction. The mixin class manages the low-level considerations of updating relationships. Every change made on the record calls a method that updates the relationships. Objects using the need_action feature should override the ``get_needaction_user_ids`` method. This methods returns a dictionary whose keys are record ids, and values a list of user ids, like in a many2many relationship. Therefore by defining only one method, you can specify if an action is required by defining the users that have to do it, in every possible situation. diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index ae13cc40900..391a0c2e3ff 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -92,7 +92,7 @@ class ir_needaction(osv.osv): validation by a manager, this mechanism allows to set a list of users asked to perform an action. - This class wraps a table (ir.needaction_users) that behaves + This class wraps a class (ir.needaction_users) that behaves like a many2many field. However, no field is added to the model inheriting from base.needaction. The mixin class manages the low-level considerations of updating relationships. Every change made on the From a7c8c8d6aef2f3043cb7978ae18d90aba09953be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 3 Apr 2012 17:49:41 +0200 Subject: [PATCH 40/43] [DOC] Updated doc and comments bzr revid: tde@openerp.com-20120403154941-0h83ws1av3clhxg4 --- doc/api/need_action_specs.rst | 4 ++-- openerp/addons/base/ir/ir_needaction.py | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/api/need_action_specs.rst b/doc/api/need_action_specs.rst index c5c44419362..c9f32dd60c4 100644 --- a/doc/api/need_action_specs.rst +++ b/doc/api/need_action_specs.rst @@ -13,7 +13,7 @@ This class wraps a class (ir.needaction_users) that behaves like a many2many fie Objects using the need_action feature should override the ``get_needaction_user_ids`` method. This methods returns a dictionary whose keys are record ids, and values a list of user ids, like in a many2many relationship. Therefore by defining only one method, you can specify if an action is required by defining the users that have to do it, in every possible situation. This class also offers several global services,: - - ``needaction_get_record_ids``: for a given model_name and uid, get all record ids that ask this user to perform an action. This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12) + - ``needaction_get_record_ids``: for the current model and uid, get all record ids that ask this user to perform an action. This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12) - ``needaction_get_action_count``: as ``needaction_get_record_ids`` but returns only the number of action, not the ids (performs a search with count=True) - ``needaction_get_user_record_references``: for a given uid, get all the records that ask this user to perform an action. Records are given as references, a list of tuples (model_name, record_id) @@ -25,7 +25,7 @@ This revision adds three functional fields to ``ir.ui.menu`` model : - ``needaction_uid_ctr``: integer field. If the target model uses the need action mechanism, this field gives the number of actions the current user has to perform. - ``needaction_record_ids``: many2many field. If the target model uses the need action mechanism, this field holds the ids of the record requesting the user to perform an action. -Those fields are functional, because they must be recalculated for each user, and each time menus are displayed. ``needaction_uid_ctr`` takes into account the domain of the action, in order to display accurate numbers. +Those fields are functional, because they depend on the user and must therefore be computed at every refresh, each time menus are displayed. The use of the need action mechanism is done by taking into account the action domain in order to display accurate results. When computing the value of the functional fields, the ids of records asking the user to perform an action is concatenated to the action domain. A counting search is then performed on the model, giving back the number of action the users has to perform, limited to the domain of the action. Addon implementation example ++++++++++++++++++++++++++++ diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 391a0c2e3ff..db4ce5b11ff 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -83,7 +83,7 @@ class ir_needaction_users(osv.osv): return True -class ir_needaction(osv.osv): +class ir_needaction_mixin(osv.osv): '''Mixin class for objects using the need action feature. Need action feature can be used by objects willing to be able to @@ -106,7 +106,7 @@ class ir_needaction(osv.osv): that have to do it, in every possible situation. This class also offers several global services,: - - ``needaction_get_record_ids``: for a given model_name and uid, get + - ``needaction_get_record_ids``: for the current model and uid, get all record ids that ask this user to perform an action. This mechanism is used for instance to display the number of pending actions in menus, such as Leads (12) @@ -117,7 +117,7 @@ class ir_needaction(osv.osv): the records that ask this user to perform an action. Records are given as references, a list of tuples (model_name, record_id) ''' - _name = 'ir.needaction' + _name = 'ir.ir_needaction_mixin' _description = 'Need action of users on records API' #------------------------------------------------------ @@ -125,6 +125,9 @@ class ir_needaction(osv.osv): #------------------------------------------------------ def get_needaction_user_ids(self, cr, uid, ids, context=None): + """ Returns the user_ids that have to perform an action + :return: dict { record_id: [user_ids], } + """ return dict.fromkeys(ids, []) def create(self, cr, uid, values, context=None): From 90e1433157bbed97641b026fddb97e270a78f358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 3 Apr 2012 18:07:25 +0200 Subject: [PATCH 41/43] [IMP] Removed unused import; added forgottent context to search. bzr revid: tde@openerp.com-20120403160725-lprixelmtx5cq87l --- openerp/osv/orm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index a59ecb941ff..81fc9b81976 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -57,7 +57,6 @@ from lxml import etree import fields import openerp import openerp.netsvc as netsvc -import openerp.pooler as pooler import openerp.tools as tools from openerp.tools.config import config from openerp.tools.safe_eval import safe_eval as eval @@ -4901,7 +4900,7 @@ class BaseModel(object): new_domain = eval(domain) + [('id', 'in', ids)] else: new_domain = [('id', 'in', ids)] - return (True, self.search(cr, uid, new_domain, limit=limit, order=order, count=True), ids) + return (True, self.search(cr, uid, new_domain, limit=limit, order=order, count=True, context=context), ids) else: return (False, 0, []) From 1ba19a0f50cf8126b993c5427dff9703ebbf4914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 3 Apr 2012 18:29:16 +0200 Subject: [PATCH 42/43] [FIX] Wrong class name bzr revid: tde@openerp.com-20120403162916-lm58en1xu9zyv0co --- openerp/addons/base/ir/ir_needaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index db4ce5b11ff..6f1e07787c6 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -117,7 +117,7 @@ class ir_needaction_mixin(osv.osv): the records that ask this user to perform an action. Records are given as references, a list of tuples (model_name, record_id) ''' - _name = 'ir.ir_needaction_mixin' + _name = 'ir.needaction_mixin' _description = 'Need action of users on records API' #------------------------------------------------------ From cffec497857cdd569e65b64c6b2096c6c8f5f986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 3 Apr 2012 18:41:27 +0200 Subject: [PATCH 43/43] [FIX] Propagated class name change bzr revid: tde@openerp.com-20120403164127-5dy7ors0vm5u7zzi --- openerp/addons/base/ir/ir_needaction.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 6f1e07787c6..3fcd56affae 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -135,7 +135,7 @@ class ir_needaction_mixin(osv.osv): context = {} needact_table_obj = self.pool.get('ir.needaction_users') # perform create - obj_id = super(ir_needaction, self).create(cr, uid, values, context=context) + obj_id = super(ir_needaction_mixin, self).create(cr, uid, values, context=context) # link user_ids needaction_user_ids = self.get_needaction_user_ids(cr, uid, [obj_id], context=context) needact_table_obj.create_users(cr, uid, [obj_id], self._name, needaction_user_ids[obj_id], context=context) @@ -146,7 +146,7 @@ class ir_needaction_mixin(osv.osv): context = {} needact_table_obj = self.pool.get('ir.needaction_users') # perform write - write_res = super(ir_needaction, self).write(cr, uid, ids, values, context=context) + write_res = super(ir_needaction_mixin, self).write(cr, uid, ids, values, context=context) # get and update user_ids needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) for id in ids: @@ -160,7 +160,7 @@ class ir_needaction_mixin(osv.osv): needact_table_obj = self.pool.get('ir.needaction_users') needact_table_obj.unlink_users(cr, uid, ids, self._name, context=context) # perform unlink - return super(ir_needaction, self).unlink(cr, uid, ids, context=context) + return super(ir_needaction_mixin, self).unlink(cr, uid, ids, context=context) #------------------------------------------------------ # Need action API