[MERGE] Merged with branch holding need_action mechanism

bzr revid: tde@openerp.com-20120330120359-gd5gnuico0vshw0v
This commit is contained in:
Thibault Delavallée 2012-03-30 14:03:59 +02:00
commit 97655cc8d2
4 changed files with 49 additions and 20 deletions

View File

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

View File

@ -34,6 +34,7 @@ class base_needaction_users_rel(osv.osv):
'''
_name = 'base.needaction_users_rel'
_description = 'Needaction relationship table'
_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 = {
}

View File

@ -258,14 +258,15 @@ 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:
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 = {
@ -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, 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=[

View File

@ -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: [has_needaction=False, needaction_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)]