1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 from operator import attrgetter
24 from osv import osv, fields
25 from tools.translate import _
29 class res_config_configurable(osv.osv_memory):
30 ''' Base classes for new-style configuration items
32 Configuration items should inherit from this class, implement
33 the execute method (and optionally the cancel one) and have
34 their view inherit from the related res_config_view_base view.
37 logger = netsvc.Logger()
39 def _progress(self, cr, uid, context=None):
40 total = self.pool.get('ir.actions.todo')\
41 .search_count(cr, uid, [], context)
42 open = self.pool.get('ir.actions.todo')\
43 .search_count(cr, uid, [('active','=',True),
44 ('state','<>','open')],
47 return round(open*100./total)
51 progress=fields.float('Configuration Progress', readonly=True),
57 def _next_action(self, cr, uid):
58 todos = self.pool.get('ir.actions.todo')
59 self.logger.notifyChannel('actions', netsvc.LOG_INFO,
60 'getting next %s' % todos)
61 active_todos = todos.search(cr, uid, [('state','=','open'),
63 limit=1, context=None)
65 return todos.browse(cr, uid, active_todos[0], context=None)
68 def _next(self, cr, uid):
69 self.logger.notifyChannel('actions', netsvc.LOG_INFO,
70 'getting next operation')
71 next = self._next_action(cr, uid)
72 self.logger.notifyChannel('actions', netsvc.LOG_INFO,
73 'next action is %s' % next)
75 self.pool.get('ir.actions.todo').write(cr, uid, next.id, {
78 action = next.action_id
80 'view_mode': action.view_mode,
81 'view_type': action.view_type,
82 'view_id': action.view_id and [action.view_id.id] or False,
83 'res_model': action.res_model,
85 'target': action.target,
87 self.logger.notifyChannel(
88 'actions', netsvc.LOG_INFO,
89 'all configuration actions have been executed')
91 current_user_menu = self.pool.get('res.users')\
92 .browse(cr, uid, uid).menu_id
93 # return the action associated with the menu
94 return self.pool.get(current_user_menu.type)\
95 .read(cr, uid, current_user_menu.id)
96 def next(self, cr, uid, ids, context=None):
97 return self._next(cr, uid)
99 def execute(self, cr, uid, ids, context=None):
100 raise NotImplementedError(
101 'Configuration items need to implement execute')
102 def cancel(self, cr, uid, ids, context=None):
105 def action_next(self, cr, uid, ids, context=None):
106 next = self.execute(cr, uid, ids, context=None)
108 return self.next(cr, uid, ids, context=context)
110 def action_skip(self, cr, uid, ids, context=None):
111 next = self.cancel(cr, uid, ids, context=None)
113 return self.next(cr, uid, ids, context=context)
114 res_config_configurable()
116 class res_config_installer(osv.osv_memory):
117 ''' New-style configuration base specialized for modules selection
120 _name = 'res.config.installer'
121 _inherit = 'res.config'
125 def _already_installed(self, cr, uid, context=None):
126 """ For each module (boolean fields in a res.config.installer),
127 check if it's already installed (neither uninstallable nor uninstalled)
128 and if it is, check it by default
130 modules = self.pool.get('ir.module.module')
132 selectable = [field for field in self._columns
133 if type(self._columns[field]) is fields.boolean]
134 return modules.browse(
136 modules.search(cr, uid,
137 [('name','in',selectable),
138 ('state','not in',['uninstallable', 'uninstalled'])],
143 def _modules_to_install(self, cr, uid, ids, context=None):
144 """ selects all modules to install:
146 * checked boolean fields
147 * return values of hook methods. Hook methods are of the form
148 ``_if_%(addon_name)s``, and are called if the corresponding
149 addon is marked for installation. They take the arguments
150 cr, uid, ids and context, and return an iterable of addon
152 * additionals, additionals are setup through the ``_install_if``
153 class variable. ``_install_if`` is a dict of {iterable:iterable}
154 where key and value are iterables of addon names.
156 If all the addons in the key are selected for installation
157 (warning: addons added through hooks don't count), then the
158 addons in the value are added to the set of modules to install
159 * not already installed
161 base = set(module_name
162 for installer in self.read(cr, uid, ids, context=context)
163 for module_name, to_install in installer.iteritems()
164 if module_name != 'id'
165 if type(self._columns[module_name]) is fields.boolean
168 hooks_results = set()
170 hook = getattr(self, '_if_%s'%(module), None)
172 hooks_results.update(hook(cr, uid, ids, context=None) or set())
175 module for requirements, consequences \
176 in self._install_if.iteritems()
177 if base.issuperset(requirements)
178 for module in consequences)
180 return (base | hooks_results | additionals) - set(
181 map(attrgetter('name'), self._already_installed(cr, uid, context)))
183 def default_get(self, cr, uid, fields_list, context=None):
184 ''' If an addon is already installed, check it by default
186 defaults = super(res_config_installer, self).default_get(
187 cr, uid, fields_list, context=context)
189 return dict(defaults,
191 map(attrgetter('name'),
192 self._already_installed(cr, uid, context=context)),
195 def fields_get(self, cr, uid, fields=None, context=None, read_access=True):
196 """ If an addon is already installed, set it to readonly as
197 res.config.installer doesn't handle uninstallations of already
200 fields = super(res_config_installer, self).fields_get(
201 cr, uid, fields, context, read_access)
203 for module in self._already_installed(cr, uid, context=context):
204 fields[module.name].update(
206 help=fields[module.name].get('help', '') +
207 '\n\nThis addon is already installed on your system')
211 def execute(self, cr, uid, ids, context=None):
212 modules = self.pool.get('ir.module.module')
213 to_install = list(self._modules_to_install(
214 cr, uid, ids, context=context))
215 self.logger.notifyChannel(
216 'installer', netsvc.LOG_INFO,
217 'Selecting addons %s to install'%to_install)
218 modules.state_update(
220 modules.search(cr, uid, [('name','in',to_install)]),
221 'to install', ['uninstalled'], context=context)
224 pooler.restart_pool(cr.dbname, update_module=True)
225 res_config_installer()
227 DEPRECATION_MESSAGE = 'You are using an addon using old-style configuration '\
228 'wizards (ir.actions.configuration.wizard). Old-style configuration '\
229 'wizards have been deprecated.\n'\
230 'The addon should be migrated to res.config objects.'
231 class ir_actions_configuration_wizard(osv.osv_memory):
232 ''' Compatibility configuration wizard
234 The old configuration wizard has been replaced by res.config, but in order
235 not to break existing but not-yet-migrated addons, the old wizard was
236 reintegrated and gutted.
238 _name='ir.actions.configuration.wizard'
239 _inherit = 'res.config'
241 def _next_action_note(self, cr, uid, ids, context=None):
242 next = self._next_action(cr, uid)
244 # if the next one is also an old-style extension, you never know...
247 return "Click 'Continue' to configure the next addon..."
248 return "Your database is now fully configured.\n\n"\
249 "Click 'Continue' and enjoy your OpenERP experience..."
252 'note': fields.text('Next Wizard', readonly=True),
255 'note': _next_action_note,
258 def execute(self, cr, uid, ids, context=None):
259 self.logger.notifyChannel(
260 'configuration', netsvc.LOG_WARNING, DEPRECATION_MESSAGE)
262 ir_actions_configuration_wizard()
264 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: