[MERGE] forward port of branch saas-2 up to revid 4984 chs@openerp.com-20131125151017-lmj53bxg1pfrr4a7
bzr revid: chs@openerp.com-20131125154140-cpbk4tcdml2a3b9n
This commit is contained in:
commit
ab386c0f5f
|
@ -25,25 +25,25 @@ create table ir_values
|
||||||
|
|
||||||
CREATE TABLE ir_model (
|
CREATE TABLE ir_model (
|
||||||
id serial,
|
id serial,
|
||||||
model varchar(64) DEFAULT ''::varchar NOT NULL,
|
model varchar DEFAULT ''::varchar NOT NULL,
|
||||||
name varchar(64),
|
name varchar,
|
||||||
state varchar(16),
|
state varchar,
|
||||||
info text,
|
info text,
|
||||||
primary key(id)
|
primary key(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE ir_model_fields (
|
CREATE TABLE ir_model_fields (
|
||||||
id serial,
|
id serial,
|
||||||
model varchar(64) DEFAULT ''::varchar NOT NULL,
|
model varchar DEFAULT ''::varchar NOT NULL,
|
||||||
model_id int references ir_model on delete cascade,
|
model_id int references ir_model on delete cascade,
|
||||||
name varchar(64) DEFAULT ''::varchar NOT NULL,
|
name varchar DEFAULT ''::varchar NOT NULL,
|
||||||
relation varchar(64),
|
relation varchar,
|
||||||
select_level varchar(4),
|
select_level varchar,
|
||||||
field_description varchar(256),
|
field_description varchar,
|
||||||
ttype varchar(64),
|
ttype varchar,
|
||||||
state varchar(64) default 'base',
|
state varchar default 'base',
|
||||||
relate boolean default False,
|
relate boolean default False,
|
||||||
relation_field varchar(128),
|
relation_field varchar,
|
||||||
translate boolean default False,
|
translate boolean default False,
|
||||||
primary key(id)
|
primary key(id)
|
||||||
);
|
);
|
||||||
|
@ -350,11 +350,11 @@ CREATE TABLE ir_model_data (
|
||||||
write_date timestamp without time zone,
|
write_date timestamp without time zone,
|
||||||
write_uid integer,
|
write_uid integer,
|
||||||
noupdate boolean,
|
noupdate boolean,
|
||||||
name character varying(128) NOT NULL,
|
name varchar NOT NULL,
|
||||||
date_init timestamp without time zone,
|
date_init timestamp without time zone,
|
||||||
date_update timestamp without time zone,
|
date_update timestamp without time zone,
|
||||||
module character varying(64) NOT NULL,
|
module varchar NOT NULL,
|
||||||
model character varying(64) NOT NULL,
|
model varchar NOT NULL,
|
||||||
res_id integer, primary key(id)
|
res_id integer, primary key(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -373,7 +373,7 @@ CREATE TABLE ir_model_constraint (
|
||||||
module integer NOT NULL references ir_module_module on delete restrict,
|
module integer NOT NULL references ir_module_module on delete restrict,
|
||||||
model integer NOT NULL references ir_model on delete restrict,
|
model integer NOT NULL references ir_model on delete restrict,
|
||||||
type character varying(1) NOT NULL,
|
type character varying(1) NOT NULL,
|
||||||
name character varying(128) NOT NULL
|
name varchar NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Records relation tables (i.e. implementing many2many) installed by a module
|
-- Records relation tables (i.e. implementing many2many) installed by a module
|
||||||
|
@ -388,7 +388,7 @@ CREATE TABLE ir_model_relation (
|
||||||
date_update timestamp without time zone,
|
date_update timestamp without time zone,
|
||||||
module integer NOT NULL references ir_module_module on delete restrict,
|
module integer NOT NULL references ir_module_module on delete restrict,
|
||||||
model integer NOT NULL references ir_model on delete restrict,
|
model integer NOT NULL references ir_model on delete restrict,
|
||||||
name character varying(128) NOT NULL
|
name varchar NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
# Copyright (C) 2004-2011 OpenERP S.A. <http://www.openerp.com>
|
# Copyright (C) 2004-2013 OpenERP S.A. <http://www.openerp.com>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -801,7 +801,7 @@ class ir_actions_server(osv.osv):
|
||||||
raise osv.except_osv(_('Error'), _("Please specify an action to launch!"))
|
raise osv.except_osv(_('Error'), _("Please specify an action to launch!"))
|
||||||
return self.pool[action.action_id.type].read(cr, uid, action.action_id.id, context=context)
|
return self.pool[action.action_id.type].read(cr, uid, action.action_id.id, context=context)
|
||||||
|
|
||||||
def run_action_code(self, cr, uid, action, eval_context=None, context=None):
|
def run_action_code_multi(self, cr, uid, action, eval_context=None, context=None):
|
||||||
eval(action.code.strip(), eval_context, mode="exec", nocopy=True) # nocopy allows to return 'action'
|
eval(action.code.strip(), eval_context, mode="exec", nocopy=True) # nocopy allows to return 'action'
|
||||||
if 'action' in eval_context:
|
if 'action' in eval_context:
|
||||||
return eval_context['action']
|
return eval_context['action']
|
||||||
|
@ -933,38 +933,50 @@ class ir_actions_server(osv.osv):
|
||||||
context = {}
|
context = {}
|
||||||
res = False
|
res = False
|
||||||
user = self.pool.get('res.users').browse(cr, uid, uid)
|
user = self.pool.get('res.users').browse(cr, uid, uid)
|
||||||
active_ids = context.get('active_ids', [context.get('active_id', None)])
|
active_ids = context.get('active_ids', [context.get('active_id')])
|
||||||
for action in self.browse(cr, uid, ids, context):
|
for action in self.browse(cr, uid, ids, context):
|
||||||
obj = None
|
|
||||||
obj_pool = self.pool[action.model_id.model]
|
obj_pool = self.pool[action.model_id.model]
|
||||||
for active_id in active_ids:
|
obj = None
|
||||||
if context.get('active_model') == action.model_id.model and active_id:
|
if context.get('active_model') == action.model_id.model and context.get('active_id'):
|
||||||
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
|
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
|
||||||
# run context dedicated to a particular active_id
|
|
||||||
run_context = dict(context, active_ids=[active_id], active_id=active_id)
|
|
||||||
# evaluation context for python strings to evaluate
|
|
||||||
eval_context = {
|
|
||||||
'self': obj_pool,
|
|
||||||
'object': obj,
|
|
||||||
'obj': obj,
|
|
||||||
'pool': self.pool,
|
|
||||||
'time': time,
|
|
||||||
'cr': cr,
|
|
||||||
'context': dict(run_context), # copy context to prevent side-effects of eval
|
|
||||||
'uid': uid,
|
|
||||||
'user': user
|
|
||||||
}
|
|
||||||
|
|
||||||
# evaluate the condition, with the specific case that a void (aka False) condition is considered as True
|
# evaluation context for python strings to evaluate
|
||||||
condition = action.condition
|
eval_context = {
|
||||||
if action.condition is False:
|
'self': obj_pool,
|
||||||
condition = True
|
'object': obj,
|
||||||
|
'obj': obj,
|
||||||
|
'pool': self.pool,
|
||||||
|
'time': time,
|
||||||
|
'cr': cr,
|
||||||
|
'uid': uid,
|
||||||
|
'user': user,
|
||||||
|
}
|
||||||
|
condition = action.condition
|
||||||
|
if condition is False:
|
||||||
|
# Void (aka False) conditions are considered as True
|
||||||
|
condition = True
|
||||||
|
if hasattr(self, 'run_action_%s_multi' % action.state):
|
||||||
|
# set active_ids in context only needed if one active_id
|
||||||
|
run_context = dict(context, active_ids=active_ids)
|
||||||
|
eval_context["context"] = run_context
|
||||||
expr = eval(str(condition), eval_context)
|
expr = eval(str(condition), eval_context)
|
||||||
if not expr:
|
if not expr:
|
||||||
continue
|
continue
|
||||||
# call the method related to the action: run_action_<STATE>
|
# call the multi method
|
||||||
if hasattr(self, 'run_action_%s' % action.state):
|
func = getattr(self, 'run_action_%s_multi' % action.state)
|
||||||
res = getattr(self, 'run_action_%s' % action.state)(cr, uid, action, eval_context=eval_context, context=run_context)
|
res = func(cr, uid, action, eval_context=eval_context, context=run_context)
|
||||||
|
|
||||||
|
elif hasattr(self, 'run_action_%s' % action.state):
|
||||||
|
func = getattr(self, 'run_action_%s' % action.state)
|
||||||
|
for active_id in active_ids:
|
||||||
|
# run context dedicated to a particular active_id
|
||||||
|
run_context = dict(context, active_ids=[active_id], active_id=active_id)
|
||||||
|
eval_context["context"] = run_context
|
||||||
|
expr = eval(str(condition), eval_context)
|
||||||
|
if not expr:
|
||||||
|
continue
|
||||||
|
# call the single method related to the action: run_action_<STATE>
|
||||||
|
res = func(cr, uid, action, eval_context=eval_context, context=run_context)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -476,7 +476,8 @@
|
||||||
<field name="model_id"/>
|
<field name="model_id"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<group expand="0" string="Group By" colspan="4" col="4">
|
<group expand="0" string="Group By" colspan="4" col="4">
|
||||||
<filter string="Action Type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'state'}"/>
|
<filter string="Action Type" domain="[]" context="{'group_by':'state'}"/>
|
||||||
|
<filter string="Model" domain="[]" context="{'group_by':'model_id'}"/>
|
||||||
</group>
|
</group>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
@ -198,7 +198,7 @@ class ir_attachment(osv.osv):
|
||||||
continue
|
continue
|
||||||
res_ids.setdefault(rmod,set()).add(rid)
|
res_ids.setdefault(rmod,set()).add(rid)
|
||||||
if values:
|
if values:
|
||||||
if values.get('res_model') and 'res_id' in values:
|
if values.get('res_model') and values.get('res_id'):
|
||||||
res_ids.setdefault(values['res_model'],set()).add(values['res_id'])
|
res_ids.setdefault(values['res_model'],set()).add(values['res_id'])
|
||||||
|
|
||||||
ima = self.pool.get('ir.model.access')
|
ima = self.pool.get('ir.model.access')
|
||||||
|
|
|
@ -253,7 +253,7 @@ class ir_fields_converter(orm.Model):
|
||||||
if not isinstance(selection, (tuple, list)):
|
if not isinstance(selection, (tuple, list)):
|
||||||
# FIXME: Don't pass context to avoid translations?
|
# FIXME: Don't pass context to avoid translations?
|
||||||
# Or just copy context & remove lang?
|
# Or just copy context & remove lang?
|
||||||
selection = selection(model, cr, uid)
|
selection = selection(model, cr, uid, context=None)
|
||||||
for item, label in selection:
|
for item, label in selection:
|
||||||
labels = self._get_translations(
|
labels = self._get_translations(
|
||||||
cr, uid, ('selection', 'model', 'code'), label, context=context)
|
cr, uid, ('selection', 'model', 'code'), label, context=context)
|
||||||
|
|
|
@ -96,8 +96,8 @@ class ir_model(osv.osv):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Model Description', size=64, translate=True, required=True),
|
'name': fields.char('Model Description', translate=True, required=True),
|
||||||
'model': fields.char('Model', size=64, required=True, select=1),
|
'model': fields.char('Model', required=True, select=1),
|
||||||
'info': fields.text('Information'),
|
'info': fields.text('Information'),
|
||||||
'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
|
'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
|
||||||
'state': fields.selection([('manual','Custom Object'),('base','Base Object')],'Type',readonly=True),
|
'state': fields.selection([('manual','Custom Object'),('base','Base Object')],'Type',readonly=True),
|
||||||
|
@ -105,7 +105,7 @@ class ir_model(osv.osv):
|
||||||
'osv_memory': fields.function(_is_osv_memory, string='Transient Model', type='boolean',
|
'osv_memory': fields.function(_is_osv_memory, string='Transient Model', type='boolean',
|
||||||
fnct_search=_search_osv_memory,
|
fnct_search=_search_osv_memory,
|
||||||
help="This field specifies whether the model is transient or not (i.e. if records are automatically deleted from the database or not)"),
|
help="This field specifies whether the model is transient or not (i.e. if records are automatically deleted from the database or not)"),
|
||||||
'modules': fields.function(_in_modules, type='char', size=128, string='In Modules', help='List of modules in which the object is defined or inherited'),
|
'modules': fields.function(_in_modules, type='char', string='In Modules', help='List of modules in which the object is defined or inherited'),
|
||||||
'view_ids': fields.function(_view_ids, type='one2many', obj='ir.ui.view', string='Views'),
|
'view_ids': fields.function(_view_ids, type='one2many', obj='ir.ui.view', string='Views'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,19 +223,19 @@ class ir_model_fields(osv.osv):
|
||||||
_rec_name = 'field_description'
|
_rec_name = 'field_description'
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Name', required=True, size=64, select=1),
|
'name': fields.char('Name', required=True, select=1),
|
||||||
'complete_name': fields.char('Complete Name', size=64, select=1),
|
'complete_name': fields.char('Complete Name', select=1),
|
||||||
'model': fields.char('Object Name', size=64, required=True, select=1,
|
'model': fields.char('Object Name', required=True, select=1,
|
||||||
help="The technical name of the model this field belongs to"),
|
help="The technical name of the model this field belongs to"),
|
||||||
'relation': fields.char('Object Relation', size=64,
|
'relation': fields.char('Object Relation',
|
||||||
help="For relationship fields, the technical name of the target model"),
|
help="For relationship fields, the technical name of the target model"),
|
||||||
'relation_field': fields.char('Relation Field', size=64,
|
'relation_field': fields.char('Relation Field',
|
||||||
help="For one2many fields, the field on the target model that implement the opposite many2one relationship"),
|
help="For one2many fields, the field on the target model that implement the opposite many2one relationship"),
|
||||||
'model_id': fields.many2one('ir.model', 'Model', required=True, select=True, ondelete='cascade',
|
'model_id': fields.many2one('ir.model', 'Model', required=True, select=True, ondelete='cascade',
|
||||||
help="The model this field belongs to"),
|
help="The model this field belongs to"),
|
||||||
'field_description': fields.char('Field Label', required=True, size=256),
|
'field_description': fields.char('Field Label', required=True),
|
||||||
'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
|
'ttype': fields.selection(_get_fields_type, 'Field Type', required=True),
|
||||||
'selection': fields.char('Selection Options',size=128, help="List of options for a selection field, "
|
'selection': fields.char('Selection Options', help="List of options for a selection field, "
|
||||||
"specified as a Python expression defining a list of (key, label) pairs. "
|
"specified as a Python expression defining a list of (key, label) pairs. "
|
||||||
"For example: [('blue','Blue'),('yellow','Yellow')]"),
|
"For example: [('blue','Blue'),('yellow','Yellow')]"),
|
||||||
'required': fields.boolean('Required'),
|
'required': fields.boolean('Required'),
|
||||||
|
@ -245,12 +245,12 @@ class ir_model_fields(osv.osv):
|
||||||
'size': fields.integer('Size'),
|
'size': fields.integer('Size'),
|
||||||
'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Type', required=True, readonly=True, select=1),
|
'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Type', required=True, readonly=True, select=1),
|
||||||
'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On Delete', help='On delete property for many2one fields'),
|
'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On Delete', help='On delete property for many2one fields'),
|
||||||
'domain': fields.char('Domain', size=256, help="The optional domain to restrict possible values for relationship fields, "
|
'domain': fields.char('Domain', help="The optional domain to restrict possible values for relationship fields, "
|
||||||
"specified as a Python expression defining a list of triplets. "
|
"specified as a Python expression defining a list of triplets. "
|
||||||
"For example: [('color','=','red')]"),
|
"For example: [('color','=','red')]"),
|
||||||
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
|
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
|
||||||
'selectable': fields.boolean('Selectable'),
|
'selectable': fields.boolean('Selectable'),
|
||||||
'modules': fields.function(_in_modules, type='char', size=128, string='In Modules', help='List of modules in which the field is defined'),
|
'modules': fields.function(_in_modules, type='char', string='In Modules', help='List of modules in which the field is defined'),
|
||||||
'serialization_field_id': fields.many2one('ir.model.fields', 'Serialization Field', domain = "[('ttype','=','serialized')]",
|
'serialization_field_id': fields.many2one('ir.model.fields', 'Serialization Field', domain = "[('ttype','=','serialized')]",
|
||||||
ondelete='cascade', help="If set, this field will be stored in the sparse "
|
ondelete='cascade', help="If set, this field will be stored in the sparse "
|
||||||
"structure of the serialization field, instead "
|
"structure of the serialization field, instead "
|
||||||
|
@ -483,7 +483,7 @@ class ir_model_constraint(Model):
|
||||||
"""
|
"""
|
||||||
_name = 'ir.model.constraint'
|
_name = 'ir.model.constraint'
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Constraint', required=True, size=128, select=1,
|
'name': fields.char('Constraint', required=True, select=1,
|
||||||
help="PostgreSQL constraint or foreign key name."),
|
help="PostgreSQL constraint or foreign key name."),
|
||||||
'model': fields.many2one('ir.model', string='Model',
|
'model': fields.many2one('ir.model', string='Model',
|
||||||
required=True, select=1),
|
required=True, select=1),
|
||||||
|
@ -552,7 +552,7 @@ class ir_model_relation(Model):
|
||||||
"""
|
"""
|
||||||
_name = 'ir.model.relation'
|
_name = 'ir.model.relation'
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Relation Name', required=True, size=128, select=1,
|
'name': fields.char('Relation Name', required=True, select=1,
|
||||||
help="PostgreSQL table name implementing a many2many relation."),
|
help="PostgreSQL table name implementing a many2many relation."),
|
||||||
'model': fields.many2one('ir.model', string='Model',
|
'model': fields.many2one('ir.model', string='Model',
|
||||||
required=True, select=1),
|
required=True, select=1),
|
||||||
|
@ -601,7 +601,7 @@ class ir_model_relation(Model):
|
||||||
class ir_model_access(osv.osv):
|
class ir_model_access(osv.osv):
|
||||||
_name = 'ir.model.access'
|
_name = 'ir.model.access'
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Name', size=64, required=True, select=True),
|
'name': fields.char('Name', required=True, select=True),
|
||||||
'active': fields.boolean('Active', help='If you uncheck the active field, it will disable the ACL without deleting it (if you delete a native ACL, it will be re-created when you reload the module.'),
|
'active': fields.boolean('Active', help='If you uncheck the active field, it will disable the ACL without deleting it (if you delete a native ACL, it will be re-created when you reload the module.'),
|
||||||
'model_id': fields.many2one('ir.model', 'Object', required=True, domain=[('osv_memory','=', False)], select=True, ondelete='cascade'),
|
'model_id': fields.many2one('ir.model', 'Object', required=True, domain=[('osv_memory','=', False)], select=True, ondelete='cascade'),
|
||||||
'group_id': fields.many2one('res.groups', 'Group', ondelete='cascade', select=True),
|
'group_id': fields.many2one('res.groups', 'Group', ondelete='cascade', select=True),
|
||||||
|
@ -815,13 +815,13 @@ class ir_model_data(osv.osv):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('External Identifier', required=True, size=128, select=1,
|
'name': fields.char('External Identifier', required=True, select=1,
|
||||||
help="External Key/Identifier that can be used for "
|
help="External Key/Identifier that can be used for "
|
||||||
"data integration with third-party systems"),
|
"data integration with third-party systems"),
|
||||||
'complete_name': fields.function(_complete_name_get, type='char', string='Complete ID'),
|
'complete_name': fields.function(_complete_name_get, type='char', string='Complete ID'),
|
||||||
'display_name': fields.function(_display_name_get, type='char', string='Record Name'),
|
'display_name': fields.function(_display_name_get, type='char', string='Record Name'),
|
||||||
'model': fields.char('Model Name', required=True, size=64, select=1),
|
'model': fields.char('Model Name', required=True, select=1),
|
||||||
'module': fields.char('Module', required=True, size=64, select=1),
|
'module': fields.char('Module', required=True, select=1),
|
||||||
'res_id': fields.integer('Record ID', select=1,
|
'res_id': fields.integer('Record ID', select=1,
|
||||||
help="ID of the target record in the database"),
|
help="ID of the target record in the database"),
|
||||||
'noupdate': fields.boolean('Non Updatable'),
|
'noupdate': fields.boolean('Non Updatable'),
|
||||||
|
@ -1128,7 +1128,7 @@ class ir_model_data(osv.osv):
|
||||||
return True
|
return True
|
||||||
to_unlink = []
|
to_unlink = []
|
||||||
cr.execute("""SELECT id,name,model,res_id,module FROM ir_model_data
|
cr.execute("""SELECT id,name,model,res_id,module FROM ir_model_data
|
||||||
WHERE module IN %s AND res_id IS NOT NULL AND noupdate=%s""",
|
WHERE module IN %s AND res_id IS NOT NULL AND noupdate=%s ORDER BY id DESC""",
|
||||||
(tuple(modules), False))
|
(tuple(modules), False))
|
||||||
for (id, name, model, res_id, module) in cr.fetchall():
|
for (id, name, model, res_id, module) in cr.fetchall():
|
||||||
if (module,name) not in self.loads:
|
if (module,name) not in self.loads:
|
||||||
|
|
|
@ -182,7 +182,7 @@ class ir_translation(osv.osv):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
record = self.browse(cr, uid, id, context=context)
|
record = self.browse(cr, uid, id, context=context)
|
||||||
if value and record.type == 'model':
|
if record.type == 'model':
|
||||||
model_name, field = record.name.split(',')
|
model_name, field = record.name.split(',')
|
||||||
model = self.pool.get(model_name)
|
model = self.pool.get(model_name)
|
||||||
#We need to take the context without the language information, because we want to write on the
|
#We need to take the context without the language information, because we want to write on the
|
||||||
|
|
|
@ -1212,7 +1212,7 @@
|
||||||
<record id="ve" model="res.country">
|
<record id="ve" model="res.country">
|
||||||
<field name="name">Venezuela</field>
|
<field name="name">Venezuela</field>
|
||||||
<field name="code">ve</field>
|
<field name="code">ve</field>
|
||||||
<field name="currency_id" ref="VUB"/>
|
<field name="currency_id" ref="VEF"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="vg" model="res.country">
|
<record id="vg" model="res.country">
|
||||||
<field name="name">Virgin Islands (British)</field>
|
<field name="name">Virgin Islands (British)</field>
|
||||||
|
|
|
@ -1540,7 +1540,7 @@
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="VUB" model="res.currency">
|
<record id="VUB" model="res.currency">
|
||||||
<field name="name">VUB</field>
|
<field name="name">VEB</field>
|
||||||
<field name="symbol">Bs</field>
|
<field name="symbol">Bs</field>
|
||||||
<field name="rounding">0.01</field>
|
<field name="rounding">0.01</field>
|
||||||
<field name="accuracy">4</field>
|
<field name="accuracy">4</field>
|
||||||
|
|
|
@ -329,7 +329,7 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Search Partner">
|
<search string="Search Partner">
|
||||||
<field name="name"
|
<field name="name"
|
||||||
filter_domain="['|','|',('display_name','ilike',self),('ref','=',self),('email,'ilike',self)]"/>
|
filter_domain="['|','|',('display_name','ilike',self),('ref','=',self),('email','ilike',self)]"/>
|
||||||
<filter help="My Partners" icon="terp-personal+" domain="[('user_id','=',uid)]"/>
|
<filter help="My Partners" icon="terp-personal+" domain="[('user_id','=',uid)]"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Persons" name="type_person" domain="[('is_company','=',0)]"/>
|
<filter string="Persons" name="type_person" domain="[('is_company','=',0)]"/>
|
||||||
|
|
|
@ -169,7 +169,8 @@ class res_users(osv.osv):
|
||||||
}
|
}
|
||||||
|
|
||||||
def on_change_login(self, cr, uid, ids, login, context=None):
|
def on_change_login(self, cr, uid, ids, login, context=None):
|
||||||
return {'value': {'email': login}}
|
v = {'email': login} if tools.single_email_re.match(login) else {}
|
||||||
|
return {'value': v}
|
||||||
|
|
||||||
def onchange_state(self, cr, uid, ids, state_id, context=None):
|
def onchange_state(self, cr, uid, ids, state_id, context=None):
|
||||||
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
|
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
|
||||||
|
|
|
@ -304,5 +304,47 @@ class test_partner_recursion(common.TransactionCase):
|
||||||
cr, uid, p1, p2, p3 = self.cr, self.uid, self.p1, self.p2, self.p3
|
cr, uid, p1, p2, p3 = self.cr, self.uid, self.p1, self.p2, self.p3
|
||||||
self.assertTrue(self.res_partner.write(cr, uid, [p1,p2,p3], {'phone': '123456'}))
|
self.assertTrue(self.res_partner.write(cr, uid, [p1,p2,p3], {'phone': '123456'}))
|
||||||
|
|
||||||
|
class test_translation(common.TransactionCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(test_translation, self).setUp()
|
||||||
|
self.res_category = self.registry('res.partner.category')
|
||||||
|
self.ir_translation = self.registry('ir.translation')
|
||||||
|
cr, uid = self.cr, self.uid
|
||||||
|
self.registry('ir.translation').load(cr, ['base'], ['fr_FR'])
|
||||||
|
self.cat_id = self.res_category.create(cr, uid, {'name': 'Customers'})
|
||||||
|
self.ir_translation.create(cr, uid, {'name': 'res.partner.category,name', 'module':'base',
|
||||||
|
'value': 'Clients', 'res_id': self.cat_id, 'lang':'fr_FR', 'state':'translated', 'type': 'model'})
|
||||||
|
|
||||||
|
def test_101_create_translated_record(self):
|
||||||
|
cr, uid = self.cr, self.uid
|
||||||
|
|
||||||
|
no_context_cat = self.res_category.browse(cr, uid, self.cat_id)
|
||||||
|
self.assertEqual(no_context_cat.name, 'Customers', "Error in basic name_get")
|
||||||
|
|
||||||
|
fr_context_cat = self.res_category.browse(cr, uid, self.cat_id, context={'lang':'fr_FR'})
|
||||||
|
self.assertEqual(fr_context_cat.name, 'Clients', "Translation not found")
|
||||||
|
|
||||||
|
def test_102_duplicate_record(self):
|
||||||
|
cr, uid = self.cr, self.uid
|
||||||
|
self.new_cat_id = self.res_category.copy(cr, uid, self.cat_id, context={'lang':'fr_FR'})
|
||||||
|
|
||||||
|
no_context_cat = self.res_category.browse(cr, uid, self.new_cat_id)
|
||||||
|
self.assertEqual(no_context_cat.name, 'Customers', "Duplication did not set untranslated value")
|
||||||
|
|
||||||
|
fr_context_cat = self.res_category.browse(cr, uid, self.new_cat_id, context={'lang':'fr_FR'})
|
||||||
|
self.assertEqual(fr_context_cat.name, 'Clients', "Did not found translation for initial value")
|
||||||
|
|
||||||
|
def test_103_duplicate_record_fr(self):
|
||||||
|
cr, uid = self.cr, self.uid
|
||||||
|
self.new_fr_cat_id = self.res_category.copy(cr, uid, self.cat_id, default={'name': 'Clients (copie)'}, context={'lang':'fr_FR'})
|
||||||
|
|
||||||
|
no_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id)
|
||||||
|
self.assertEqual(no_context_cat.name, 'Customers', "Duplication erased original untranslated value")
|
||||||
|
|
||||||
|
fr_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id, context={'lang':'fr_FR'})
|
||||||
|
self.assertEqual(fr_context_cat.name, 'Clients (copie)', "Did not used default value for translated value")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest2.main()
|
unittest2.main()
|
||||||
|
|
|
@ -40,6 +40,19 @@ class test_views(common.TransactionCase):
|
||||||
""",
|
""",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_20_remove_unexisting_attribute(self):
|
||||||
|
Views = self.registry('ir.ui.view')
|
||||||
|
Views.create(self.cr, self.uid, {
|
||||||
|
'name': 'Test View',
|
||||||
|
'model': 'ir.ui.view',
|
||||||
|
'inherit_id': self.browse_ref('base.view_view_tree').id,
|
||||||
|
'arch': """<?xml version="1.0"?>
|
||||||
|
<xpath expr="//field[@name='name']" position="attributes">
|
||||||
|
<attribute name="non_existing_attribute"></attribute>
|
||||||
|
</xpath>
|
||||||
|
""",
|
||||||
|
})
|
||||||
|
|
||||||
def _insert_view(self, **kw):
|
def _insert_view(self, **kw):
|
||||||
"""Insert view into database via a query to passtrough validation"""
|
"""Insert view into database via a query to passtrough validation"""
|
||||||
kw.pop('id', None)
|
kw.pop('id', None)
|
||||||
|
|
|
@ -94,11 +94,11 @@ def preload_registry(dbname):
|
||||||
""" Preload a registry, and start the cron."""
|
""" Preload a registry, and start the cron."""
|
||||||
try:
|
try:
|
||||||
update_module = True if openerp.tools.config['init'] or openerp.tools.config['update'] else False
|
update_module = True if openerp.tools.config['init'] or openerp.tools.config['update'] else False
|
||||||
openerp.modules.registry.RegistryManager.new(dbname, update_module=update_module)
|
registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=update_module)
|
||||||
except Exception:
|
except Exception:
|
||||||
_logger.exception('Failed to initialize database `%s`.', dbname)
|
_logger.exception('Failed to initialize database `%s`.', dbname)
|
||||||
return False
|
return False
|
||||||
return True
|
return registry._assertion_report.failures == 0
|
||||||
|
|
||||||
def run_test_file(dbname, test_file):
|
def run_test_file(dbname, test_file):
|
||||||
""" Preload a registry, possibly run a test file, and start the cron."""
|
""" Preload a registry, possibly run a test file, and start the cron."""
|
||||||
|
|
|
@ -342,7 +342,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||||
if processed_modules:
|
if processed_modules:
|
||||||
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
|
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
|
||||||
for (model, name) in cr.fetchall():
|
for (model, name) in cr.fetchall():
|
||||||
if model in registry and not registry[model].is_transient():
|
if model in registry and not registry[model].is_transient() and isinstance(registry[model], openerp.osv.orm.AbstractModel):
|
||||||
_logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,1,1,1',
|
_logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,1,1,1',
|
||||||
model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))
|
model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))
|
||||||
|
|
||||||
|
|
|
@ -199,15 +199,16 @@ class RegistryManager(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls, db_name, force_demo=False, status=None, update_module=False):
|
def get(cls, db_name, force_demo=False, status=None, update_module=False):
|
||||||
""" Return a registry for a given database name."""
|
""" Return a registry for a given database name."""
|
||||||
try:
|
with cls.registries_lock:
|
||||||
return cls.registries[db_name]
|
try:
|
||||||
except KeyError:
|
return cls.registries[db_name]
|
||||||
return cls.new(db_name, force_demo, status,
|
except KeyError:
|
||||||
update_module)
|
return cls.new(db_name, force_demo, status,
|
||||||
finally:
|
update_module)
|
||||||
# set db tracker - cleaned up at the WSGI
|
finally:
|
||||||
# dispatching phase in openerp.service.wsgi_server.application
|
# set db tracker - cleaned up at the WSGI
|
||||||
threading.current_thread().dbname = db_name
|
# dispatching phase in openerp.service.wsgi_server.application
|
||||||
|
threading.current_thread().dbname = db_name
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls, db_name, force_demo=False, status=None,
|
def new(cls, db_name, force_demo=False, status=None,
|
||||||
|
|
|
@ -1147,7 +1147,7 @@ class function(_column):
|
||||||
# make the result a tuple if it is not already one
|
# make the result a tuple if it is not already one
|
||||||
if isinstance(value, (int,long)) and hasattr(obj._columns[field], 'relation'):
|
if isinstance(value, (int,long)) and hasattr(obj._columns[field], 'relation'):
|
||||||
obj_model = obj.pool[obj._columns[field].relation]
|
obj_model = obj.pool[obj._columns[field].relation]
|
||||||
dict_names = dict(obj_model.name_get(cr, uid, [value], context))
|
dict_names = dict(obj_model.name_get(cr, SUPERUSER_ID, [value], context))
|
||||||
result = (value, dict_names[value])
|
result = (value, dict_names[value])
|
||||||
|
|
||||||
if field_type == 'binary':
|
if field_type == 'binary':
|
||||||
|
|
|
@ -399,7 +399,15 @@ class browse_record(object):
|
||||||
ids = filter(lambda id: name not in self._data[id], self._data.keys())
|
ids = filter(lambda id: name not in self._data[id], self._data.keys())
|
||||||
# read the results
|
# read the results
|
||||||
field_names = map(lambda x: x[0], fields_to_fetch)
|
field_names = map(lambda x: x[0], fields_to_fetch)
|
||||||
field_values = self._table.read(self._cr, self._uid, ids, field_names, context=self._context, load="_classic_write")
|
try:
|
||||||
|
field_values = self._table.read(self._cr, self._uid, ids, field_names, context=self._context, load="_classic_write")
|
||||||
|
except (openerp.exceptions.AccessError, except_orm):
|
||||||
|
if len(ids) == 1:
|
||||||
|
raise
|
||||||
|
# prefetching attempt failed, perhaps we're violating ACL restrictions involuntarily
|
||||||
|
_logger.info('Prefetching attempt for fields %s on %s failed for ids %s, re-trying just for id %s', field_names, self._model._name, ids, self._id)
|
||||||
|
ids = [self._id]
|
||||||
|
field_values = self._table.read(self._cr, self._uid, ids, field_names, context=self._context, load="_classic_write")
|
||||||
|
|
||||||
# TODO: improve this, very slow for reports
|
# TODO: improve this, very slow for reports
|
||||||
if self._fields_process:
|
if self._fields_process:
|
||||||
|
@ -2153,8 +2161,8 @@ class BaseModel(object):
|
||||||
attribute = (child.get('name'), child.text and child.text.encode('utf8') or None)
|
attribute = (child.get('name'), child.text and child.text.encode('utf8') or None)
|
||||||
if attribute[1]:
|
if attribute[1]:
|
||||||
node.set(attribute[0], attribute[1])
|
node.set(attribute[0], attribute[1])
|
||||||
else:
|
elif attribute[0] in node.attrib:
|
||||||
del(node.attrib[attribute[0]])
|
del node.attrib[attribute[0]]
|
||||||
else:
|
else:
|
||||||
sib = node.getnext()
|
sib = node.getnext()
|
||||||
for child in spec:
|
for child in spec:
|
||||||
|
@ -4997,10 +5005,7 @@ class BaseModel(object):
|
||||||
else:
|
else:
|
||||||
default['state'] = self._defaults['state']
|
default['state'] = self._defaults['state']
|
||||||
|
|
||||||
context_wo_lang = context.copy()
|
data = self.read(cr, uid, [id,], context=context)
|
||||||
if 'lang' in context:
|
|
||||||
del context_wo_lang['lang']
|
|
||||||
data = self.read(cr, uid, [id,], context=context_wo_lang)
|
|
||||||
if data:
|
if data:
|
||||||
data = data[0]
|
data = data[0]
|
||||||
else:
|
else:
|
||||||
|
@ -5060,36 +5065,50 @@ class BaseModel(object):
|
||||||
# TODO it seems fields_get can be replaced by _all_columns (no need for translation)
|
# TODO it seems fields_get can be replaced by _all_columns (no need for translation)
|
||||||
fields = self.fields_get(cr, uid, context=context)
|
fields = self.fields_get(cr, uid, context=context)
|
||||||
|
|
||||||
translation_records = []
|
|
||||||
for field_name, field_def in fields.items():
|
for field_name, field_def in fields.items():
|
||||||
|
# removing the lang to compare untranslated values
|
||||||
|
context_wo_lang = dict(context, lang=None)
|
||||||
|
old_record, new_record = self.browse(cr, uid, [old_id, new_id], context=context_wo_lang)
|
||||||
# we must recursively copy the translations for o2o and o2m
|
# we must recursively copy the translations for o2o and o2m
|
||||||
if field_def['type'] == 'one2many':
|
if field_def['type'] == 'one2many':
|
||||||
target_obj = self.pool[field_def['relation']]
|
target_obj = self.pool[field_def['relation']]
|
||||||
old_record, new_record = self.read(cr, uid, [old_id, new_id], [field_name], context=context)
|
|
||||||
# here we rely on the order of the ids to match the translations
|
# here we rely on the order of the ids to match the translations
|
||||||
# as foreseen in copy_data()
|
# as foreseen in copy_data()
|
||||||
old_children = sorted(old_record[field_name])
|
old_children = sorted(r.id for r in old_record[field_name])
|
||||||
new_children = sorted(new_record[field_name])
|
new_children = sorted(r.id for r in new_record[field_name])
|
||||||
for (old_child, new_child) in zip(old_children, new_children):
|
for (old_child, new_child) in zip(old_children, new_children):
|
||||||
target_obj.copy_translations(cr, uid, old_child, new_child, context=context)
|
target_obj.copy_translations(cr, uid, old_child, new_child, context=context)
|
||||||
# and for translatable fields we keep them for copy
|
# and for translatable fields we keep them for copy
|
||||||
elif field_def.get('translate'):
|
elif field_def.get('translate'):
|
||||||
trans_name = ''
|
|
||||||
if field_name in self._columns:
|
if field_name in self._columns:
|
||||||
trans_name = self._name + "," + field_name
|
trans_name = self._name + "," + field_name
|
||||||
|
target_id = new_id
|
||||||
|
source_id = old_id
|
||||||
elif field_name in self._inherit_fields:
|
elif field_name in self._inherit_fields:
|
||||||
trans_name = self._inherit_fields[field_name][0] + "," + field_name
|
trans_name = self._inherit_fields[field_name][0] + "," + field_name
|
||||||
if trans_name:
|
# get the id of the parent record to set the translation
|
||||||
trans_ids = trans_obj.search(cr, uid, [
|
inherit_field_name = self._inherit_fields[field_name][1]
|
||||||
('name', '=', trans_name),
|
target_id = new_record[inherit_field_name].id
|
||||||
('res_id', '=', old_id)
|
source_id = old_record[inherit_field_name].id
|
||||||
])
|
else:
|
||||||
translation_records.extend(trans_obj.read(cr, uid, trans_ids, context=context))
|
continue
|
||||||
|
|
||||||
for record in translation_records:
|
trans_ids = trans_obj.search(cr, uid, [
|
||||||
del record['id']
|
('name', '=', trans_name),
|
||||||
record['res_id'] = new_id
|
('res_id', '=', source_id)
|
||||||
trans_obj.create(cr, uid, record, context=context)
|
])
|
||||||
|
user_lang = context.get('lang')
|
||||||
|
for record in trans_obj.read(cr, uid, trans_ids, context=context):
|
||||||
|
del record['id']
|
||||||
|
# remove source to avoid triggering _set_src
|
||||||
|
del record['source']
|
||||||
|
record.update({'res_id': target_id})
|
||||||
|
if user_lang and user_lang == record['lang']:
|
||||||
|
# 'source' to force the call to _set_src
|
||||||
|
# 'value' needed if value is changed in copy(), want to see the new_value
|
||||||
|
record['source'] = old_record[field_name]
|
||||||
|
record['value'] = new_record[field_name]
|
||||||
|
trans_obj.create(cr, uid, record, context=context)
|
||||||
|
|
||||||
|
|
||||||
def copy(self, cr, uid, id, default=None, context=None):
|
def copy(self, cr, uid, id, default=None, context=None):
|
||||||
|
|
|
@ -242,7 +242,7 @@ class _rml_styles(object,):
|
||||||
if sname in self.styles_obj:
|
if sname in self.styles_obj:
|
||||||
style = self.styles_obj[sname]
|
style = self.styles_obj[sname]
|
||||||
else:
|
else:
|
||||||
_logger.warning('Warning: style not found, %s - setting default!\n' % (node.get('style'),) )
|
_logger.debug('Warning: style not found, %s - setting default!', node.get('style'))
|
||||||
if not style:
|
if not style:
|
||||||
style = self.default_style['Normal']
|
style = self.default_style['Normal']
|
||||||
para_update = self._para_style_update(node)
|
para_update = self._para_style_update(node)
|
||||||
|
@ -631,6 +631,18 @@ class _rml_Illustration(platypus.flowables.Flowable):
|
||||||
drw = _rml_draw(self.localcontext ,self.node,self.styles, images=self.self2.images, path=self.self2.path, title=self.self2.title)
|
drw = _rml_draw(self.localcontext ,self.node,self.styles, images=self.self2.images, path=self.self2.path, title=self.self2.title)
|
||||||
drw.render(self.canv, None)
|
drw.render(self.canv, None)
|
||||||
|
|
||||||
|
# Workaround for issue #15: https://bitbucket.org/rptlab/reportlab/issue/15/infinite-pages-produced-when-splitting
|
||||||
|
original_pto_split = platypus.flowables.PTOContainer.split
|
||||||
|
def split(self, availWidth, availHeight):
|
||||||
|
res = original_pto_split(self, availWidth, availHeight)
|
||||||
|
if len(res) > 2 and len(self._content) > 0:
|
||||||
|
header = self._content[0]._ptoinfo.header
|
||||||
|
trailer = self._content[0]._ptoinfo.trailer
|
||||||
|
if isinstance(res[-2], platypus.flowables.UseUpSpace) and len(header + trailer) == len(res[:-2]):
|
||||||
|
return []
|
||||||
|
return res
|
||||||
|
platypus.flowables.PTOContainer.split = split
|
||||||
|
|
||||||
class _rml_flowable(object):
|
class _rml_flowable(object):
|
||||||
def __init__(self, doc, localcontext, images=None, path='.', title=None, canvas=None):
|
def __init__(self, doc, localcontext, images=None, path='.', title=None, canvas=None):
|
||||||
if images is None:
|
if images is None:
|
||||||
|
@ -1012,11 +1024,16 @@ class _rml_template(object):
|
||||||
# Reset Page Number with new story tag
|
# Reset Page Number with new story tag
|
||||||
fis.append(PageReset())
|
fis.append(PageReset())
|
||||||
story_cnt += 1
|
story_cnt += 1
|
||||||
if self.localcontext and self.localcontext.get('internal_header',False):
|
try:
|
||||||
self.doc_tmpl.afterFlowable(fis)
|
if self.localcontext and self.localcontext.get('internal_header',False):
|
||||||
self.doc_tmpl.build(fis,canvasmaker=NumberedCanvas)
|
self.doc_tmpl.afterFlowable(fis)
|
||||||
else:
|
self.doc_tmpl.build(fis,canvasmaker=NumberedCanvas)
|
||||||
self.doc_tmpl.build(fis)
|
else:
|
||||||
|
self.doc_tmpl.build(fis)
|
||||||
|
except platypus.doctemplate.LayoutError, e:
|
||||||
|
e.name = 'Print Error'
|
||||||
|
e.value = 'The document you are trying to print contains a table row that does not fit on one page. Please try to split it in smaller rows or contact your administrator.'
|
||||||
|
raise
|
||||||
|
|
||||||
def parseNode(rml, localcontext=None, fout=None, images=None, path='.', title=None):
|
def parseNode(rml, localcontext=None, fout=None, images=None, path='.', title=None):
|
||||||
node = etree.XML(rml)
|
node = etree.XML(rml)
|
||||||
|
|
|
@ -95,9 +95,10 @@ class TestACL(common.TransactionCase):
|
||||||
part = P.browse(self.cr, self.demo_uid, pid)
|
part = P.browse(self.cr, self.demo_uid, pid)
|
||||||
# accessing fields must no raise exceptions...
|
# accessing fields must no raise exceptions...
|
||||||
part.name
|
part.name
|
||||||
# ... except they are restricted
|
# ... except if they are restricted
|
||||||
with self.assertRaises(openerp.osv.orm.except_orm) as cm:
|
with self.assertRaises(openerp.osv.orm.except_orm) as cm:
|
||||||
part.email
|
with mute_logger('openerp.osv.orm'):
|
||||||
|
part.email
|
||||||
|
|
||||||
self.assertEqual(cm.exception.args[0], 'Access Denied')
|
self.assertEqual(cm.exception.args[0], 'Access Denied')
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -87,7 +87,9 @@ def html_sanitize(src, silent=True):
|
||||||
# some corner cases make the parser crash (such as <SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT> in test_mail)
|
# some corner cases make the parser crash (such as <SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT> in test_mail)
|
||||||
cleaner = clean.Cleaner(**kwargs)
|
cleaner = clean.Cleaner(**kwargs)
|
||||||
cleaned = cleaner.clean_html(src)
|
cleaned = cleaner.clean_html(src)
|
||||||
except etree.ParserError:
|
except etree.ParserError, e:
|
||||||
|
if 'empty' in str(e):
|
||||||
|
return ""
|
||||||
if not silent:
|
if not silent:
|
||||||
raise
|
raise
|
||||||
logger.warning('ParserError obtained when sanitizing %r', src, exc_info=True)
|
logger.warning('ParserError obtained when sanitizing %r', src, exc_info=True)
|
||||||
|
|
|
@ -470,6 +470,7 @@ ALL_LANGUAGES = {
|
||||||
'ja_JP': u'Japanese / 日本語',
|
'ja_JP': u'Japanese / 日本語',
|
||||||
'ko_KP': u'Korean (KP) / 한국어 (KP)',
|
'ko_KP': u'Korean (KP) / 한국어 (KP)',
|
||||||
'ko_KR': u'Korean (KR) / 한국어 (KR)',
|
'ko_KR': u'Korean (KR) / 한국어 (KR)',
|
||||||
|
'lo_LA': u'Lao / ພາສາລາວ',
|
||||||
'lt_LT': u'Lithuanian / Lietuvių kalba',
|
'lt_LT': u'Lithuanian / Lietuvių kalba',
|
||||||
'lv_LV': u'Latvian / latviešu valoda',
|
'lv_LV': u'Latvian / latviešu valoda',
|
||||||
'ml_IN': u'Malayalam / മലയാളം',
|
'ml_IN': u'Malayalam / മലയാളം',
|
||||||
|
|
|
@ -448,9 +448,9 @@ class YamlInterpreter(object):
|
||||||
result = getattr(model, match.group(1))(self.cr, SUPERUSER_ID, [], *args)
|
result = getattr(model, match.group(1))(self.cr, SUPERUSER_ID, [], *args)
|
||||||
for key, val in (result or {}).get('value', {}).items():
|
for key, val in (result or {}).get('value', {}).items():
|
||||||
assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist either on the object '%s', either in the view '%s' used for the creation" % (key, match.group(1), model._name, view_info['name'])
|
assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist either on the object '%s', either in the view '%s' used for the creation" % (key, match.group(1), model._name, view_info['name'])
|
||||||
record_dict[key] = process_val(key, val)
|
if key not in fields:
|
||||||
#if (key in fields) and record_dict[key] == process_val(key, val):
|
# do not shadow values explicitly set in yaml.
|
||||||
# print '*** You can remove these lines:', key, val
|
record_dict[key] = process_val(key, val)
|
||||||
else:
|
else:
|
||||||
nodes = list(el) + nodes
|
nodes = list(el) + nodes
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -40,8 +40,7 @@ def get_addons_from_paths(paths, exclude):
|
||||||
module_names = []
|
module_names = []
|
||||||
for p in paths:
|
for p in paths:
|
||||||
if os.path.exists(p):
|
if os.path.exists(p):
|
||||||
names = list(set(os.listdir(p)))
|
names = [n for n in os.listdir(p) if os.path.isfile(os.path.join(p, n, '__openerp__.py')) and not n.startswith('.') and n not in exclude]
|
||||||
names = filter(lambda a: not (a.startswith('.') or a in exclude), names)
|
|
||||||
names = filter(lambda a: os.path.isdir(os.path.join(p, a)), names)
|
names = filter(lambda a: os.path.isdir(os.path.join(p, a)), names)
|
||||||
names = filter(lambda a: os.path.exists(os.path.join(p, a, '__openerp__.py')), names)
|
names = filter(lambda a: os.path.exists(os.path.join(p, a, '__openerp__.py')), names)
|
||||||
module_names.extend(names)
|
module_names.extend(names)
|
||||||
|
|
Loading…
Reference in New Issue