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
2012-12-17 14:30:29 +00:00
from operator import attrgetter
2013-01-21 15:07:48 +00:00
import re
2010-01-23 12:43:35 +00:00
2013-01-18 11:03:00 +00:00
from openerp import pooler , SUPERUSER_ID
2012-12-10 15:27:23 +00:00
from openerp . osv import osv , fields
from openerp . tools import ustr
from openerp . tools . translate import _
2013-01-21 15:07:48 +00:00
from openerp import exceptions
2009-12-03 15:11:22 +00:00
2012-01-24 16:28:04 +00:00
_logger = logging . getLogger ( __name__ )
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 '
2009-12-03 15:11:22 +00:00
2010-08-30 13:04:48 +00:00
def _next_action ( self , cr , uid , context = None ) :
2011-07-18 12:39:07 +00:00
Todos = self . pool [ ' ir.actions.todo ' ]
2012-01-24 16:28:04 +00:00
_logger . info ( ' getting next %s ' , Todos )
2009-12-03 15:11:22 +00:00
2011-07-18 12:39:07 +00:00
active_todos = Todos . browse ( cr , uid ,
2011-07-29 14:26:22 +00:00
Todos . search ( cr , uid , [ ' & ' , ( ' type ' , ' = ' , ' automatic ' ) , ( ' state ' , ' = ' , ' open ' ) ] ) ,
2011-07-18 12:39:07 +00:00
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
2010-01-26 16:42:37 +00:00
2010-08-30 13:04:48 +00:00
def _next ( self , cr , uid , context = None ) :
2012-01-24 16:28:04 +00:00
_logger . info ( ' getting next operation ' )
2011-07-18 12:39:07 +00:00
next = self . _next_action ( cr , uid , context = context )
2012-01-24 16:28:04 +00:00
_logger . info ( ' next action is %s ' , next )
2009-12-03 15:11:22 +00:00
if next :
2011-06-30 11:47:26 +00:00
res = next . action_launch ( context = context )
2011-07-18 10:18:12 +00:00
res [ ' nodestroy ' ] = False
2011-06-30 11:47:26 +00:00
return res
2012-07-18 13:50:10 +00:00
# reload the client; open the first available root menu
menu_obj = self . pool . get ( ' ir.ui.menu ' )
menu_ids = menu_obj . search ( cr , uid , [ ( ' parent_id ' , ' = ' , False ) ] , context = context )
return {
' type ' : ' ir.actions.client ' ,
' tag ' : ' reload ' ,
' params ' : { ' menu_id ' : menu_ids and menu_ids [ 0 ] or False } ,
}
2010-11-19 11:55:11 +00:00
2010-04-18 20:07:32 +00:00
def start ( self , cr , uid , ids , context = None ) :
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 ` ` .
"""
2011-07-18 12:39:07 +00:00
next = self . execute ( cr , uid , ids , context = context )
2009-12-10 07:32:13 +00:00
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 ` ` .
"""
2011-07-18 12:39:07 +00:00
next = self . cancel ( cr , uid , ids , context = context )
2010-01-26 16:42:37 +00:00
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 ` ` .
"""
2011-07-18 12:39:07 +00:00
next = self . cancel ( cr , uid , ids , context = context )
2009-12-10 07:32:13 +00:00
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 .
2011-01-06 06:17:32 +00:00
Again , setup your hooks accordingly .
2010-01-26 12:19:01 +00:00
. . [ #] 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-01-06 11:54:54 +00:00
_install_if = { }
2011-07-19 06:56:58 +00:00
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 ) )
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),
2011-07-19 06:56:58 +00:00
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 ]
2010-01-23 14:37:05 +00:00
"""
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 :
2012-12-14 12:38:03 +00:00
hook = getattr ( self , ' _if_ %s ' % module , None )
2010-01-06 11:54:54 +00:00
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 )
2011-07-19 06:56:58 +00:00
return ( base | hooks_results | additionals ) . difference (
self . already_installed ( cr , uid , context ) )
2010-01-06 11:54:54 +00:00
2011-03-16 12:04:44 +00:00
def default_get ( self , cr , uid , fields_list , context = None ) :
''' If an addon is already installed, check it by default
'''
defaults = super ( res_config_installer , self ) . default_get (
cr , uid , fields_list , context = context )
return dict ( defaults ,
* * dict . fromkeys (
2011-07-19 06:56:58 +00:00
self . already_installed ( cr , uid , context = context ) ,
2011-03-16 12:04:44 +00:00
True ) )
def fields_get ( self , cr , uid , fields = None , context = None , write_access = True ) :
""" 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 (
cr , uid , fields , context , write_access )
2011-07-19 06:56:58 +00:00
for name in self . already_installed ( cr , uid , context = context ) :
if name not in fields :
2011-03-16 12:04:44 +00:00
continue
2011-07-19 06:56:58 +00:00
fields [ name ] . update (
2011-03-16 12:04:44 +00:00
readonly = True ,
2011-07-19 06:56:58 +00:00
help = ustr ( fields [ name ] . get ( ' help ' , ' ' ) ) +
2011-03-16 12:04:44 +00:00
_ ( ' \n \n This addon is already installed on your system ' ) )
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 ) )
2012-01-24 16:28:04 +00:00
_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
2011-01-20 16:03:47 +00:00
new_db , self . pool = pooler . restart_pool ( cr . dbname , update_module = True )
2012-10-28 12:32:16 +00:00
2010-01-06 07:53:30 +00:00
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 '
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
2010-12-16 15:04:30 +00:00
return _ ( " Click ' Continue ' to configure the next addon... " )
return _ ( " Your database is now fully configured. \n \n " \
" Click ' Continue ' and enjoy your OpenERP experience... " )
2009-12-16 15:59:41 +00:00
_columns = {
' note ' : fields . text ( ' Next Wizard ' , readonly = True ) ,
}
_defaults = {
' note ' : _next_action_note ,
}
def execute ( self , cr , uid , ids , context = None ) :
2012-02-02 09:26:34 +00:00
_logger . warning ( DEPRECATION_MESSAGE )
2009-12-17 14:19:35 +00:00
2009-12-16 15:59:41 +00:00
ir_actions_configuration_wizard ( )
2012-03-02 13:41:56 +00:00
class res_config_settings ( osv . osv_memory ) :
""" Base configuration wizard for application settings. It provides support for setting
default values , assigning groups to employee users , and installing modules .
To make such a ' settings ' wizard , define a model like : :
class my_config_wizard ( osv . osv_memory ) :
2012-03-06 10:46:46 +00:00
_name = ' my.settings '
2012-03-02 13:41:56 +00:00
_inherit = ' res.config.settings '
_columns = {
2012-03-06 10:46:46 +00:00
' default_foo ' : fields . type ( . . . , default_model = ' my.model ' ) ,
' group_bar ' : fields . boolean ( . . . , group = ' base.group_user ' , implied_group = ' my.group ' ) ,
2012-03-02 13:41:56 +00:00
' module_baz ' : fields . boolean ( . . . ) ,
' other_field ' : fields . type ( . . . ) ,
}
2012-04-04 13:34:17 +00:00
The method ` ` execute ` ` provides some support based on a naming convention :
2012-03-02 13:41:56 +00:00
* For a field like ' default_XXX ' , ` ` execute ` ` sets the ( global ) default value of
the field ' XXX ' in the model named by ` ` default_model ` ` to the field ' s value.
2012-03-05 10:16:35 +00:00
* For a boolean field like ' group_XXX ' , ` ` execute ` ` adds / removes ' implied_group '
to / from the implied groups of ' group ' , depending on the field ' s value.
2012-03-06 10:46:46 +00:00
By default ' group ' is the group Employee . Groups are given by their xml id .
2012-03-02 13:41:56 +00:00
* For a boolean field like ' module_XXX ' , ` ` execute ` ` triggers the immediate
installation of the module named ' XXX ' if the field has value ` ` True ` ` .
2012-03-06 10:46:46 +00:00
* For the other fields , the method ` ` execute ` ` invokes all methods with a name
that starts with ' set_ ' ; such methods can be defined to implement the effect
of those fields .
The method ` ` default_get ` ` retrieves values that reflect the current status of the
fields like ' default_XXX ' , ' group_XXX ' and ' module_XXX ' . It also invokes all methods
with a name that starts with ' get_default_ ' ; such methods can be defined to provide
current values for other fields .
2012-03-02 13:41:56 +00:00
"""
_name = ' res.config.settings '
2012-03-27 11:38:20 +00:00
def copy ( self , cr , uid , id , values , context = None ) :
raise osv . except_osv ( _ ( " Cannot duplicate configuration! " ) , " " )
2012-03-02 13:41:56 +00:00
def _get_classified_fields ( self , cr , uid , context = None ) :
""" return a dictionary with the fields classified by category::
{ ' default ' : [ ( ' default_foo ' , ' model ' , ' foo ' ) , . . . ] ,
2012-03-05 10:16:35 +00:00
' group ' : [ ( ' group_bar ' , browse_group , browse_implied_group ) , . . . ] ,
2012-03-02 13:41:56 +00:00
' module ' : [ ( ' module_baz ' , browse_module ) , . . . ] ,
' other ' : [ ' other_field ' , . . . ] ,
}
"""
ir_model_data = self . pool . get ( ' ir.model.data ' )
ir_module = self . pool . get ( ' ir.module.module ' )
2012-03-05 10:16:35 +00:00
def ref ( xml_id ) :
mod , xml = xml_id . split ( ' . ' , 1 )
return ir_model_data . get_object ( cr , uid , mod , xml , context )
2012-03-02 13:41:56 +00:00
defaults , groups , modules , others = [ ] , [ ] , [ ] , [ ]
for name , field in self . _columns . items ( ) :
if name . startswith ( ' default_ ' ) and hasattr ( field , ' default_model ' ) :
defaults . append ( ( name , field . default_model , name [ 8 : ] ) )
2012-03-05 10:16:35 +00:00
elif name . startswith ( ' group_ ' ) and isinstance ( field , fields . boolean ) and hasattr ( field , ' implied_group ' ) :
field_group = getattr ( field , ' group ' , ' base.group_user ' )
groups . append ( ( name , ref ( field_group ) , ref ( field . implied_group ) ) )
2012-03-02 13:41:56 +00:00
elif name . startswith ( ' module_ ' ) and isinstance ( field , fields . boolean ) :
mod_ids = ir_module . search ( cr , uid , [ ( ' name ' , ' = ' , name [ 7 : ] ) ] )
2012-09-11 11:50:03 +00:00
record = ir_module . browse ( cr , uid , mod_ids [ 0 ] , context ) if mod_ids else None
modules . append ( ( name , record ) )
2012-03-02 13:41:56 +00:00
else :
others . append ( name )
return { ' default ' : defaults , ' group ' : groups , ' module ' : modules , ' other ' : others }
def default_get ( self , cr , uid , fields , context = None ) :
ir_values = self . pool . get ( ' ir.values ' )
classified = self . _get_classified_fields ( cr , uid , context )
res = super ( res_config_settings , self ) . default_get ( cr , uid , fields , context )
# defaults: take the corresponding default value they set
for name , model , field in classified [ ' default ' ] :
value = ir_values . get_default ( cr , uid , model , field )
if value is not None :
res [ name ] = value
# groups: which groups are implied by the group Employee
2012-03-05 10:16:35 +00:00
for name , group , implied_group in classified [ ' group ' ] :
res [ name ] = implied_group in group . implied_ids
2012-03-02 13:41:56 +00:00
# modules: which modules are installed/to install
for name , module in classified [ ' module ' ] :
2012-09-11 11:50:03 +00:00
res [ name ] = module and module . state in ( ' installed ' , ' to install ' , ' to upgrade ' )
2012-03-02 13:41:56 +00:00
2012-03-05 10:16:35 +00:00
# other fields: call all methods that start with 'get_default_'
for method in dir ( self ) :
2012-03-06 10:46:46 +00:00
if method . startswith ( ' get_default_ ' ) :
2012-03-05 10:16:35 +00:00
res . update ( getattr ( self , method ) ( cr , uid , fields , context ) )
2012-03-02 13:41:56 +00:00
return res
def execute ( self , cr , uid , ids , context = None ) :
ir_values = self . pool . get ( ' ir.values ' )
ir_module = self . pool . get ( ' ir.module.module ' )
classified = self . _get_classified_fields ( cr , uid , context )
config = self . browse ( cr , uid , ids [ 0 ] , context )
# default values fields
for name , model , field in classified [ ' default ' ] :
ir_values . set_default ( cr , uid , model , field , config [ name ] )
2012-03-05 10:16:35 +00:00
# group fields: modify group / implied groups
for name , group , implied_group in classified [ ' group ' ] :
if config [ name ] :
group . write ( { ' implied_ids ' : [ ( 4 , implied_group . id ) ] } )
else :
group . write ( { ' implied_ids ' : [ ( 3 , implied_group . id ) ] } )
implied_group . write ( { ' users ' : [ ( 3 , u . id ) for u in group . users ] } )
# other fields: execute all methods that start with 'set_'
for method in dir ( self ) :
if method . startswith ( ' set_ ' ) :
getattr ( self , method ) ( cr , uid , ids , context )
2012-03-02 13:41:56 +00:00
2012-06-22 09:51:26 +00:00
# module fields: install/uninstall the selected modules
2012-12-21 20:45:39 +00:00
to_install_missing_names = [ ]
2012-05-30 10:52:43 +00:00
to_uninstall_ids = [ ]
2012-12-21 20:45:39 +00:00
to_install_ids = [ ]
2012-09-21 13:29:11 +00:00
lm = len ( ' module_ ' )
2012-03-02 13:41:56 +00:00
for name , module in classified [ ' module ' ] :
2012-09-25 15:19:44 +00:00
if config [ name ] :
2012-12-21 20:45:39 +00:00
if not module :
# missing module, will be provided by apps.openerp.com
to_install_missing_names . append ( name [ lm : ] )
elif module . state == ' uninstalled ' :
# local module, to be installed
to_install_ids . append ( module . id )
2012-05-30 10:12:04 +00:00
else :
2012-09-25 15:19:44 +00:00
if module and module . state in ( ' installed ' , ' to upgrade ' ) :
to_uninstall_ids . append ( module . id )
2012-09-11 11:50:03 +00:00
if to_uninstall_ids :
ir_module . button_immediate_uninstall ( cr , uid , to_uninstall_ids , context = context )
2012-12-21 20:45:39 +00:00
if to_install_ids :
ir_module . button_immediate_install ( cr , uid , to_install_ids , context = context )
2012-06-22 09:51:26 +00:00
2012-12-21 20:45:39 +00:00
if to_install_missing_names :
2012-09-21 13:29:11 +00:00
return {
' type ' : ' ir.actions.client ' ,
' tag ' : ' apps ' ,
2012-12-21 20:45:39 +00:00
' params ' : { ' modules ' : to_install_missing_names } ,
2012-09-21 13:29:11 +00:00
}
2012-10-28 12:32:16 +00:00
config = self . pool . get ( ' res.config ' ) . next ( cr , uid , [ ] , context = context ) or { }
if config . get ( ' type ' ) not in ( ' ir.actions.act_window_close ' , ) :
return config
2012-05-03 08:23:40 +00:00
# force client-side reload (update user menu and current view)
2012-04-04 13:34:17 +00:00
return {
2012-05-03 08:23:40 +00:00
' type ' : ' ir.actions.client ' ,
2012-05-15 12:10:16 +00:00
' tag ' : ' reload ' ,
2012-04-04 13:34:17 +00:00
}
2012-03-02 13:41:56 +00:00
2012-06-26 07:47:46 +00:00
def cancel ( self , cr , uid , ids , context = None ) :
# ignore the current record, and send the action to reopen the view
act_window = self . pool . get ( ' ir.actions.act_window ' )
action_ids = act_window . search ( cr , uid , [ ( ' res_model ' , ' = ' , self . _name ) ] )
if action_ids :
return act_window . read ( cr , uid , action_ids [ 0 ] , [ ] , context = context )
return { }
2013-01-15 17:47:05 +00:00
2012-08-28 12:47:50 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
""" Override name_get method to return an appropriate configuration wizard
name , and not the generated name . """
2013-01-15 17:47:05 +00:00
2012-08-28 12:56:23 +00:00
if not ids :
2012-08-28 12:47:50 +00:00
return [ ]
# name_get may receive int id instead of an id list
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
2013-01-15 17:47:05 +00:00
2012-08-28 12:47:50 +00:00
act_window = self . pool . get ( ' ir.actions.act_window ' )
action_ids = act_window . search ( cr , uid , [ ( ' res_model ' , ' = ' , self . _name ) ] , context = context )
name = self . _name
if action_ids :
name = act_window . read ( cr , uid , action_ids [ 0 ] , [ ' name ' ] , context = context ) [ ' name ' ]
return [ ( record . id , name ) for record in self . browse ( cr , uid , ids , context = context ) ]
2012-06-26 07:47:46 +00:00
2013-01-21 16:59:16 +00:00
def get_option_path ( self , cr , uid , menu_xml_id = None , context = None ) :
2013-01-22 16:22:23 +00:00
"""
Fetch the path to a specified configuration view .
: param string menu_xml_id : the xml id of the menuitem where the view
is located , structured as follows : module_name . menuitem_xml_id
( e . g . : " base.menu_sale_config " )
: return string : full path to the menuitem
( e . g . : " Settings/Configuration/Sales " )
"""
2013-01-21 16:59:16 +00:00
module_name , menu_xml_id = menu_xml_id . split ( ' . ' )
dummy , menu_id = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , module_name , menu_xml_id )
ir_ui_menu = self . pool . get ( ' ir.ui.menu ' ) . browse ( cr , uid , menu_id , context = context )
2013-01-21 15:07:48 +00:00
2013-01-21 16:59:16 +00:00
return ir_ui_menu . complete_name
2013-01-15 17:47:05 +00:00
2013-01-21 16:59:16 +00:00
def get_option_name ( self , cr , uid , full_field_name = None , context = None ) :
2013-01-22 16:22:23 +00:00
"""
Fetch the human readable name of a specified configuration option .
: param string full_field_name : the full name of the field , structured
as follows : model_name . field_name
( e . g . : " sale.config.settings.fetchmail_lead " )
: return string : human readable name of the field
( e . g . : " Create leads from incoming mails " )
"""
2013-01-21 16:59:16 +00:00
model_name , field_name = full_field_name . rsplit ( ' . ' , 1 )
2013-01-17 18:33:42 +00:00
2013-01-23 15:49:43 +00:00
return self . pool . get ( model_name ) . fields_get ( cr , uid , allfields = [ field_name ] , context = context ) [ field_name ] [ ' string ' ]
2013-01-15 17:47:05 +00:00
2013-01-21 15:07:48 +00:00
def get_warning_config ( cr , msg , context = None ) :
2013-01-22 16:22:23 +00:00
"""
2013-01-24 15:41:19 +00:00
Helper : return a Warning exception with the given message where the
2013-01-22 16:22:23 +00:00
% ( field : ) s and / or % ( menu : ) s are replaced by the human readable field ' s name
and / or menuitem ' s full path.
Usage :
- - - - - -
Just include in your error message % ( field : model_name . field_name ) s to
obtain the human readable field ' s name, and/or
% ( menu : module_name . menuitem_xml_id ) s to obtain the menuitem ' s full path.
Example of use :
- - - - - - - - - - - - - - -
from openerp . addons . base . res . res_config import get_warning_config
raise get_warning_config ( cr , _ ( " Error: this action is prohibited. You should check the field % (field:sale.config.settings.fetchmail_lead)s in % (menu:base.menu_sale_config)s. " ) , context = context )
will return an exception containing the following message :
Error : this action is prohibited . You should check the field Create leads from incoming mails in Settings / Configuration / Sales .
"""
2013-01-21 15:07:48 +00:00
res_config_obj = pooler . get_pool ( cr . dbname ) . get ( ' res.config.settings ' )
2013-01-22 16:22:23 +00:00
regex_path = r ' % \ (((?:menu|field):[a-z_ \ .]*) \ )s '
2013-01-21 15:07:48 +00:00
2013-01-22 14:31:56 +00:00
# Process the message
# 1/ find the path and/or field references, put them in a list
references = re . findall ( regex_path , msg , flags = re . I )
2013-01-21 16:59:16 +00:00
2013-01-22 14:31:56 +00:00
# 2/ fetch the path and/or field replacement values
2013-01-21 16:59:16 +00:00
# (full path and human readable field's name)
2013-01-22 14:31:56 +00:00
values = { }
2013-01-21 16:59:16 +00:00
for item in references :
ref_type , ref = item . split ( ' : ' )
2013-01-22 16:22:23 +00:00
if ref_type == ' menu ' :
2013-01-22 14:31:56 +00:00
values [ item ] = res_config_obj . get_option_path ( cr , SUPERUSER_ID , ref , context )
2013-01-21 16:59:16 +00:00
elif ref_type == ' field ' :
2013-01-22 14:31:56 +00:00
values [ item ] = res_config_obj . get_option_name ( cr , SUPERUSER_ID , ref , context )
2013-01-21 16:59:16 +00:00
2013-01-21 18:16:50 +00:00
# 4/ substitute and return the result
2013-01-24 15:41:19 +00:00
return exceptions . Warning ( msg % values )
2013-01-15 17:47:05 +00:00
2009-12-03 15:11:22 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: