2009-12-03 15:11:22 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
2010-01-23 12:43:35 +00:00
|
|
|
#
|
2009-12-03 15:11:22 +00:00
|
|
|
# OpenERP, Open Source Management Solution
|
|
|
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
|
|
|
#
|
|
|
|
# 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
|
2010-01-23 12:43:35 +00:00
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2009-12-03 15:11:22 +00:00
|
|
|
#
|
|
|
|
##############################################################################
|
2010-11-08 10:08:57 +00:00
|
|
|
import logging
|
2010-01-23 12:43:35 +00:00
|
|
|
from operator import attrgetter
|
|
|
|
|
2009-12-04 12:14:52 +00:00
|
|
|
from osv import osv, fields
|
2010-01-23 14:37:05 +00:00
|
|
|
from tools.translate import _
|
2009-12-03 15:11:22 +00:00
|
|
|
import netsvc
|
2010-01-06 07:53:30 +00:00
|
|
|
import pooler
|
2009-12-03 15:11:22 +00:00
|
|
|
|
2010-05-05 04:50:13 +00:00
|
|
|
|
2009-12-03 15:11:22 +00:00
|
|
|
class res_config_configurable(osv.osv_memory):
|
2009-12-10 07:34:13 +00:00
|
|
|
''' Base classes for new-style configuration items
|
|
|
|
|
|
|
|
Configuration items should inherit from this class, implement
|
|
|
|
the execute method (and optionally the cancel one) and have
|
|
|
|
their view inherit from the related res_config_view_base view.
|
|
|
|
'''
|
2009-12-04 10:58:21 +00:00
|
|
|
_name = 'res.config'
|
2010-10-04 14:33:36 +00:00
|
|
|
_inherit = 'ir.wizard.screen'
|
2009-12-03 15:11:22 +00:00
|
|
|
logger = netsvc.Logger()
|
2010-11-08 10:08:57 +00:00
|
|
|
__logger = logging.getLogger(_name)
|
2009-12-03 15:11:22 +00:00
|
|
|
|
2010-08-09 10:55:27 +00:00
|
|
|
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)
|
|
|
|
'''
|
|
|
|
return (self.pool.get('ir.actions.todo')\
|
|
|
|
.search_count(cr, uid, [('state','<>','open')], context),
|
|
|
|
self.pool.get('ir.actions.todo')\
|
|
|
|
.search_count(cr, uid, [], context))
|
|
|
|
|
2009-12-04 12:14:52 +00:00
|
|
|
def _progress(self, cr, uid, context=None):
|
2010-08-09 10:55:27 +00:00
|
|
|
closed, total = self.get_current_progress(cr, uid, context=context)
|
2009-12-04 12:14:52 +00:00
|
|
|
if total:
|
2010-08-09 10:41:21 +00:00
|
|
|
return round(closed*100./total)
|
2009-12-04 12:14:52 +00:00
|
|
|
return 100.
|
2010-05-11 09:38:58 +00:00
|
|
|
|
2009-12-04 12:14:52 +00:00
|
|
|
_columns = dict(
|
2010-05-05 04:50:13 +00:00
|
|
|
progress = fields.float('Configuration Progress', readonly=True),
|
2010-10-04 14:33:36 +00:00
|
|
|
)
|
|
|
|
|
2009-12-04 12:14:52 +00:00
|
|
|
_defaults = dict(
|
2010-05-05 04:50:13 +00:00
|
|
|
progress = _progress,
|
2010-10-04 14:33:36 +00:00
|
|
|
)
|
2009-12-04 12:14:52 +00:00
|
|
|
|
2010-08-30 13:04:48 +00:00
|
|
|
def _next_action(self, cr, uid, context=None):
|
2009-12-03 15:11:22 +00:00
|
|
|
todos = self.pool.get('ir.actions.todo')
|
2010-11-08 10:08:57 +00:00
|
|
|
self.__logger.info('getting next %s', todos)
|
2010-04-18 20:07:32 +00:00
|
|
|
active_todos = todos.search(cr, uid, [('state','=','open')],
|
2010-01-26 16:42:37 +00:00
|
|
|
limit=1)
|
2009-12-03 15:11:22 +00:00
|
|
|
if active_todos:
|
2010-04-28 06:54:06 +00:00
|
|
|
todo_obj = todos.browse(cr, uid, active_todos[0], context=None)
|
|
|
|
todo_groups = map(lambda x:x.id, todo_obj.groups_id)
|
2010-11-08 10:41:28 +00:00
|
|
|
dont_skip_todo = True
|
2010-04-28 06:54:06 +00:00
|
|
|
if todo_groups:
|
2010-06-18 14:05:37 +00:00
|
|
|
cr.execute("select 1 from res_groups_users_rel where uid=%s and gid IN %s",(uid, tuple(todo_groups),))
|
2010-04-28 06:54:06 +00:00
|
|
|
dont_skip_todo = bool(cr.fetchone())
|
|
|
|
if dont_skip_todo:
|
|
|
|
return todos.browse(cr, uid, active_todos[0], context=None)
|
|
|
|
else:
|
|
|
|
todos.write(cr, uid, active_todos[0], {'state':'skip'}, context=None)
|
|
|
|
return self._next_action(cr, uid)
|
2009-12-03 15:11:22 +00:00
|
|
|
return None
|
|
|
|
|
2010-08-30 13:04:48 +00:00
|
|
|
def _set_previous_todo(self, cr, uid, state, context=None):
|
2010-01-26 16:42:37 +00:00
|
|
|
""" 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
|
2010-01-26 18:45:11 +00:00
|
|
|
# into the res.config view, I'm not sure how to get the
|
|
|
|
# "previous" todo
|
2010-08-30 13:04:48 +00:00
|
|
|
previous_todo = self._next_action(cr, uid, context=context)
|
2010-01-26 16:42:37 +00:00
|
|
|
if not previous_todo:
|
2010-11-08 10:44:12 +00:00
|
|
|
self.__logger.warn(_("Couldn't find previous ir.actions.todo"))
|
|
|
|
return
|
2010-01-26 16:42:37 +00:00
|
|
|
previous_todo.write({'state':state})
|
|
|
|
|
2010-08-30 13:04:48 +00:00
|
|
|
def _next(self, cr, uid, context=None):
|
2010-11-08 10:08:57 +00:00
|
|
|
self.__logger.info('getting next operation')
|
2009-12-03 15:11:22 +00:00
|
|
|
next = self._next_action(cr, uid)
|
2010-11-08 10:08:57 +00:00
|
|
|
self.__logger.info('next action is %s', next)
|
2009-12-03 15:11:22 +00:00
|
|
|
if next:
|
|
|
|
action = next.action_id
|
|
|
|
return {
|
|
|
|
'view_mode': action.view_mode,
|
|
|
|
'view_type': action.view_type,
|
|
|
|
'view_id': action.view_id and [action.view_id.id] or False,
|
|
|
|
'res_model': action.res_model,
|
|
|
|
'type': action.type,
|
|
|
|
'target': action.target,
|
2010-06-25 09:22:56 +00:00
|
|
|
}
|
2010-11-08 10:08:57 +00:00
|
|
|
self.__logger.info('all configuration actions have been executed')
|
2009-12-16 13:33:35 +00:00
|
|
|
|
|
|
|
current_user_menu = self.pool.get('res.users')\
|
|
|
|
.browse(cr, uid, uid).menu_id
|
|
|
|
# return the action associated with the menu
|
2010-11-19 11:55:11 +00:00
|
|
|
return self.pool.get(current_user_menu.type)\
|
|
|
|
.read(cr, uid, current_user_menu.id)
|
|
|
|
|
2010-04-18 20:07:32 +00:00
|
|
|
def start(self, cr, uid, ids, context=None):
|
|
|
|
ids2 = self.pool.get('ir.actions.todo').search(cr, uid, [], context=context)
|
|
|
|
for todo in self.pool.get('ir.actions.todo').browse(cr, uid, ids2, context=context):
|
|
|
|
if (todo.restart=='always') or (todo.restart=='onskip' and (todo.state in ('skip','cancel'))):
|
|
|
|
todo.write({'state':'open'})
|
|
|
|
return self.next(cr, uid, ids, context)
|
|
|
|
|
2009-12-10 08:06:50 +00:00
|
|
|
def next(self, cr, uid, ids, context=None):
|
2010-01-26 18:45:11 +00:00
|
|
|
""" Returns the next todo action to execute (using the default
|
2010-01-26 16:42:37 +00:00
|
|
|
sort order)
|
|
|
|
"""
|
2010-08-30 13:04:48 +00:00
|
|
|
return self._next(cr, uid, context=context)
|
2009-12-10 07:32:13 +00:00
|
|
|
|
|
|
|
def execute(self, cr, uid, ids, context=None):
|
2010-01-26 16:42:37 +00:00
|
|
|
""" Method called when the user clicks on the ``Next`` button.
|
|
|
|
|
|
|
|
Execute *must* be overloaded unless ``action_next`` is overloaded
|
|
|
|
(which is something you generally don't need to do).
|
|
|
|
|
|
|
|
If ``execute`` returns an action dictionary, that action is executed
|
|
|
|
rather than just going to the next configuration item.
|
|
|
|
"""
|
2009-12-10 07:32:13 +00:00
|
|
|
raise NotImplementedError(
|
|
|
|
'Configuration items need to implement execute')
|
|
|
|
def cancel(self, cr, uid, ids, context=None):
|
2010-01-26 16:42:37 +00:00
|
|
|
""" Method called when the user click on the ``Skip`` button.
|
|
|
|
|
|
|
|
``cancel`` should be overloaded instead of ``action_skip``. As with
|
|
|
|
``execute``, if it returns an action dictionary that action is
|
|
|
|
executed in stead of the default (going to the next configuration item)
|
|
|
|
|
|
|
|
The default implementation is a NOOP.
|
2010-01-26 18:45:11 +00:00
|
|
|
|
|
|
|
``cancel`` is also called by the default implementation of
|
|
|
|
``action_cancel``.
|
2010-01-26 16:42:37 +00:00
|
|
|
"""
|
2009-12-10 07:32:13 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
def action_next(self, cr, uid, ids, context=None):
|
2010-01-26 16:42:37 +00:00
|
|
|
""" Action handler for the ``next`` event.
|
|
|
|
|
|
|
|
Sets the status of the todo the event was sent from to
|
|
|
|
``done``, calls ``execute`` and -- unless ``execute`` returned
|
|
|
|
an action dictionary -- executes the action provided by calling
|
|
|
|
``next``.
|
|
|
|
"""
|
2010-11-08 10:47:18 +00:00
|
|
|
self._set_previous_todo(cr, uid, state='done', context=context)
|
2009-12-10 07:32:13 +00:00
|
|
|
next = self.execute(cr, uid, ids, context=None)
|
|
|
|
if next: return next
|
2009-12-10 08:06:50 +00:00
|
|
|
return self.next(cr, uid, ids, context=context)
|
|
|
|
|
2009-12-10 07:32:13 +00:00
|
|
|
def action_skip(self, cr, uid, ids, context=None):
|
2010-01-26 16:42:37 +00:00
|
|
|
""" Action handler for the ``skip`` event.
|
|
|
|
|
|
|
|
Sets the status of the todo the event was sent from to
|
|
|
|
``skip``, calls ``cancel`` and -- unless ``cancel`` returned
|
|
|
|
an action dictionary -- executes the action provided by calling
|
|
|
|
``next``.
|
|
|
|
"""
|
2010-11-08 10:47:18 +00:00
|
|
|
self._set_previous_todo(cr, uid, state='skip', context=context)
|
2010-01-26 16:42:37 +00:00
|
|
|
next = self.cancel(cr, uid, ids, context=None)
|
|
|
|
if next: return next
|
|
|
|
return self.next(cr, uid, ids, context=context)
|
|
|
|
|
|
|
|
def action_cancel(self, cr, uid, ids, context=None):
|
|
|
|
""" Action handler for the ``cancel`` event. That event isn't
|
|
|
|
generated by the res.config.view.base inheritable view, the
|
|
|
|
inherited view has to overload one of the buttons (or add one
|
|
|
|
more).
|
|
|
|
|
|
|
|
Sets the status of the todo the event was sent from to
|
|
|
|
``cancel``, calls ``cancel`` and -- unless ``cancel`` returned
|
|
|
|
an action dictionary -- executes the action provided by calling
|
|
|
|
``next``.
|
|
|
|
"""
|
2010-11-08 10:47:18 +00:00
|
|
|
self._set_previous_todo(cr, uid, state='cancel', context=context)
|
2009-12-10 07:32:13 +00:00
|
|
|
next = self.cancel(cr, uid, ids, context=None)
|
|
|
|
if next: return next
|
2009-12-10 08:06:50 +00:00
|
|
|
return self.next(cr, uid, ids, context=context)
|
2010-04-18 20:07:32 +00:00
|
|
|
|
2009-12-03 15:11:22 +00:00
|
|
|
res_config_configurable()
|
|
|
|
|
2010-01-06 07:53:30 +00:00
|
|
|
class res_config_installer(osv.osv_memory):
|
2010-01-26 12:19:01 +00:00
|
|
|
""" New-style configuration base specialized for addons selection
|
2010-01-06 07:53:30 +00:00
|
|
|
and installation.
|
2010-01-26 12:19:01 +00:00
|
|
|
|
|
|
|
Basic usage
|
|
|
|
-----------
|
|
|
|
|
|
|
|
Subclasses can simply define a number of _columns as
|
|
|
|
fields.boolean objects. The keys (column names) should be the
|
|
|
|
names of the addons to install (when selected). Upon action
|
|
|
|
execution, selected boolean fields (and those only) will be
|
|
|
|
interpreted as addons to install, and batch-installed.
|
|
|
|
|
|
|
|
Additional addons
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
It is also possible to require the installation of an additional
|
|
|
|
addon set when a specific preset of addons has been marked for
|
|
|
|
installation (in the basic usage only, additionals can't depend on
|
|
|
|
one another).
|
|
|
|
|
|
|
|
These additionals are defined through the ``_install_if``
|
|
|
|
property. This property is a mapping of a collection of addons (by
|
|
|
|
name) to a collection of addons (by name) [#]_, and if all the *key*
|
|
|
|
addons are selected for installation, then the *value* ones will
|
|
|
|
be selected as well. For example::
|
|
|
|
|
|
|
|
_install_if = {
|
|
|
|
('sale','crm'): ['sale_crm'],
|
|
|
|
}
|
|
|
|
|
|
|
|
This will install the ``sale_crm`` addon if and only if both the
|
|
|
|
``sale`` and ``crm`` addons are selected for installation.
|
|
|
|
|
|
|
|
You can define as many additionals as you wish, and additionals
|
|
|
|
can overlap in key and value. For instance::
|
|
|
|
|
|
|
|
_install_if = {
|
|
|
|
('sale','crm'): ['sale_crm'],
|
|
|
|
('sale','project'): ['project_mrp'],
|
|
|
|
}
|
|
|
|
|
|
|
|
will install both ``sale_crm`` and ``project_mrp`` if all of
|
|
|
|
``sale``, ``crm`` and ``project`` are selected for installation.
|
|
|
|
|
|
|
|
Hook methods
|
|
|
|
------------
|
|
|
|
|
|
|
|
Subclasses might also need to express dependencies more complex
|
|
|
|
than that provided by additionals. In this case, it's possible to
|
|
|
|
define methods of the form ``_if_%(name)s`` where ``name`` is the
|
|
|
|
name of a boolean field. If the field is selected, then the
|
|
|
|
corresponding module will be marked for installation *and* the
|
|
|
|
hook method will be executed.
|
|
|
|
|
|
|
|
Hook methods take the usual set of parameters (cr, uid, ids,
|
|
|
|
context) and can return a collection of additional addons to
|
|
|
|
install (if they return anything, otherwise they should not return
|
|
|
|
anything, though returning any "falsy" value such as None or an
|
|
|
|
empty collection will have the same effect).
|
|
|
|
|
|
|
|
Complete control
|
|
|
|
----------------
|
|
|
|
|
|
|
|
The last hook is to simply overload the ``modules_to_install``
|
|
|
|
method, which implements all the mechanisms above. This method
|
|
|
|
takes the usual set of parameters (cr, uid, ids, context) and
|
|
|
|
returns a ``set`` of addons to install (addons selected by the
|
|
|
|
above methods minus addons from the *basic* set which are already
|
|
|
|
installed) [#]_ so an overloader can simply manipulate the ``set``
|
|
|
|
returned by ``res_config_installer.modules_to_install`` to add or
|
|
|
|
remove addons.
|
|
|
|
|
|
|
|
Skipping the installer
|
|
|
|
----------------------
|
|
|
|
|
|
|
|
Unless it is removed from the view, installers have a *skip*
|
|
|
|
button which invokes ``action_skip`` (and the ``cancel`` hook from
|
|
|
|
``res.config``). Hooks and additionals *are not run* when skipping
|
|
|
|
installation, even for already installed addons.
|
|
|
|
|
|
|
|
Again, setup your hooks accordinly.
|
|
|
|
|
|
|
|
.. [#] note that since a mapping key needs to be hashable, it's
|
|
|
|
possible to use a tuple or a frozenset, but not a list or a
|
|
|
|
regular set
|
|
|
|
|
|
|
|
.. [#] because the already-installed modules are only pruned at
|
|
|
|
the very end of ``modules_to_install``, additionals and
|
|
|
|
hooks depending on them *are guaranteed to execute*. Setup
|
|
|
|
your hooks accordingly.
|
|
|
|
"""
|
2010-01-06 07:53:30 +00:00
|
|
|
_name = 'res.config.installer'
|
|
|
|
_inherit = 'res.config'
|
2010-11-08 10:08:57 +00:00
|
|
|
__logger = logging.getLogger(_name)
|
2010-01-06 07:53:30 +00:00
|
|
|
|
2010-01-06 11:54:54 +00:00
|
|
|
_install_if = {}
|
|
|
|
|
2010-01-23 14:37:05 +00:00
|
|
|
def _already_installed(self, cr, uid, context=None):
|
|
|
|
""" For each module (boolean fields in a res.config.installer),
|
2010-09-07 15:06:06 +00:00
|
|
|
check if it's already installed (either 'to install', 'to upgrade' or 'installed')
|
2010-01-23 14:37:05 +00:00
|
|
|
and if it is, check it by default
|
|
|
|
"""
|
|
|
|
modules = self.pool.get('ir.module.module')
|
|
|
|
|
|
|
|
selectable = [field for field in self._columns
|
|
|
|
if type(self._columns[field]) is fields.boolean]
|
|
|
|
return modules.browse(
|
|
|
|
cr, uid,
|
|
|
|
modules.search(cr, uid,
|
|
|
|
[('name','in',selectable),
|
2010-09-07 15:06:06 +00:00
|
|
|
('state','in',['to install', 'installed', 'to upgrade'])],
|
2010-01-23 14:37:05 +00:00
|
|
|
context=context),
|
|
|
|
context=context)
|
|
|
|
|
|
|
|
|
2010-01-26 12:19:01 +00:00
|
|
|
def modules_to_install(self, cr, uid, ids, context=None):
|
2010-01-23 14:37:05 +00:00
|
|
|
""" selects all modules to install:
|
|
|
|
|
|
|
|
* checked boolean fields
|
|
|
|
* return values of hook methods. Hook methods are of the form
|
|
|
|
``_if_%(addon_name)s``, and are called if the corresponding
|
|
|
|
addon is marked for installation. They take the arguments
|
|
|
|
cr, uid, ids and context, and return an iterable of addon
|
|
|
|
names
|
|
|
|
* additionals, additionals are setup through the ``_install_if``
|
|
|
|
class variable. ``_install_if`` is a dict of {iterable:iterable}
|
|
|
|
where key and value are iterables of addon names.
|
|
|
|
|
|
|
|
If all the addons in the key are selected for installation
|
|
|
|
(warning: addons added through hooks don't count), then the
|
|
|
|
addons in the value are added to the set of modules to install
|
|
|
|
* not already installed
|
|
|
|
"""
|
2010-01-06 11:54:54 +00:00
|
|
|
base = set(module_name
|
|
|
|
for installer in self.read(cr, uid, ids, context=context)
|
|
|
|
for module_name, to_install in installer.iteritems()
|
|
|
|
if module_name != 'id'
|
|
|
|
if type(self._columns[module_name]) is fields.boolean
|
|
|
|
if to_install)
|
2010-01-23 14:37:05 +00:00
|
|
|
|
2010-01-06 11:54:54 +00:00
|
|
|
hooks_results = set()
|
|
|
|
for module in base:
|
|
|
|
hook = getattr(self, '_if_%s'%(module), None)
|
|
|
|
if hook:
|
|
|
|
hooks_results.update(hook(cr, uid, ids, context=None) or set())
|
|
|
|
|
|
|
|
additionals = set(
|
|
|
|
module for requirements, consequences \
|
|
|
|
in self._install_if.iteritems()
|
|
|
|
if base.issuperset(requirements)
|
|
|
|
for module in consequences)
|
|
|
|
|
2010-01-23 14:37:05 +00:00
|
|
|
return (base | hooks_results | additionals) - set(
|
|
|
|
map(attrgetter('name'), self._already_installed(cr, uid, context)))
|
2010-01-06 11:54:54 +00:00
|
|
|
|
2010-01-23 12:43:35 +00:00
|
|
|
def default_get(self, cr, uid, fields_list, context=None):
|
2010-01-23 14:37:05 +00:00
|
|
|
''' If an addon is already installed, check it by default
|
|
|
|
'''
|
2010-01-23 12:43:35 +00:00
|
|
|
defaults = super(res_config_installer, self).default_get(
|
|
|
|
cr, uid, fields_list, context=context)
|
|
|
|
|
|
|
|
return dict(defaults,
|
|
|
|
**dict.fromkeys(
|
2010-01-23 14:37:05 +00:00
|
|
|
map(attrgetter('name'),
|
|
|
|
self._already_installed(cr, uid, context=context)),
|
2010-01-23 12:43:35 +00:00
|
|
|
True))
|
|
|
|
|
2010-07-12 14:15:13 +00:00
|
|
|
def fields_get(self, cr, uid, fields=None, context=None, write_access=True):
|
2010-01-23 14:37:05 +00:00
|
|
|
""" If an addon is already installed, set it to readonly as
|
|
|
|
res.config.installer doesn't handle uninstallations of already
|
|
|
|
installed addons
|
|
|
|
"""
|
|
|
|
fields = super(res_config_installer, self).fields_get(
|
2010-07-12 14:15:13 +00:00
|
|
|
cr, uid, fields, context, write_access)
|
2010-01-23 14:37:05 +00:00
|
|
|
|
|
|
|
for module in self._already_installed(cr, uid, context=context):
|
2010-06-15 07:59:00 +00:00
|
|
|
if module.name not in fields:
|
|
|
|
continue
|
2010-01-23 14:37:05 +00:00
|
|
|
fields[module.name].update(
|
|
|
|
readonly=True,
|
|
|
|
help=fields[module.name].get('help', '') +
|
2010-01-23 14:50:17 +00:00
|
|
|
_('\n\nThis addon is already installed on your system'))
|
2010-01-23 14:37:05 +00:00
|
|
|
|
|
|
|
return fields
|
|
|
|
|
2010-01-06 07:53:30 +00:00
|
|
|
def execute(self, cr, uid, ids, context=None):
|
|
|
|
modules = self.pool.get('ir.module.module')
|
2010-01-26 12:19:01 +00:00
|
|
|
to_install = list(self.modules_to_install(
|
2010-01-10 18:31:46 +00:00
|
|
|
cr, uid, ids, context=context))
|
2010-11-08 10:08:57 +00:00
|
|
|
self.__logger.info('Selecting addons %s to install', to_install)
|
2010-01-10 18:31:46 +00:00
|
|
|
modules.state_update(
|
|
|
|
cr, uid,
|
|
|
|
modules.search(cr, uid, [('name','in',to_install)]),
|
|
|
|
'to install', ['uninstalled'], context=context)
|
2010-11-19 11:55:11 +00:00
|
|
|
cr.commit() #TOFIX: after remove this statement, installation wizard is fail
|
2010-01-06 07:53:30 +00:00
|
|
|
pooler.restart_pool(cr.dbname, update_module=True)
|
|
|
|
res_config_installer()
|
|
|
|
|
2009-12-17 14:19:35 +00:00
|
|
|
DEPRECATION_MESSAGE = 'You are using an addon using old-style configuration '\
|
|
|
|
'wizards (ir.actions.configuration.wizard). Old-style configuration '\
|
|
|
|
'wizards have been deprecated.\n'\
|
|
|
|
'The addon should be migrated to res.config objects.'
|
2009-12-16 15:59:41 +00:00
|
|
|
class ir_actions_configuration_wizard(osv.osv_memory):
|
|
|
|
''' Compatibility configuration wizard
|
|
|
|
|
|
|
|
The old configuration wizard has been replaced by res.config, but in order
|
|
|
|
not to break existing but not-yet-migrated addons, the old wizard was
|
|
|
|
reintegrated and gutted.
|
|
|
|
'''
|
|
|
|
_name='ir.actions.configuration.wizard'
|
|
|
|
_inherit = 'res.config'
|
2010-11-08 10:08:57 +00:00
|
|
|
__logger = logging.getLogger(_name)
|
2009-12-16 15:59:41 +00:00
|
|
|
|
|
|
|
def _next_action_note(self, cr, uid, ids, context=None):
|
|
|
|
next = self._next_action(cr, uid)
|
|
|
|
if next:
|
2009-12-17 14:19:14 +00:00
|
|
|
# if the next one is also an old-style extension, you never know...
|
|
|
|
if next.note:
|
|
|
|
return next.note
|
|
|
|
return "Click 'Continue' to configure the next addon..."
|
2009-12-16 15:59:41 +00:00
|
|
|
return "Your database is now fully configured.\n\n"\
|
|
|
|
"Click 'Continue' and enjoy your OpenERP experience..."
|
|
|
|
|
|
|
|
_columns = {
|
|
|
|
'note': fields.text('Next Wizard', readonly=True),
|
|
|
|
}
|
|
|
|
_defaults = {
|
|
|
|
'note': _next_action_note,
|
|
|
|
}
|
|
|
|
|
|
|
|
def execute(self, cr, uid, ids, context=None):
|
2010-11-08 10:08:57 +00:00
|
|
|
self.__logger.warn(DEPRECATION_MESSAGE)
|
2009-12-17 14:19:35 +00:00
|
|
|
|
2009-12-16 15:59:41 +00:00
|
|
|
ir_actions_configuration_wizard()
|
|
|
|
|
2009-12-03 15:11:22 +00:00
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|