From 6f53850e7d95daf5cf33a38473d730a863690800 Mon Sep 17 00:00:00 2001 From: Quality Team <> Date: Tue, 4 May 2010 16:46:42 +0200 Subject: [PATCH] [FIX] Rewrite the field.property engine to work as expected (value per company) bzr revid: stephane@openerp.com-20100504144642-piruhn25d8qyxiof --- bin/addons/base/res/ir_property.py | 43 ++++++----- bin/addons/base/res/res_company.py | 6 +- bin/osv/fields.py | 139 +++++++++++++++++++----------------- bin/osv/orm.py | 34 ++++++--- 4 files changed, 125 insertions(+), 97 deletions(-) diff --git a/bin/addons/base/res/ir_property.py b/bin/addons/base/res/ir_property.py index b02ba59..c7673bf 100644 --- a/bin/addons/base/res/ir_property.py +++ b/bin/addons/base/res/ir_property.py @@ -20,36 +20,41 @@ ############################################################################## from osv import osv,fields - +from operator import attrgetter # ------------------------------------------------------------------------- # Properties # ------------------------------------------------------------------------- -def _models_get(self, cr, uid, context={}): - obj = self.pool.get('ir.model.fields') - ids = obj.search(cr, uid, [('view_load','=',1)]) - res = [] - done = {} - for o in obj.browse(cr, uid, ids, context=context): - if o.model_id.id not in done: - res.append( [o.model_id.model, o.model_id.name]) - done[o.model_id.id] = True - return res - 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 res + + def _models_get(self, cr, uid, context=None): + return self._models_field_get(cr, uid, 'model_id.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), - 'value': fields.char('Value', size=128), - 'res_id': fields.reference('Resource', selection=_models_get, size=128), + 'value': fields.reference('Value', selection=_models_get2, size=128), +# 'value': fields.char('Value', size=128), + 'res_id': fields.reference('Resource', selection=_models_get, size=128, + help="If not set, act as default property"), 'company_id': fields.many2one('res.company', 'Company'), 'fields_id': fields.many2one('ir.model.fields', 'Fields', ondelete='cascade', required=True) } - def unlink(self, cr, uid, ids, context={}): - if ids: - cr.execute('DELETE FROM ir_model_fields WHERE id IN (SELECT fields_id FROM ir_property WHERE (fields_id IS NOT NULL) AND (id = ANY (%s)))', (ids,)) - res = super(ir_property, self).unlink(cr, uid, ids, context) - return res def get(self, cr, uid, name, model, res_id=False, context={}): cr.execute('select id from ir_model_fields where name=%s and model=%s', (name, model)) diff --git a/bin/addons/base/res/res_company.py b/bin/addons/base/res/res_company.py index c3024d5..6a64d57 100644 --- a/bin/addons/base/res/res_company.py +++ b/bin/addons/base/res/res_company.py @@ -109,11 +109,9 @@ class res_company(osv.osv): proxy = self.pool.get('multi_company.default') args = [ ('object_id.model', '=', object), + ('field_id', '=', field), ] - if field: - args.append(('field_id.name','=',field)) - else: - args.append(('field_id','=',False)) + ids = proxy.search(cr, uid, args, context=context) for rule in proxy.browse(cr, uid, ids, context): user = self.pool.get('res.users').browse(cr, uid, uid) diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 71faa98..be1f5c2 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -873,87 +873,93 @@ class serialized(_column): class property(function): - def _fnct_write(self, obj, cr, uid, id, prop, id_val, val, context=None): - if not context: + def _get_domain(self, obj, cr, uid, prop_name, context=None): + def_id = self._field_get(cr, uid, obj._name, prop_name) + + company = obj.pool.get('res.company') + cid = company._company_default_get(cr, uid, obj._name, def_id, + context=context) + + domain = ['&', ('fields_id', '=', def_id), + '|', ('company_id', '=', cid), ('company_id', '=', False)] + return domain + + def _get_default(self, obj, cr, uid, prop_name, context=None): + prop = obj.pool.get('ir.property') + domain = self._get_domain(obj, cr, uid, prop_name, context) + ids = prop.search(cr, uid, domain, order='company_id', context=context) + if not ids: + return False + return prop.browse(cr, uid, ids[0], context).value + + 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 = [('res_id', 'in', vids)] + \ + self._get_domain(obj, cr, uid, prop_name, context) + + return prop.search(cr, uid, domain, context=context) + + def _fnct_write(self, obj, cr, uid, id, prop_name, id_val, obj_dest, context=None): + if context is None: context = {} - (obj_dest,) = val - definition_id = self._field_get(cr, uid, obj._name, prop) - property = obj.pool.get('ir.property') - nid = property.search(cr, uid, [('fields_id', '=', definition_id), - ('res_id', '=', obj._name+','+str(id))]) - while len(nid): - cr.execute('DELETE FROM ir_property WHERE id=%s', (nid.pop(),)) - - nid = property.search(cr, uid, [('fields_id', '=', definition_id), - ('res_id', '=', False)]) - default_val = False - if nid: - default_val = property.browse(cr, uid, nid[0], context).value - - company_id = obj.pool.get('res.company')._company_default_get(cr, uid, obj._name, prop, context=context) - res = False - if val[0]: - newval = (id_val and obj_dest+','+str(id_val)) or False - else: - newval = id_val or False - if (newval != default_val) and newval: - propdef = obj.pool.get('ir.model.fields').browse(cr, uid, - definition_id, context=context) - res = property.create(cr, uid, { + nids = self._get_by_id(obj, cr, uid, prop_name, [id], context) + if nids: + cr.execute('DELETE FROM ir_property WHERE id IN %s', (tuple(nids),)) + + default_val = self._get_default(obj, cr, uid, prop_name, context) + id_val = "%s,%d" % (obj_dest, id_val) + + if id_val and id_val != default_val: + def_id = self._field_get(cr, uid, obj._name, prop_name) + company = obj.pool.get('res.company') + cid = company._company_default_get(cr, uid, obj._name, def_id, + context=context) + propdef = obj.pool.get('ir.model.fields').browse(cr, uid, def_id, + context=context) + prop = obj.pool.get('ir.property') + return prop.create(cr, uid, { 'name': propdef.name, - 'value': newval, + 'value': id_val, 'res_id': obj._name+','+str(id), - 'company_id': company_id, - 'fields_id': definition_id - }, context=context) - return res + 'company_id': cid, + 'fields_id': def_id, + #'type': self._type, + }, context=context) + return False - def _fnct_read(self, obj, cr, uid, ids, prop, val, context=None): - if not context: + + def _fnct_read(self, obj, cr, uid, ids, prop_name, obj_dest, context=None): + from orm import browse_record + if context is None: context = {} + property = obj.pool.get('ir.property') - definition_id = self._field_get(cr, uid, obj._name, prop) - nid = property.search(cr, uid, [('fields_id', '=', definition_id), - ('res_id', '=', False)]) - default_val = False - if nid: - d = property.browse(cr, uid, nid[0], context).value - default_val = (d and int(d.split(',')[1])) or False + default_val = self._get_default(obj, cr, uid, prop_name, context) + if isinstance(default_val, browse_record): + default_val = default_val.id + else: + default_val = False - vids = [obj._name + ',' + str(id) for id in ids] - nids = property.search(cr, uid, [('fields_id', '=', definition_id), - ('res_id', 'in', vids)]) + nids = self._get_by_id(obj, cr, uid, prop_name, ids, context) res = {} for id in ids: res[id] = default_val for prop in property.browse(cr, uid, nids): - if prop.value.find(',') >= 0: - res[int(prop.res_id.id)] = (prop.value and \ - int(prop.value.split(',')[1])) or False - else: - res[int(prop.res_id.id)] = prop.value or '' - - if self._obj: - obj = obj.pool.get(self._obj) - to_check = res.values() - if default_val and default_val not in to_check: - to_check += [default_val] - existing_ids = obj.search(cr, uid, [('id', 'in', to_check)]) - for id, res_id in res.items(): - if res_id not in existing_ids: - cr.execute('DELETE FROM ir_property WHERE value=%s', ((obj._name+','+str(res_id)),)) - res[id] = default_val - names = dict(obj.name_get(cr, uid, existing_ids, context)) - for r in res.keys(): - if res[r] and res[r] in names: - res[r] = (res[r], names[res[r]]) - else: - res[r] = False + value = prop.value + if isinstance(value, browse_record): + if not value.exists(): + cr.execute('DELETE FROM ir_property WHERE id=%s', (prop.id,)) + continue + value = value.id + res[prop.res_id.id] = value or False return res + def _field_get(self, cr, uid, model_name, prop): if not self.field_id.get(cr.dbname): cr.execute('SELECT id \ @@ -964,9 +970,10 @@ class property(function): return self.field_id[cr.dbname] def __init__(self, obj_prop, **args): + #assert obj_prop self.field_id = {} function.__init__(self, self._fnct_read, False, self._fnct_write, - (obj_prop, ), **args) + obj_prop, **args) def restart(self): self.field_id = {} diff --git a/bin/osv/orm.py b/bin/osv/orm.py index c5019c7..161364a 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -170,6 +170,7 @@ class browse_record(object): def __getitem__(self, name): if name == 'id': return self._id + if name not in self._data[self._id]: # build the list of fields we will fetch @@ -179,10 +180,12 @@ class browse_record(object): elif name in self._table._inherit_fields: col = self._table._inherit_fields[name][2] elif hasattr(self._table, str(name)): - if isinstance(getattr(self._table, name), (types.MethodType, types.LambdaType, types.FunctionType)): - return lambda *args, **argv: getattr(self._table, name)(self._cr, self._uid, [self._id], *args, **argv) + attr = getattr(self._table, name) + + if isinstance(attr, (types.MethodType, types.LambdaType, types.FunctionType)): + return lambda *args, **argv: attr(self._cr, self._uid, [self._id], *args, **argv) else: - return getattr(self._table, name) + return attr else: self.logger.notifyChannel("browse_record", netsvc.LOG_WARNING, "Field '%s' does not exist in object '%s': \n%s" % ( @@ -250,6 +253,8 @@ class browse_record(object): context=self._context, list_class=self._list_class, fields_process=self._fields_process) + else: + new_data[n] = ids2 else: new_data[n] = browse_null() else: @@ -271,6 +276,7 @@ class browse_record(object): else: new_data[n] = data[n] self._data[data['id']].update(new_data) + if not name in self._data[self._id]: #how did this happen? self.logger.notifyChannel("browse_record", netsvc.LOG_ERROR, @@ -299,9 +305,13 @@ class browse_record(object): return "browse_record(%s, %d)" % (self._table_name, self._id) def __eq__(self, other): + if not isinstance(other, browse_record): + return False return (self._table_name, self._id) == (other._table_name, other._id) def __ne__(self, other): + if not isinstance(other, browse_record): + return True return (self._table_name, self._id) != (other._table_name, other._id) # we need to define __unicode__ even though we've already defined __str__ @@ -2583,8 +2593,13 @@ class orm(orm_template): if nid: prop_value = property_obj.browse(cr, uid, nid[0], context=context).value - value[f] = (prop_value and int(prop_value.split(',')[1])) \ - or False + if prop_value: + if isinstance(prop_value, (browse_record, browse_null)): + value[f] = prop_value.id + else: + value[f] = int(prop_value.rsplit(',', 1)[1]) + else: + value[f] = False # get the default values set by the user and override the default # values defined in the object @@ -3802,9 +3817,12 @@ class orm(orm_template): trans_obj.create(cr, uid, record, context) return new_id - def exists(self, cr, uid, id, context=None): - cr.execute('SELECT count(1) FROM "%s" where id=%%s' % (self._table,), (id,)) - return bool(cr.fetchone()[0]) + def exists(self, cr, uid, ids, context=None): + if type(ids) in (int,long): + ids = [ids] + query = 'SELECT count(1) FROM "%s"' % (self._table) + cr.execute(query + "WHERE ID IN %s", (tuple(ids),)) + return cr.fetchone()[0] == len(ids) def check_recursion(self, cr, uid, ids, parent=None): """ -- 1.7.10.4