[MERGE] Merged with new base.needaction implementation
bzr revid: tde@openerp.com-20120315101558-gdxas1qywl15zx7k
This commit is contained in:
commit
e09d180008
|
@ -0,0 +1,34 @@
|
|||
Need action 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.
|
||||
|
||||
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).
|
||||
|
||||
A menu in Settings/Users has been added to allows having a quick look to need_action_user_ids.
|
||||
|
||||
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
|
|
@ -14,3 +14,4 @@ New feature merges
|
|||
:maxdepth: 1
|
||||
|
||||
api/user_img_specs
|
||||
api/need_action_specs
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2009-Today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
|
||||
class base_needaction_users_rel(osv.osv):
|
||||
'''
|
||||
base_needaction_users_rel holds data related to the needaction
|
||||
mechanism inside OpenERP. A needaction is characterized by:
|
||||
- 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 the 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 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 ot 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.
|
||||
|
||||
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'
|
||||
|
||||
_columns = {
|
||||
}
|
||||
|
||||
#------------------------------------------------------
|
||||
# need action relationship management
|
||||
#------------------------------------------------------
|
||||
|
||||
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')
|
||||
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 _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 _update_users(self, cr, uid, ids, user_ids, context=None):
|
||||
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)
|
||||
return True
|
||||
|
||||
#------------------------------------------------------
|
||||
# Addon API
|
||||
#------------------------------------------------------
|
||||
|
||||
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, 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, [obj_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 = {}
|
||||
# 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)
|
||||
return write_res
|
||||
|
||||
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, context=context)
|
||||
|
||||
#------------------------------------------------------
|
||||
# General API
|
||||
#------------------------------------------------------
|
||||
|
||||
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 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')
|
||||
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
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="view_notification_tree">
|
||||
<field name="name">base.needaction_users_rel.tree</field>
|
||||
<field name="model">base.needaction_users_rel</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Subscription">
|
||||
<field name="user_id"/>
|
||||
<field name="res_model"/>
|
||||
<field name="res_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_needaction_users_rel" model="ir.actions.act_window">
|
||||
<field name="name">Need action relationships</field>
|
||||
<field name="res_model">base.needaction_users_rel</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_needaction_users_rel" name="Need actions" parent="base.menu_users" sequence="20" action="action_view_needaction_users_rel" groups="base.group_extended"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -34,7 +34,6 @@ import res_request
|
|||
import res_lang
|
||||
import res_log
|
||||
import res_widget
|
||||
import res_needaction
|
||||
import ir_property
|
||||
|
||||
import wizard
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2009-Today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
|
||||
class res_needaction(osv.osv):
|
||||
'''Mixin class for object implementing a need_action mechanism
|
||||
|
||||
Need action mechanism can be used by objects wanting 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 add have a field
|
||||
linking to 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. Setting an user_id is done
|
||||
through redefining the get_needaction_user_id method, that
|
||||
stores the need_action_user_id function fields.
|
||||
|
||||
This mechanism is used for instance to display the number of pending action
|
||||
in menus.
|
||||
'''
|
||||
_name = 'res.needaction'
|
||||
_description = 'Need action Engine'
|
||||
|
||||
def get_needaction_user_id(self, cr, uid, ids, name, arg, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
result = {}
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
result[obj.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:
|
Loading…
Reference in New Issue