[MERGE] client_actions and ir.todo rework by xmo

bzr revid: al@openerp.com-20110804115501-prpmo6lwrm6z989o
This commit is contained in:
Antony Lesuisse 2011-08-04 13:55:01 +02:00
commit 934e7e8f8e
10 changed files with 165 additions and 135 deletions

View File

@ -54,7 +54,6 @@
'module/wizard/base_import_language_view.xml',
'module/wizard/base_module_upgrade_view.xml',
'module/wizard/base_module_configuration_view.xml',
'module/wizard/base_module_shortcut_data.xml',
'module/wizard/base_export_language_view.xml',
'module/wizard/base_update_translations_view.xml',
'res/res_request_view.xml',

View File

@ -106,6 +106,11 @@ CREATE TABLE ir_act_server (
)
INHERITS (ir_actions);
CREATE TABLE ir_act_client (
primary key(id)
)
INHERITS (ir_actions);
CREATE TABLE ir_ui_view (
id serial NOT NULL,

View File

@ -306,9 +306,8 @@
<record id="config_wizard_simple_view" model="ir.actions.todo">
<field name="action_id" ref="action_config_simple_view_form"/>
<field name="category_id" ref="category_administration_config"/>
<field name="type">special</field>
<field name="type">automatic</field>
<field name="sequence">1</field>
<field name="state">skip</field>
</record>
</data>

View File

@ -1889,7 +1889,7 @@
<field name="type"/>
<field name="state" readonly="1"/>
<button name="action_launch" states="open" string="Launch" type="object" icon="gtk-execute" help="Launch Configuration Wizard"/>
<button name="action_open" states="cancel,skip,done"
<button name="action_open" states="done"
string="Todo" type="object" help="Set as Todo"
icon="gtk-convert"/>
</tree>
@ -1913,7 +1913,7 @@
<group colspan="4" col="4">
<field name="state" colspan="2" readonly="1"/>
<button name="action_launch" states="open" string="Launch" type="object" icon="gtk-execute" help="Launch Configuration Wizard"/>
<button name="action_open" states="cancel,skip,done"
<button name="action_open" states="done"
string="Set as Todo" type="object"
icon="gtk-convert"/>
</group>

View File

@ -18,20 +18,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import fields,osv
from tools.safe_eval import safe_eval as eval
import tools
import time
from tools.config import config
from tools.translate import _
import netsvc
import logging
import re
import ast
import copy
import logging
import os
import re
import time
import tools
from xml import dom
import netsvc
from osv import fields,osv
from report.report_sxw import report_sxw, report_rml
from tools.config import config
from tools.safe_eval import safe_eval as eval
from tools.translate import _
class actions(osv.osv):
_name = 'ir.actions.actions'
@ -162,13 +163,13 @@ class act_window(osv.osv):
def _invalid_model_msg(self, cr, uid, ids, context=None):
return _('Invalid model name in the action definition.')
_constraints = [
(_check_model, _invalid_model_msg, ['res_model','src_model'])
]
def _views_get_fnc(self, cr, uid, ids, name, arg, context=None):
"""Returns an ordered list of the specific view modes that should be
"""Returns an ordered list of the specific view modes that should be
enabled when displaying the result of this action, along with the
ID of the specific view to use for each mode, if any were required.
@ -208,7 +209,7 @@ class act_window(osv.osv):
if act.search_view_id:
search_view_id = act.search_view_id.id
else:
res_view = self.pool.get('ir.ui.view').search(cr, uid,
res_view = self.pool.get('ir.ui.view').search(cr, uid,
[('model','=',act.res_model),('type','=','search'),
('inherit_id','=',False)], context=context)
if res_view:
@ -808,7 +809,7 @@ class ir_actions_todo_category(osv.osv):
_name = 'ir.actions.todo.category'
_description = "Configuration Wizard Category"
_columns = {
'name':fields.char('Name', size=64, translate=True, required=True),
'name':fields.char('Name', size=64, translate=True, required=True),
'sequence': fields.integer('Sequence'),
'wizards_ids': fields.one2many('ir.actions.todo', 'category_id', 'Configuration Wizards'),
}
@ -816,10 +817,9 @@ ir_actions_todo_category()
# This model use to register action services.
TODO_STATES = [('open', 'To Do'),
('done', 'Done'),
('skip','Skipped'),
('cancel','Cancelled')]
('done', 'Done')]
TODO_TYPES = [('manual', 'Launch Manually'),
('automatic', 'Launch Automatically')]
class ir_actions_todo(osv.osv):
"""
Configuration Wizards
@ -833,10 +833,9 @@ class ir_actions_todo(osv.osv):
'sequence': fields.integer('Sequence'),
'state': fields.selection(TODO_STATES, string='State', required=True),
'name': fields.char('Name', size=64),
'type': fields.selection([('special','Special'),('normal','Normal'),('normal_recurring','Normal Recurring')], 'Type', required=True,
help="""Special: the wizard is run whenever the system is reconfigured.
Normal: the wizard is visible in the configuration panel until it is done.
Normal Recurring: the wizard is visible in the configuration panel regardless of its state."""),
'type': fields.selection(TODO_TYPES, 'Type', required=True,
help="""Manual: Launched manually.
Automatic: Runs whenever the system is reconfigured."""),
'groups_id': fields.many2many('res.groups', 'res_groups_action_rel', 'uid', 'gid', 'Groups'),
'note': fields.text('Text', translate=True),
'category_id': fields.many2one('ir.actions.todo.category','Category'),
@ -844,33 +843,108 @@ Normal Recurring: the wizard is visible in the configuration panel regardless of
_defaults={
'state': 'open',
'sequence': 10,
'type': 'special',
'type': 'manual',
}
_order="sequence,name,id"
def action_launch(self, cr, uid, ids, context=None):
""" Launch Action of Wizard"""
if context is None:
context = {}
wizard_id = ids and ids[0] or False
wizard = self.browse(cr, uid, wizard_id, context=context)
if wizard.type == 'automatic':
wizard.write({'state': 'done'})
res = self.pool.get('ir.actions.act_window').read(cr, uid, wizard.action_id.id, [], context=context)
res.update({'nodestroy': True})
res['nodestroy'] = True
# Open a specific record when res_id is provided in the context
if res.get('context'):
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
ctx = eval(res['context'], {'user': user})
if ctx.get('res_id'):
res.update({'res_id': ctx.pop('res_id')})
res.update({'context': ctx})
res.update(
res_id=ctx.pop('res_id'),
context=ctx)
return res
def action_open(self, cr, uid, ids, context=None):
""" Sets configuration wizard in TODO state"""
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
def progress(self, cr, uid, context=None):
""" Returns a dict with 3 keys {todo, done, total}.
These keys all map to integers and provide the number of todos
marked as open, the total number of todos and the number of
todos not open (which is basically a shortcut to total-todo)
:rtype: dict
"""
user_groups = set(map(
lambda x: x.id,
self.pool['res.users'].browse(cr, uid, [uid], context=context)[0].groups_id))
def groups_match(todo):
""" Checks if the todo's groups match those of the current user
"""
return not todo.groups_id \
or bool(user_groups.intersection((
group.id for group in todo.groups_id)))
done = filter(
groups_match,
self.browse(cr, uid,
self.search(cr, uid, ['&', ('state', '!=', 'open'), ('type', '=', 'manual')], context=context),
context=context))
total = filter(
groups_match,
self.browse(cr, uid,
self.search(cr, uid, [('type', '=', 'manual')], context=context),
context=context))
return {
'done': len(done),
'total': len(total),
'todo': len(total) - len(done)
}
ir_actions_todo()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class act_client(osv.osv):
_name = 'ir.actions.client'
_inherit = 'ir.actions.actions'
_table = 'ir_act_client'
_sequence = 'ir_actions_id_seq'
_order = 'name'
def _get_params(self, cr, uid, ids, field_name, arg, context):
return dict([
((record.id, ast.literal_eval(record.params_store))
if record.params_store else (record.id, False))
for record in self.browse(cr, uid, ids, context=context)
])
def _set_params(self, cr, uid, ids, field_name, field_value, arg, context):
assert isinstance(field_value, dict), "params can only be dictionaries"
for record in self.browse(cr, uid, ids, context=context):
record.write({field_name: repr(field_value)})
_columns = {
'tag': fields.char('Client action tag', size=64, required=True,
help="An arbitrary string, interpreted by the client"
" according to its own needs and wishes. There "
"is no central tag repository across clients."),
'params': fields.function(_get_params, fnct_inv=_set_params,
type='binary', method=True,
string="Supplementary arguments",
help="Arguments sent to the client along with"
"the view tag"),
'params_store': fields.binary("Params storage", readonly=True)
}
_defaults = {
'type': 'ir.actions.client',
}
act_client()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -273,6 +273,7 @@ class ir_ui_menu(osv.osv):
('ir.actions.wizard', 'ir.actions.wizard'),
('ir.actions.url', 'ir.actions.url'),
('ir.actions.server', 'ir.actions.server'),
('ir.actions.client', 'ir.actions.client'),
]),
}

View File

@ -27,7 +27,8 @@ class base_module_configuration(osv.osv_memory):
_name = "base.module.configuration"
def start(self, cr, uid, ids, context=None):
todo_ids = self.pool.get('ir.actions.todo').search(cr, uid, ['|', '|', ('type','=','normal_recurring'), ('state', '=', 'open'), '&', ('state', '=', 'skip'), ('type', '=', 'special')])
todo_ids = self.pool.get('ir.actions.todo').search(cr, uid,
['|', ('type','=','recurring'), ('state', '=', 'open')])
if not todo_ids:
# When there is no wizard todo it will display message
data_obj = self.pool.get('ir.model.data')

View File

@ -16,28 +16,5 @@
</field>
</record>
<record id="action_start_configurator" model="ir.actions.server">
<field name="name">Start Configuration</field>
<field name="model_id" ref="model_base_module_configuration"/>
<field name="state">code</field>
<field name="code">action = obj.start()</field>
</record>
<menuitem name="Add More Features"
action="action_start_configurator"
id="menu_view_base_module_configuration" parent="base.menu_config"
type="server" icon="STOCK_EXECUTE" sequence="100" />
<record model="ir.values" id="action_todo_config">
<field name="model_id" ref="model_ir_actions_todo" />
<field name="object" eval="1" />
<field name="name">Start Configuration</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.server,' + str(ref('action_start_configurator'))" />
<field name="key">action</field>
<field name="model">ir.actions.todo</field>
</record>
</data>
</openerp>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="ir_ui_view_sc_configuration" model="ir.ui.view_sc">
<field name="name">Add More Features</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="menu_view_base_module_configuration"/>
</record>
</data>
</openerp>

View File

@ -19,7 +19,7 @@
#
##############################################################################
import logging
from operator import attrgetter
from operator import attrgetter, itemgetter
from osv import osv, fields
from tools.translate import _
@ -37,16 +37,14 @@ class res_config_configurable(osv.osv_memory):
'''
_name = 'res.config'
_inherit = 'ir.wizard.screen'
logger = netsvc.Logger()
__logger = logging.getLogger(_name)
def get_current_progress(self, cr, uid, context=None):
'''Return a description the current progress of configuration:
a tuple of (non_open_todos:int, total_todos: int)
'''
todo_pool = self.pool.get('ir.actions.todo')
return (todo_pool.search_count(cr, uid, [('state','<>','open')], context),
todo_pool.search_count(cr, uid, [], context))
return itemgetter('done', 'total')(
self.pool.get('ir.actions.todo').progress(cr, uid, context=context))
def _progress(self, cr, uid, context=None):
closed, total = self.get_current_progress(cr, uid, context=context)
@ -63,51 +61,35 @@ class res_config_configurable(osv.osv_memory):
)
def _next_action(self, cr, uid, context=None):
todos = self.pool.get('ir.actions.todo')
self.__logger.info('getting next %s', todos)
# Don't forget to change the domain in search view, if this condition is changed
active_todos = todos.search(cr, uid, [('state','=','open')],
limit=1)
if active_todos:
todo_obj = todos.browse(cr, uid, active_todos[0], context=None)
todo_groups = map(lambda x:x.id, todo_obj.groups_id)
dont_skip_todo = True
if todo_groups:
cr.execute("select 1 from res_groups_users_rel where uid=%s and gid IN %s",(uid, tuple(todo_groups),))
dont_skip_todo = bool(cr.fetchone())
if dont_skip_todo:
res = todos.browse(cr, uid, active_todos[0], context=None)
# A wizard opening directly a form instead of calling
# next_action will remain in the todo state so we set it to
# done ourselves.
if res.action_id.target == 'current':
res.write({'state': 'done'})
return res
else:
todos.write(cr, uid, active_todos[0], {'state':'skip'}, context=None)
return self._next_action(cr, uid)
return None
Todos = self.pool['ir.actions.todo']
self.__logger.info('getting next %s', Todos)
def _set_previous_todo(self, cr, uid, state, context=None):
""" lookup the previous (which is still the next at this point)
ir.actions.todo, set it to whatever state was provided.
"""
# this is ultra brittle, but apart from storing the todo id
# into the res.config view, I'm not sure how to get the
# "previous" todo
previous_todo = self._next_action(cr, uid, context=context)
if not previous_todo:
self.__logger.warn(_("Couldn't find previous ir.actions.todo"))
return
previous_todo.write({'state':state})
active_todos = Todos.browse(cr, uid,
Todos.search(cr, uid, ['&', ('type', '=', 'automatic'), ('state','=','open')]),
context=context)
user_groups = set(map(
lambda g: g.id,
self.pool['res.users'].browse(cr, uid, [uid], context=context)[0].groups_id))
valid_todos_for_user = [
todo for todo in active_todos
if not todo.groups_id or bool(user_groups.intersection((
group.id for group in todo.groups_id)))
]
if valid_todos_for_user:
return valid_todos_for_user[0]
return None
def _next(self, cr, uid, context=None):
self.__logger.info('getting next operation')
next = self._next_action(cr, uid)
next = self._next_action(cr, uid, context=context)
self.__logger.info('next action is %s', next)
if next:
res = next.action_launch(context=context)
res.update({'nodestroy': False})
res['nodestroy'] = False
return res
self.__logger.info('all configuration actions have been executed')
@ -116,11 +98,6 @@ class res_config_configurable(osv.osv_memory):
return self.pool.get(current_user_menu.type).read(cr, uid, current_user_menu.id)
def start(self, cr, uid, ids, context=None):
todo_pool = self.pool.get('ir.actions.todo')
ids2 = todo_pool.search(cr, uid, [], context=context)
for todo in todo_pool.browse(cr, uid, ids2, context=context):
if (todo.type=='normal_recurring'):
todo.write({'state':'open'})
return self.next(cr, uid, ids, context)
def next(self, cr, uid, ids, context=None):
@ -162,8 +139,7 @@ class res_config_configurable(osv.osv_memory):
an action dictionary -- executes the action provided by calling
``next``.
"""
self._set_previous_todo(cr, uid, state='done', context=context)
next = self.execute(cr, uid, ids, context=None)
next = self.execute(cr, uid, ids, context=context)
if next: return next
return self.next(cr, uid, ids, context=context)
@ -175,8 +151,7 @@ class res_config_configurable(osv.osv_memory):
an action dictionary -- executes the action provided by calling
``next``.
"""
self._set_previous_todo(cr, uid, state='skip', context=context)
next = self.cancel(cr, uid, ids, context=None)
next = self.cancel(cr, uid, ids, context=context)
if next: return next
return self.next(cr, uid, ids, context=context)
@ -191,8 +166,7 @@ class res_config_configurable(osv.osv_memory):
an action dictionary -- executes the action provided by calling
``next``.
"""
self._set_previous_todo(cr, uid, state='cancel', context=context)
next = self.cancel(cr, uid, ids, context=None)
next = self.cancel(cr, uid, ids, context=context)
if next: return next
return self.next(cr, uid, ids, context=context)
@ -296,10 +270,24 @@ class res_config_installer(osv.osv_memory):
_install_if = {}
def already_installed(self, cr, uid, context=None):
""" For each module, check if it's already installed and if it
is return its name
:returns: a list of the already installed modules in this
installer
:rtype: [str]
"""
return map(attrgetter('name'),
self._already_installed(cr, uid, context=context))
def _already_installed(self, cr, uid, context=None):
""" For each module (boolean fields in a res.config.installer),
check if it's already installed (either 'to install', 'to upgrade' or 'installed')
and if it is, check it by default
check if it's already installed (either 'to install', 'to upgrade'
or 'installed') and if it is return the module's browse_record
:returns: a list of all installed modules in this installer
:rtype: [browse_record]
"""
modules = self.pool.get('ir.module.module')
@ -351,8 +339,8 @@ class res_config_installer(osv.osv_memory):
if base.issuperset(requirements)
for module in consequences)
return (base | hooks_results | additionals) - set(
map(attrgetter('name'), self._already_installed(cr, uid, context)))
return (base | hooks_results | additionals).difference(
self.already_installed(cr, uid, context))
def default_get(self, cr, uid, fields_list, context=None):
''' If an addon is already installed, check it by default
@ -362,8 +350,7 @@ class res_config_installer(osv.osv_memory):
return dict(defaults,
**dict.fromkeys(
map(attrgetter('name'),
self._already_installed(cr, uid, context=context)),
self.already_installed(cr, uid, context=context),
True))
def fields_get(self, cr, uid, fields=None, context=None, write_access=True):
@ -374,12 +361,12 @@ class res_config_installer(osv.osv_memory):
fields = super(res_config_installer, self).fields_get(
cr, uid, fields, context, write_access)
for module in self._already_installed(cr, uid, context=context):
if module.name not in fields:
for name in self.already_installed(cr, uid, context=context):
if name not in fields:
continue
fields[module.name].update(
fields[name].update(
readonly=True,
help= ustr(fields[module.name].get('help', '')) +
help= ustr(fields[name].get('help', '')) +
_('\n\nThis addon is already installed on your system'))
return fields