[MERGE] trunk

bzr revid: al@openerp.com-20130625162755-d6552p98m5jiw941
This commit is contained in:
Antony Lesuisse 2013-06-25 18:27:55 +02:00
commit f4332b9b60
10 changed files with 112 additions and 46 deletions

View File

@ -843,7 +843,6 @@ A property is a special field: fields.property.
relation='product.pricelist',
string="Sale Pricelist",
method=True,
view_load=True,
group_name="Pricelists Properties"),
}

View File

@ -21,3 +21,5 @@ Changelog
``openerp.exceptions.RedirectWarning``.
- Give a pair of new methods to ``res.config.settings`` and a helper to make
them easier to use: ``get_config_warning()``.
- Path to webkit report files (field ``report_file``) must be writen with the
Unix way (with ``/`` and not ``\``)

View File

@ -42,7 +42,6 @@ CREATE TABLE ir_model_fields (
field_description varchar(256),
ttype varchar(64),
state varchar(64) default 'base',
view_load boolean,
relate boolean default False,
relation_field varchar(128),
translate boolean default False,

View File

@ -245,7 +245,6 @@ class ir_model_fields(osv.osv):
"specified as a Python expression defining a list of triplets. "
"For example: [('color','=','red')]"),
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
'view_load': fields.boolean('View Auto-Load'),
'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'),
'serialization_field_id': fields.many2one('ir.model.fields', 'Serialization Field', domain = "[('ttype','=','serialized')]",
@ -256,7 +255,6 @@ class ir_model_fields(osv.osv):
}
_rec_name='field_description'
_defaults = {
'view_load': 0,
'selection': "",
'domain': "[]",
'name': 'x_',
@ -386,7 +384,6 @@ class ir_model_fields(osv.osv):
('size', 'size', int),
('on_delete', 'ondelete', str),
('translate', 'translate', bool),
('view_load', 'view_load', bool),
('selectable', 'selectable', bool),
('select_level', 'select', int),
('selection', 'selection', eval),

View File

@ -22,7 +22,7 @@
import time
from openerp.osv import osv, fields
from openerp.osv.orm import browse_record
from openerp.osv.orm import browse_record, browse_null
from openerp.tools.misc import attrgetter
# -------------------------------------------------------------------------
@ -32,27 +32,10 @@ from openerp.tools.misc import attrgetter
class ir_property(osv.osv):
_name = 'ir.property'
def _models_field_get(self, cr, uid, field_key, field_value, context=None):
get = attrgetter(field_key, field_value)
obj = self.pool.get('ir.model.fields')
ids = obj.search(cr, uid, [('view_load','=',1)], context=context)
res = set()
for o in obj.browse(cr, uid, ids, context=context):
res.add(get(o))
return list(res)
def _models_get(self, cr, uid, context=None):
return self._models_field_get(cr, uid, 'model', 'model_id.name', context)
def _models_get2(self, cr, uid, context=None):
return self._models_field_get(cr, uid, 'relation', 'relation', context)
_columns = {
'name': fields.char('Name', size=128, select=1),
'res_id': fields.reference('Resource', selection=_models_get, size=128,
help="If not set, acts as a default value for new resources", select=1),
'res_id': fields.char('Resource', size=128, help="If not set, acts as a default value for new resources", select=1),
'company_id': fields.many2one('res.company', 'Company', select=1),
'fields_id': fields.many2one('ir.model.fields', 'Field', ondelete='cascade', required=True, select=1),
@ -60,7 +43,7 @@ class ir_property(osv.osv):
'value_integer' : fields.integer('Value'),
'value_text' : fields.text('Value'), # will contain (char, text)
'value_binary' : fields.binary('Value'),
'value_reference': fields.reference('Value', selection=_models_get2, size=128),
'value_reference': fields.char('Value', size=128),
'value_datetime' : fields.datetime('Value'),
'type' : fields.selection([('char', 'Char'),
@ -72,6 +55,7 @@ class ir_property(osv.osv):
('many2one', 'Many2One'),
('date', 'Date'),
('datetime', 'DateTime'),
('selection', 'Selection'),
],
'Type',
required=True,
@ -106,6 +90,7 @@ class ir_property(osv.osv):
'many2one': 'value_reference',
'date' : 'value_datetime',
'datetime' : 'value_datetime',
'selection': 'value_text',
}
field = type2field.get(type_)
if not field:
@ -128,7 +113,6 @@ class ir_property(osv.osv):
values[field] = value
return values
def write(self, cr, uid, ids, values, context=None):
return super(ir_property, self).write(cr, uid, ids, self._update_values(cr, uid, ids, values), context=context)
@ -136,7 +120,7 @@ class ir_property(osv.osv):
return super(ir_property, self).create(cr, uid, self._update_values(cr, uid, None, values), context=context)
def get_by_record(self, cr, uid, record, context=None):
if record.type in ('char', 'text'):
if record.type in ('char', 'text', 'selection'):
return record.value_text
elif record.type == 'float':
return record.value_float
@ -147,7 +131,10 @@ class ir_property(osv.osv):
elif record.type == 'binary':
return record.value_binary
elif record.type == 'many2one':
return record.value_reference
if not record.value_reference:
return browse_null()
model, resource_id = record.value_reference.split(',')
return self.pool.get(model).browse(cr, uid, int(resource_id), context=context)
elif record.type == 'datetime':
return record.value_datetime
elif record.type == 'date':
@ -160,7 +147,8 @@ class ir_property(osv.osv):
domain = self._get_domain(cr, uid, name, model, context=context)
if domain is not None:
domain = [('res_id', '=', res_id)] + domain
nid = self.search(cr, uid, domain, context=context)
#make the search with company_id asc to make sure that properties specific to a company are given first
nid = self.search(cr, uid, domain, limit=1, order='company_id asc', context=context)
if not nid: return False
record = self.browse(cr, uid, nid[0], context=context)
return self.get_by_record(cr, uid, record, context=context)

View File

@ -160,16 +160,16 @@
</page>
<page string="Preferences">
<group>
<group name="preferences">
<group string="Localization" name="preferences">
<field name="lang"/>
<field name="tz"/>
</group>
<group groups="base.group_no_one">
<group string="Menus Customization" groups="base.group_no_one">
<field name="action_id"/>
<field domain="[('usage','=','menu')]" name="menu_id" required="True"/>
</group>
</group>
<group string="Email preferences">
<group string="Messaging and Social" name="messaging">
<field name="signature"/>
</group>
</page>

View File

@ -109,7 +109,6 @@ class _column(object):
self._context = context
self.write = False
self.read = False
self.view_load = 0
self.select = select
self.manual = manual
self.selectable = True
@ -1383,8 +1382,10 @@ class property(function):
def _get_by_id(self, obj, cr, uid, prop_name, ids, context=None):
prop = obj.pool.get('ir.property')
vids = [obj._name + ',' + str(oid) for oid in ids]
domain = [('fields_id.model', '=', obj._name), ('fields_id.name', 'in', prop_name)]
def_id = self._field_get(cr, uid, obj._name, prop_name[0])
company = obj.pool.get('res.company')
cid = company._company_default_get(cr, uid, obj._name, def_id, context=context)
domain = [('fields_id.model', '=', obj._name), ('fields_id.name', 'in', prop_name), ('company_id', '=', cid)]
#domain = prop._get_domain(cr, uid, prop_name, obj._name, context)
if vids:
domain = [('res_id', 'in', vids)] + domain
@ -1477,11 +1478,13 @@ class property(function):
self.field_id[cr.dbname] = res and res[0]
return self.field_id[cr.dbname]
def __init__(self, obj_prop, **args):
# TODO remove obj_prop parameter (use many2one type)
def __init__(self, **args):
self.field_id = {}
function.__init__(self, self._fnct_read, False, self._fnct_write,
obj_prop, multi='properties', **args)
if 'view_load' in args:
_logger.warning("view_load attribute is deprecated on ir.fields. Args: %r", args)
obj = 'relation' in args and args['relation'] or ''
function.__init__(self, self._fnct_read, False, self._fnct_write, obj=obj, multi='properties', **args)
def restart(self):
self.field_id = {}

View File

@ -794,7 +794,6 @@ class BaseModel(object):
'field_description': f.string,
'ttype': f._type,
'relation': f._obj or '',
'view_load': (f.view_load and 1) or 0,
'select_level': tools.ustr(f.select or 0),
'readonly': (f.readonly and 1) or 0,
'required': (f.required and 1) or 0,
@ -824,12 +823,12 @@ class BaseModel(object):
vals['id'] = id
cr.execute("""INSERT INTO ir_model_fields (
id, model_id, model, name, field_description, ttype,
relation,view_load,state,select_level,relation_field, translate, serialization_field_id
relation,state,select_level,relation_field, translate, serialization_field_id
) VALUES (
%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s
%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s
)""", (
id, vals['model_id'], vals['model'], vals['name'], vals['field_description'], vals['ttype'],
vals['relation'], bool(vals['view_load']), 'base',
vals['relation'], 'base',
vals['select_level'], vals['relation_field'], bool(vals['translate']), vals['serialization_field_id']
))
if 'module' in context:
@ -847,11 +846,11 @@ class BaseModel(object):
cr.commit()
cr.execute("""UPDATE ir_model_fields SET
model_id=%s, field_description=%s, ttype=%s, relation=%s,
view_load=%s, select_level=%s, readonly=%s ,required=%s, selectable=%s, relation_field=%s, translate=%s, serialization_field_id=%s
select_level=%s, readonly=%s ,required=%s, selectable=%s, relation_field=%s, translate=%s, serialization_field_id=%s
WHERE
model=%s AND name=%s""", (
vals['model_id'], vals['field_description'], vals['ttype'],
vals['relation'], bool(vals['view_load']),
vals['relation'],
vals['select_level'], bool(vals['readonly']), bool(vals['required']), bool(vals['selectable']), vals['relation_field'], bool(vals['translate']), vals['serialization_field_id'], vals['model'], vals['name']
))
break
@ -4880,6 +4879,34 @@ class BaseModel(object):
# for backward compatibility
resolve_o2m_commands_to_record_dicts = resolve_2many_commands
def search_read(self, cr, uid, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
"""
Performs a ``search()`` followed by a ``read()``.
:param cr: database cursor
:param user: current user id
:param domain: Search domain, see ``args`` parameter in ``search()``. Defaults to an empty domain that will match all records.
:param fields: List of fields to read, see ``fields`` parameter in ``read()``. Defaults to all fields.
:param offset: Number of records to skip, see ``offset`` parameter in ``search()``. Defaults to 0.
:param limit: Maximum number of records to return, see ``limit`` parameter in ``search()``. Defaults to no limit.
:param order: Columns to sort result, see ``order`` parameter in ``search()``. Defaults to no sort.
:param context: context arguments.
:return: List of dictionaries containing the asked fields.
:rtype: List of dictionaries.
"""
record_ids = self.search(cr, uid, domain or [], offset, limit or False, order or False, context or {})
if not record_ids:
return []
result = self.read(cr, uid, record_ids, fields or [], context or {})
# reorder read
if len(result) >= 1:
index = {}
for r in result:
index[r['id']] = r
result = [index[x] for x in record_ids if x in index]
return result
def _register_hook(self, cr):
""" stuff to do right after the registry is built """
pass

View File

@ -76,6 +76,30 @@ class TestORM(common.TransactionCase):
with self.assertRaises(Exception):
self.partner.unlink(cr, uid2, [p1,p2])
@mute_logger('openerp.osv.orm')
def test_search_read(self):
# simple search_read
self.partner.create(self.cr, UID, {'name': 'MyPartner1'})
found = self.partner.search_read(self.cr, UID, [['name', '=', 'MyPartner1']], ['name'])
self.assertEqual(len(found), 1)
self.assertEqual(found[0]['name'], 'MyPartner1')
self.assertTrue('id' in found[0])
# search_read correct order
self.partner.create(self.cr, UID, {'name': 'MyPartner2'})
found = self.partner.search_read(self.cr, UID, [['name', 'like', 'MyPartner']], ['name'], order="name")
self.assertEqual(len(found), 2)
self.assertEqual(found[0]['name'], 'MyPartner1')
self.assertEqual(found[1]['name'], 'MyPartner2')
found = self.partner.search_read(self.cr, UID, [['name', 'like', 'MyPartner']], ['name'], order="name desc")
self.assertEqual(len(found), 2)
self.assertEqual(found[0]['name'], 'MyPartner2')
self.assertEqual(found[1]['name'], 'MyPartner1')
# search_read that finds nothing
found = self.partner.search_read(self.cr, UID, [['name', '=', 'Does not exists']], ['name'])
self.assertEqual(len(found), 0)
class TestInherits(common.TransactionCase):
""" test the behavior of the orm for models that use _inherits;

View File

@ -1,8 +1,11 @@
"""
Install OpenERP on a new (by default) database.
"""
import contextlib
import errno
import os
import sys
import time
import common
@ -11,7 +14,8 @@ def install_openerp(database_name, create_database_flag, module_names, install_d
config = openerp.tools.config
if create_database_flag:
create_database(database_name)
with lock_file('/tmp/global_openerp_create_database.lock'):
create_database(database_name)
config['init'] = dict.fromkeys(module_names, 1)
@ -23,6 +27,29 @@ def install_openerp(database_name, create_database_flag, module_names, install_d
return registry
# From http://code.activestate.com/recipes/576572/
@contextlib.contextmanager
def lock_file(path, wait_delay=.1, max_try=600):
attempt = 0
while True:
attempt += 1
if attempt > max_try:
raise IOError("Could not lock file %s." % path)
try:
fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
except OSError, e:
if e.errno != errno.EEXIST:
raise
time.sleep(wait_delay)
continue
else:
break
try:
yield fd
finally:
os.close(fd)
os.unlink(path)
# TODO turn template1 in a parameter
# This should be exposed from openerp (currently in
# openerp/service/web_services.py).