[MERGE] trunk
bzr revid: al@openerp.com-20130625162755-d6552p98m5jiw941
This commit is contained in:
commit
f4332b9b60
|
@ -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"),
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ``\``)
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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).
|
||||
|
|
Loading…
Reference in New Issue