[MERGE] from trunk
bzr revid: xmo@openerp.com-20121010154605-u16f57fnck148ued
This commit is contained in:
commit
7a7876d4a8
|
@ -557,7 +557,9 @@ class ir_model_access(osv.osv):
|
|||
model_name = model
|
||||
|
||||
# TransientModel records have no access rights, only an implicit access rule
|
||||
if self.pool.get(model_name).is_transient():
|
||||
if not self.pool.get(model_name):
|
||||
_logger.error('Missing model %s' % (model_name, ))
|
||||
elif self.pool.get(model_name).is_transient():
|
||||
return True
|
||||
|
||||
# We check if a specific rule exists
|
||||
|
|
|
@ -265,7 +265,7 @@ class ir_ui_menu(osv.osv):
|
|||
}
|
||||
if menu.action and menu.action.type in ('ir.actions.act_window','ir.actions.client') and menu.action.res_model:
|
||||
obj = self.pool.get(menu.action.res_model)
|
||||
if obj._needaction:
|
||||
if obj and obj._needaction:
|
||||
if menu.action.type=='ir.actions.act_window':
|
||||
dom = menu.action.domain and eval(menu.action.domain, {'uid': uid}) or []
|
||||
else:
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<search string="Search modules">
|
||||
<field name="name" filter_domain="['|', '|', ('summary', 'ilike', self), ('shortdesc', 'ilike', self), ('name',
|
||||
'ilike', self)]"/>
|
||||
'ilike', self)]" string="Module"/>
|
||||
<filter name="app" icon="terp-check" string="Apps" domain="[('application', '=', 1)]"/>
|
||||
<filter name="extra" icon="terp-check" string="Extra" domain="[('application', '=', 0)]"/>
|
||||
<separator/>
|
||||
|
|
|
@ -106,8 +106,8 @@
|
|||
<field name="zip" class="oe_inline" placeholder="ZIP"/>
|
||||
<field name="city" class="oe_inline" placeholder="City"/>
|
||||
</div>
|
||||
<field name="state_id" placeholder="State" options='{"no_open": true}'/>
|
||||
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
|
||||
<field name="state_id" placeholder="State" options='{"no_open": True}'/>
|
||||
<field name="country_id" placeholder="Country" options='{"no_open": True}'/>
|
||||
</div>
|
||||
</group>
|
||||
<group name="bank" string="Information About the Bank">
|
||||
|
|
|
@ -46,10 +46,10 @@
|
|||
<field name="street2"/>
|
||||
<div>
|
||||
<field name="city" placeholder="City" style="width: 40%%"/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 24%%" options='{"no_open": true}'/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 24%%" options='{"no_open": True}'/>
|
||||
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
|
||||
</div>
|
||||
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": true}' on_change="on_change_country(country_id)"/>
|
||||
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": True}' on_change="on_change_country(country_id)"/>
|
||||
</div>
|
||||
<label for="rml_header1"/>
|
||||
<div>
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<group>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="country_id" options='{"no_open": true}'/>
|
||||
<field name="country_id" options='{"no_open": True}'/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -301,7 +301,7 @@ class res_partner(osv.osv, format_address):
|
|||
|
||||
def onchange_type(self, cr, uid, ids, is_company, context=None):
|
||||
# get value as for an onchange on the image
|
||||
value = tools.image_get_resized_images(self._get_default_image(cr, uid, is_company, context), return_big=True)
|
||||
value = tools.image_get_resized_images(self._get_default_image(cr, uid, is_company, context), return_big=True, return_medium=False, return_small=False)
|
||||
value['title'] = False
|
||||
if is_company:
|
||||
value['parent_id'] = False
|
||||
|
|
|
@ -161,10 +161,10 @@
|
|||
<field name="street2"/>
|
||||
<div class="address_format">
|
||||
<field name="city" placeholder="City" style="width: 40%%"/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 37%%" options='{"no_open": true}'/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 37%%" options='{"no_open": True}'/>
|
||||
<field name="zip" placeholder="ZIP" style="width: 20%%"/>
|
||||
</div>
|
||||
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": true}'/>
|
||||
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": True}'/>
|
||||
</div>
|
||||
<field name="website" widget="url" placeholder="e.g. www.openerp.com"/>
|
||||
</group>
|
||||
|
@ -177,7 +177,7 @@
|
|||
<field name="email" widget="email"/>
|
||||
<field name="title" domain="[('domain', '=', 'contact')]"
|
||||
groups="base.group_no_one"
|
||||
options='{"no_open": true}' attrs="{'invisible': [('is_company','=', True)]}" />
|
||||
options='{"no_open": True}' attrs="{'invisible': [('is_company','=', True)]}" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
|
|
|
@ -341,14 +341,12 @@ class res_users(osv.osv):
|
|||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
user2copy = self.read(cr, uid, [id], ['login','name'])[0]
|
||||
if default is None:
|
||||
default = {}
|
||||
copy_pattern = _("%s (copy)")
|
||||
copydef = dict(login=(copy_pattern % user2copy['login']),
|
||||
name=(copy_pattern % user2copy['name']),
|
||||
)
|
||||
copydef.update(default)
|
||||
return super(res_users, self).copy(cr, uid, id, copydef, context)
|
||||
default = dict(default or {})
|
||||
if ('name' not in default) and ('partner_id' not in default):
|
||||
default['name'] = _("%s (copy)") % user2copy['name']
|
||||
if 'login' not in default:
|
||||
default['login'] = _("%s (copy)") % user2copy['login']
|
||||
return super(res_users, self).copy(cr, uid, id, default, context)
|
||||
|
||||
def context_get(self, cr, uid, context=None):
|
||||
user = self.browse(cr, SUPERUSER_ID, uid, context)
|
||||
|
|
|
@ -52,6 +52,7 @@ import pickle
|
|||
import re
|
||||
import simplejson
|
||||
import time
|
||||
import traceback
|
||||
import types
|
||||
|
||||
import psycopg2
|
||||
|
@ -65,6 +66,7 @@ import openerp.tools as tools
|
|||
from openerp.tools.config import config
|
||||
from openerp.tools.misc import CountingStream
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from ast import literal_eval
|
||||
from openerp.tools.translate import _
|
||||
from openerp import SUPERUSER_ID
|
||||
from query import Query
|
||||
|
@ -377,6 +379,8 @@ class browse_record(object):
|
|||
else:
|
||||
error_msg = "Field '%s' does not exist in object '%s'" % (name, self)
|
||||
self.__logger.warning(error_msg)
|
||||
if self.__logger.isEnabledFor(logging.DEBUG):
|
||||
self.__logger.debug(''.join(traceback.format_stack()))
|
||||
raise KeyError(error_msg)
|
||||
|
||||
# if the field is a classic one or a many2one, we'll fetch all classic and many2one fields
|
||||
|
@ -1808,7 +1812,13 @@ class BaseModel(object):
|
|||
field = model_fields.get(node.get('name'))
|
||||
if field:
|
||||
transfer_field_to_modifiers(field, modifiers)
|
||||
|
||||
#evaluate the options as python code, but send it as json to the client
|
||||
if node.get('options'):
|
||||
try:
|
||||
node.set('options', simplejson.dumps(literal_eval(node.get('options'))))
|
||||
except Exception, e:
|
||||
_logger.exception('Invalid `options´ attribute, should be a valid python expression: %r', node.get('options'))
|
||||
raise except_orm('Invalid options', 'Invalid options: %r %s' % (node.get('options'), e))
|
||||
|
||||
elif node.tag in ('form', 'tree'):
|
||||
result = self.view_header_get(cr, user, False, node.tag, context)
|
||||
|
@ -3043,14 +3053,14 @@ class BaseModel(object):
|
|||
('numeric', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
|
||||
('float8', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
|
||||
]
|
||||
if f_pg_type == 'varchar' and f._type == 'char' and f_pg_size < f.size:
|
||||
if f_pg_type == 'varchar' and f._type == 'char' and ((f.size is None and f_pg_size) or f_pg_size < f.size):
|
||||
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
|
||||
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, pg_varchar(f.size)))
|
||||
cr.execute('UPDATE "%s" SET "%s"=temp_change_size::%s' % (self._table, k, pg_varchar(f.size)))
|
||||
cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
|
||||
cr.commit()
|
||||
_schema.debug("Table '%s': column '%s' (type varchar) changed size from %s to %s",
|
||||
self._table, k, f_pg_size, f.size)
|
||||
self._table, k, f_pg_size or 'unlimited', f.size or 'unlimited')
|
||||
for c in casts:
|
||||
if (f_pg_type==c[0]) and (f._type==c[1]):
|
||||
if f_pg_type != f_obj_type:
|
||||
|
@ -3283,8 +3293,7 @@ class BaseModel(object):
|
|||
# attlen is the number of bytes necessary to represent the type when
|
||||
# the type has a fixed size. If the type has a varying size attlen is
|
||||
# -1 and atttypmod is the size limit + 4, or -1 if there is no limit.
|
||||
# Thus the query can return a negative size for a unlimited varchar.
|
||||
cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
|
||||
cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN (CASE WHEN a.atttypmod=-1 THEN 0 ELSE a.atttypmod-4 END) ELSE a.attlen END as size " \
|
||||
"FROM pg_class c,pg_attribute a,pg_type t " \
|
||||
"WHERE c.relname=%s " \
|
||||
"AND c.oid=a.attrelid " \
|
||||
|
@ -4823,56 +4832,45 @@ class BaseModel(object):
|
|||
else:
|
||||
raise IndexError( _("Record #%d of %s not found, cannot copy!") %( id, self._name))
|
||||
|
||||
# TODO it seems fields_get can be replaced by _all_columns (no need for translation)
|
||||
fields = self.fields_get(cr, uid, context=context)
|
||||
for f in fields:
|
||||
ftype = fields[f]['type']
|
||||
|
||||
if self._log_access and f in LOG_ACCESS_COLUMNS:
|
||||
del data[f]
|
||||
# build a black list of fields that should not be copied
|
||||
blacklist = set(MAGIC_COLUMNS + ['parent_left', 'parent_right'])
|
||||
def blacklist_given_fields(obj):
|
||||
# blacklist the fields that are given by inheritance
|
||||
for other, field_to_other in obj._inherits.items():
|
||||
blacklist.add(field_to_other)
|
||||
if field_to_other in default:
|
||||
# all the fields of 'other' are given by the record: default[field_to_other],
|
||||
# except the ones redefined in self
|
||||
blacklist.update(set(self.pool.get(other)._all_columns) - set(self._columns))
|
||||
else:
|
||||
blacklist_given_fields(self.pool.get(other))
|
||||
blacklist_given_fields(self)
|
||||
|
||||
res = dict(default)
|
||||
for f, colinfo in self._all_columns.items():
|
||||
field = colinfo.column
|
||||
if f in default:
|
||||
data[f] = default[f]
|
||||
elif 'function' in fields[f]:
|
||||
del data[f]
|
||||
elif ftype == 'many2one':
|
||||
try:
|
||||
data[f] = data[f] and data[f][0]
|
||||
except:
|
||||
pass
|
||||
elif ftype == 'one2many':
|
||||
res = []
|
||||
rel = self.pool.get(fields[f]['relation'])
|
||||
if data[f]:
|
||||
# duplicate following the order of the ids
|
||||
# because we'll rely on it later for copying
|
||||
# translations in copy_translation()!
|
||||
data[f].sort()
|
||||
for rel_id in data[f]:
|
||||
# the lines are first duplicated using the wrong (old)
|
||||
# parent but then are reassigned to the correct one thanks
|
||||
# to the (0, 0, ...)
|
||||
d = rel.copy_data(cr, uid, rel_id, context=context)
|
||||
if d:
|
||||
res.append((0, 0, d))
|
||||
data[f] = res
|
||||
elif ftype == 'many2many':
|
||||
data[f] = [(6, 0, data[f])]
|
||||
elif f in blacklist:
|
||||
pass
|
||||
elif isinstance(field, fields.function):
|
||||
pass
|
||||
elif field._type == 'many2one':
|
||||
res[f] = data[f] and data[f][0]
|
||||
elif field._type == 'one2many':
|
||||
other = self.pool.get(field._obj)
|
||||
# duplicate following the order of the ids because we'll rely on
|
||||
# it later for copying translations in copy_translation()!
|
||||
lines = [other.copy_data(cr, uid, line_id, context=context) for line_id in sorted(data[f])]
|
||||
# the lines are duplicated using the wrong (old) parent, but then
|
||||
# are reassigned to the correct one thanks to the (0, 0, ...)
|
||||
res[f] = [(0, 0, line) for line in lines if line]
|
||||
elif field._type == 'many2many':
|
||||
res[f] = [(6, 0, data[f])]
|
||||
else:
|
||||
res[f] = data[f]
|
||||
|
||||
del data['id']
|
||||
|
||||
# make sure we don't break the current parent_store structure and
|
||||
# force a clean recompute!
|
||||
for parent_column in ['parent_left', 'parent_right']:
|
||||
data.pop(parent_column, None)
|
||||
# Remove _inherits field's from data recursively, missing parents will
|
||||
# be created by create() (so that copy() copy everything).
|
||||
def remove_ids(inherits_dict):
|
||||
for parent_table in inherits_dict:
|
||||
del data[inherits_dict[parent_table]]
|
||||
remove_ids(self.pool.get(parent_table)._inherits)
|
||||
remove_ids(self._inherits)
|
||||
return data
|
||||
return res
|
||||
|
||||
def copy_translations(self, cr, uid, old_id, new_id, context=None):
|
||||
if context is None:
|
||||
|
|
|
@ -6,6 +6,85 @@ import common
|
|||
UID = common.ADMIN_USER_ID
|
||||
DB = common.DB
|
||||
|
||||
class TestInherits(common.TransactionCase):
|
||||
""" test the behavior of the orm for models that use _inherits;
|
||||
specifically: res.users, that inherits from res.partner
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestInherits, self).setUp()
|
||||
self.partner = self.registry('res.partner')
|
||||
self.user = self.registry('res.users')
|
||||
|
||||
def test_create(self):
|
||||
""" creating a user should automatically create a new partner """
|
||||
partners_before = self.partner.search(self.cr, UID, [])
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
|
||||
foo = self.user.browse(self.cr, UID, foo_id)
|
||||
|
||||
self.assertNotIn(foo.partner_id.id, partners_before)
|
||||
|
||||
def test_create_with_ancestor(self):
|
||||
""" creating a user with a specific 'partner_id' should not create a new partner """
|
||||
par_id = self.partner.create(self.cr, UID, {'name': 'Foo'})
|
||||
partners_before = self.partner.search(self.cr, UID, [])
|
||||
foo_id = self.user.create(self.cr, UID, {'partner_id': par_id, 'login': 'foo', 'password': 'foo'})
|
||||
partners_after = self.partner.search(self.cr, UID, [])
|
||||
|
||||
self.assertEqual(set(partners_before), set(partners_after))
|
||||
|
||||
foo = self.user.browse(self.cr, UID, foo_id)
|
||||
self.assertEqual(foo.name, 'Foo')
|
||||
self.assertEqual(foo.partner_id.id, par_id)
|
||||
|
||||
def test_read(self):
|
||||
""" inherited fields should be read without any indirection """
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
|
||||
foo_values, = self.user.read(self.cr, UID, [foo_id])
|
||||
partner_id = foo_values['partner_id'][0]
|
||||
partner_values, = self.partner.read(self.cr, UID, [partner_id])
|
||||
self.assertEqual(foo_values['name'], partner_values['name'])
|
||||
|
||||
foo = self.user.browse(self.cr, UID, foo_id)
|
||||
self.assertEqual(foo.name, foo.partner_id.name)
|
||||
|
||||
def test_copy(self):
|
||||
""" copying a user should automatically copy its partner, too """
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
|
||||
foo_before, = self.user.read(self.cr, UID, [foo_id])
|
||||
bar_id = self.user.copy(self.cr, UID, foo_id, {'login': 'bar', 'password': 'bar'})
|
||||
foo_after, = self.user.read(self.cr, UID, [foo_id])
|
||||
|
||||
self.assertEqual(foo_before, foo_after)
|
||||
|
||||
foo, bar = self.user.browse(self.cr, UID, [foo_id, bar_id])
|
||||
self.assertEqual(bar.login, 'bar')
|
||||
self.assertNotEqual(foo.id, bar.id)
|
||||
self.assertNotEqual(foo.partner_id.id, bar.partner_id.id)
|
||||
|
||||
def test_copy_with_ancestor(self):
|
||||
""" copying a user with 'parent_id' in defaults should not duplicate the partner """
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
|
||||
par_id = self.partner.create(self.cr, UID, {'name': 'Bar'})
|
||||
|
||||
foo_before, = self.user.read(self.cr, UID, [foo_id])
|
||||
partners_before = self.partner.search(self.cr, UID, [])
|
||||
bar_id = self.user.copy(self.cr, UID, foo_id, {'partner_id': par_id, 'login': 'bar'})
|
||||
foo_after, = self.user.read(self.cr, UID, [foo_id])
|
||||
partners_after = self.partner.search(self.cr, UID, [])
|
||||
|
||||
self.assertEqual(foo_before, foo_after)
|
||||
self.assertEqual(set(partners_before), set(partners_after))
|
||||
|
||||
foo, bar = self.user.browse(self.cr, UID, [foo_id, bar_id])
|
||||
self.assertNotEqual(foo.id, bar.id)
|
||||
self.assertEqual(bar.partner_id.id, par_id)
|
||||
self.assertEqual(bar.login, 'bar', "login is given from copy parameters")
|
||||
self.assertEqual(bar.password, foo.password, "password is given from original record")
|
||||
self.assertEqual(bar.name, 'Bar', "name is given from specific partner")
|
||||
|
||||
|
||||
|
||||
CREATE = lambda values: (0, False, values)
|
||||
UPDATE = lambda id, values: (1, id, values)
|
||||
DELETE = lambda id: (2, id, False)
|
||||
|
@ -19,6 +98,7 @@ def sorted_by_id(list_of_dicts):
|
|||
return sorted(list_of_dicts, key=lambda d: d.get('id'))
|
||||
|
||||
class TestO2MSerialization(common.TransactionCase):
|
||||
""" test the orm method 'write' on one2many fields """
|
||||
|
||||
def setUp(self):
|
||||
super(TestO2MSerialization, self).setUp()
|
||||
|
|
|
@ -313,13 +313,13 @@ class YamlInterpreter(object):
|
|||
#context = self.get_context(record, self.eval_context)
|
||||
#TOFIX: record.context like {'withoutemployee':True} should pass from self.eval_context. example: test_project.yml in project module
|
||||
context = record.context
|
||||
view_info = False
|
||||
if view_id:
|
||||
varg = view_id
|
||||
if view_id is True: varg = False
|
||||
view = model.fields_view_get(self.cr, SUPERUSER_ID, varg, 'form', context)
|
||||
view_id = etree.fromstring(view['arch'].encode('utf-8'))
|
||||
view_info = model.fields_view_get(self.cr, SUPERUSER_ID, varg, 'form', context)
|
||||
|
||||
record_dict = self._create_record(model, fields, view_id, default=default)
|
||||
record_dict = self._create_record(model, fields, view_info, default=default)
|
||||
_logger.debug("RECORD_DICT %s" % record_dict)
|
||||
id = self.pool.get('ir.model.data')._update(self.cr, SUPERUSER_ID, record.model, \
|
||||
self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode, context=context)
|
||||
|
@ -327,16 +327,18 @@ class YamlInterpreter(object):
|
|||
if config.get('import_partial'):
|
||||
self.cr.commit()
|
||||
|
||||
def _create_record(self, model, fields, view=False, parent={}, default=True):
|
||||
if view is not False:
|
||||
defaults = default and model._add_missing_default_values(self.cr, SUPERUSER_ID, {}, context=self.context) or {}
|
||||
fg = model.fields_get(self.cr, SUPERUSER_ID, context=self.context)
|
||||
else:
|
||||
defaults = {}
|
||||
fg = {}
|
||||
record_dict = {}
|
||||
fields = fields or {}
|
||||
|
||||
def _create_record(self, model, fields, view_info=False, parent={}, default=True):
|
||||
"""This function processes the !record tag in yalm files. It simulates the record creation through an xml
|
||||
view (either specified on the !record tag or the default one for this object), including the calls to
|
||||
on_change() functions.
|
||||
:param model: model instance
|
||||
:param fields: dictonary mapping the field names and their values
|
||||
:param view_info: result of fields_view_get() called on the object
|
||||
:param parent: dictionary containing the values already computed for the parent, in case of one2many fields
|
||||
:param default: if True, the default values must be processed too or not
|
||||
:return: dictionary mapping the field names and their values, ready to use when calling the create() function
|
||||
:rtype: dict
|
||||
"""
|
||||
def process_val(key, val):
|
||||
if fg[key]['type']=='many2one':
|
||||
if type(val) in (tuple,list):
|
||||
|
@ -348,30 +350,41 @@ class YamlInterpreter(object):
|
|||
val = map(lambda x: (0,0,x), val)
|
||||
return val
|
||||
|
||||
view = view_info and etree.fromstring(view_info['arch'].encode('utf-8')) or False
|
||||
fields = fields or {}
|
||||
if view is not False:
|
||||
fg = view_info['fields']
|
||||
# gather the default values on the object. (Can't use `fields´ as parameter instead of {} because we may
|
||||
# have references like `base.main_company´ in the yaml file and it's not compatible with the function)
|
||||
defaults = default and model._add_missing_default_values(self.cr, SUPERUSER_ID, {}, context=self.context) or {}
|
||||
|
||||
# copy the default values in record_dict, only if they are in the view (because that's what the client does)
|
||||
# the other default values will be added later on by the create().
|
||||
record_dict = dict([(key, val) for key, val in defaults.items() if key in fg])
|
||||
|
||||
# Process all on_change calls
|
||||
nodes = (view is not False) and [view] or []
|
||||
nodes = [view]
|
||||
while nodes:
|
||||
el = nodes.pop(0)
|
||||
if el.tag=='field':
|
||||
field_name = el.attrib['name']
|
||||
assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name)
|
||||
if field_name in fields:
|
||||
view2 = None
|
||||
# if the form view is not inline, we call fields_view_get
|
||||
one2many_form_view = None
|
||||
if (view is not False) and (fg[field_name]['type']=='one2many'):
|
||||
view2 = view.find("field[@name='%s']/form"%(field_name,))
|
||||
if not view2:
|
||||
view2 = self.pool.get(fg[field_name]['relation']).fields_view_get(self.cr, SUPERUSER_ID, False, 'form', self.context)
|
||||
view2 = etree.fromstring(view2['arch'].encode('utf-8'))
|
||||
# for one2many fields, we want to eval them using the inline form view defined on the parent
|
||||
one2many_form_view = view_info['fields'][field_name]['views'].get('form')
|
||||
# if the form view is not defined inline, we call fields_view_get()
|
||||
if not one2many_form_view:
|
||||
one2many_form_view = self.pool.get(fg[field_name]['relation']).fields_view_get(self.cr, SUPERUSER_ID, False, 'form', self.context)
|
||||
|
||||
field_value = self._eval_field(model, field_name, fields[field_name], view2, parent=record_dict, default=default)
|
||||
field_value = self._eval_field(model, field_name, fields[field_name], one2many_form_view or view_info, parent=record_dict, default=default)
|
||||
record_dict[field_name] = field_value
|
||||
#if (field_name in defaults) and defaults[field_name] == field_value:
|
||||
# print '*** You can remove these lines:', field_name, field_value
|
||||
elif (field_name in defaults):
|
||||
if (field_name not in record_dict):
|
||||
record_dict[field_name] = process_val(field_name, defaults[field_name])
|
||||
else:
|
||||
|
||||
#if field_name has a default value or a value is given in the yaml file, we must call its on_change()
|
||||
elif field_name not in defaults:
|
||||
continue
|
||||
|
||||
if not el.attrib.get('on_change', False):
|
||||
|
@ -388,7 +401,7 @@ class YamlInterpreter(object):
|
|||
|
||||
ctx = record_dict.copy()
|
||||
ctx['context'] = self.context
|
||||
ctx['uid'] = 1
|
||||
ctx['uid'] = SUPERUSER_ID
|
||||
ctx['parent'] = parent2(parent)
|
||||
for a in fg:
|
||||
if a not in ctx:
|
||||
|
@ -398,13 +411,14 @@ class YamlInterpreter(object):
|
|||
args = map(lambda x: eval(x, ctx), match.group(2).split(','))
|
||||
result = getattr(model, match.group(1))(self.cr, SUPERUSER_ID, [], *args)
|
||||
for key, val in (result or {}).get('value', {}).items():
|
||||
if key not in fields:
|
||||
assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist on the object '%s'" % (key, match.group(1), model._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 in fields) and record_dict[key] == process_val(key, val):
|
||||
# print '*** You can remove these lines:', key, val
|
||||
else:
|
||||
nodes = list(el) + nodes
|
||||
else:
|
||||
record_dict = {}
|
||||
|
||||
for field_name, expression in fields.items():
|
||||
if field_name in record_dict:
|
||||
|
@ -440,7 +454,7 @@ class YamlInterpreter(object):
|
|||
def process_eval(self, node):
|
||||
return eval(node.expression, self.eval_context)
|
||||
|
||||
def _eval_field(self, model, field_name, expression, view=False, parent={}, default=True):
|
||||
def _eval_field(self, model, field_name, expression, view_info=False, parent={}, default=True):
|
||||
# TODO this should be refactored as something like model.get_field() in bin/osv
|
||||
if field_name in model._columns:
|
||||
column = model._columns[field_name]
|
||||
|
@ -461,7 +475,7 @@ class YamlInterpreter(object):
|
|||
value = self.get_id(expression)
|
||||
elif column._type == "one2many":
|
||||
other_model = self.get_model(column._obj)
|
||||
value = [(0, 0, self._create_record(other_model, fields, view, parent, default=default)) for fields in expression]
|
||||
value = [(0, 0, self._create_record(other_model, fields, view_info, parent, default=default)) for fields in expression]
|
||||
elif column._type == "many2many":
|
||||
ids = [self.get_id(xml_id) for xml_id in expression]
|
||||
value = [(6, 0, ids)]
|
||||
|
|
Loading…
Reference in New Issue