[MERGE] sync with trunk
bzr revid: odo@openerp.com-20110624102631-kiy8j2d1fc7heeco
This commit is contained in:
+273
-196
File diff suppressed because it is too large
Load Diff
@@ -588,7 +588,6 @@ class ir_model_data(osv.osv):
|
||||
def __init__(self, pool, cr):
|
||||
osv.osv.__init__(self, pool, cr)
|
||||
self.doinit = True
|
||||
self.unlink_mark = {}
|
||||
|
||||
# also stored in pool to avoid being discarded along with this osv instance
|
||||
if getattr(pool, 'model_data_reference_ids', None) is None:
|
||||
@@ -637,6 +636,14 @@ class ir_model_data(osv.osv):
|
||||
id = False
|
||||
return id
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
""" Regular unlink method, but make sure to clear the caches. """
|
||||
ref_ids = self.browse(cr, uid, ids, context=context)
|
||||
for ref_id in ref_ids:
|
||||
self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name)
|
||||
self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name)
|
||||
return super(ir_model_data,self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None):
|
||||
model_obj = self.pool.get(model)
|
||||
if not context:
|
||||
@@ -727,12 +734,6 @@ class ir_model_data(osv.osv):
|
||||
table.replace('.', '_'))] = (table, inherit_id)
|
||||
return res_id
|
||||
|
||||
def _unlink(self, cr, uid, model, res_ids):
|
||||
for res_id in res_ids:
|
||||
self.unlink_mark[(model, res_id)] = False
|
||||
cr.execute('delete from ir_model_data where res_id=%s and model=%s', (res_id, model))
|
||||
return True
|
||||
|
||||
def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
|
||||
if type(models[0])==type([]) or type(models[0])==type(()):
|
||||
model,res_id = models[0]
|
||||
@@ -760,15 +761,25 @@ class ir_model_data(osv.osv):
|
||||
return True
|
||||
|
||||
def _process_end(self, cr, uid, modules):
|
||||
""" Clear records removed from updated module data.
|
||||
|
||||
This method is called at the end of the module loading process.
|
||||
It is meant to removed records that are no longer present in the
|
||||
updated data. Such records are recognised as the one with an xml id
|
||||
and a module in ir_model_data and noupdate set to false, but not
|
||||
present in self.loads.
|
||||
|
||||
"""
|
||||
if not modules:
|
||||
return True
|
||||
modules = list(modules)
|
||||
module_in = ",".join(["%s"] * len(modules))
|
||||
cr.execute('select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ') and noupdate=%s', modules + [False])
|
||||
wkf_todo = []
|
||||
to_unlink = []
|
||||
for (id, name, model, res_id,module) in cr.fetchall():
|
||||
if (module,name) not in self.loads:
|
||||
self.unlink_mark[(model,res_id)] = id
|
||||
to_unlink.append((model,res_id))
|
||||
if model=='workflow.activity':
|
||||
cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
|
||||
wkf_todo.extend(cr.fetchall())
|
||||
@@ -781,36 +792,19 @@ class ir_model_data(osv.osv):
|
||||
|
||||
cr.commit()
|
||||
if not config.get('import_partial'):
|
||||
for (model, res_id) in self.unlink_mark.keys():
|
||||
for (model, res_id) in to_unlink:
|
||||
if self.pool.get(model):
|
||||
self.__logger.info('Deleting %s@%s', res_id, model)
|
||||
try:
|
||||
self.pool.get(model).unlink(cr, uid, [res_id])
|
||||
if id:
|
||||
ids = self.search(cr, uid, [('res_id','=',res_id),
|
||||
('model','=',model)])
|
||||
self.__logger.debug('=> Deleting %s: %s',
|
||||
self._name, ids)
|
||||
if len(ids) > 1 and \
|
||||
self.__logger.isEnabledFor(logging.WARNING):
|
||||
self.__logger.warn(
|
||||
'Got %d %s for (%s, %d): %s',
|
||||
len(ids), self._name, model, res_id,
|
||||
map(itemgetter('module','name'),
|
||||
self.read(cr, uid, ids,
|
||||
['name', 'module'])))
|
||||
self.unlink(cr, uid, ids)
|
||||
cr.execute(
|
||||
'DELETE FROM ir_values WHERE value=%s',
|
||||
('%s,%s'%(model, res_id),))
|
||||
cr.commit()
|
||||
except Exception:
|
||||
cr.rollback()
|
||||
self.__logger.warn(
|
||||
'Could not delete id: %d of model %s\nThere '
|
||||
'should be some relation that points to this '
|
||||
'resource\nYou should manually fix this and '
|
||||
'restart with --update=module', res_id, model)
|
||||
'Could not delete obsolete record with id: %d of model %s\n'
|
||||
'There should be some relation that points to this resource\n'
|
||||
'You should manually fix this and restart with --update=module',
|
||||
res_id, model)
|
||||
return True
|
||||
ir_model_data()
|
||||
|
||||
|
||||
@@ -197,10 +197,13 @@ class view_sc(osv.osv):
|
||||
|
||||
def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context=None):
|
||||
ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context)
|
||||
results = self.read(cr, uid, ids, ['res_id','name'], context=context)
|
||||
available_menus = self.pool.get(model).search(cr, uid, [], context=context)
|
||||
results = self.read(cr, uid, ids, ['res_id'], context=context)
|
||||
name_map = dict(self.pool.get(model).name_get(cr, uid, [x['res_id'] for x in results], context=context))
|
||||
# Make sure to return only shortcuts pointing to exisintg menu items.
|
||||
return filter(lambda result: result['res_id'] in available_menus, results)
|
||||
filtered_results = filter(lambda result: result['res_id'] in name_map, results)
|
||||
for result in filtered_results:
|
||||
result.update(name=name_map[result['res_id']])
|
||||
return filtered_results
|
||||
|
||||
_order = 'sequence,name'
|
||||
_defaults = {
|
||||
|
||||
@@ -56,6 +56,9 @@ class lang(osv.osv):
|
||||
default_value = ir_values_obj.get(cr, uid, 'default', False, ['res.partner'])
|
||||
if not default_value:
|
||||
ir_values_obj.set(cr, uid, 'default', False, 'lang', ['res.partner'], lang)
|
||||
default_value = ir_values_obj.get(cr, uid, 'default', False, ['res.users'])
|
||||
if not default_value:
|
||||
ir_values_obj.set(cr, uid, 'default', False, 'context_lang', ['res.users'], lang)
|
||||
return True
|
||||
|
||||
def load_lang(self, cr, uid, lang, lang_name=None):
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
-
|
||||
Testing for hierarchical search in M2M
|
||||
-
|
||||
!python {model: res.partner }: |
|
||||
ids = self.search(cr, uid, [('category_id', 'child_of','supplier')])
|
||||
assert len(ids) >= 1, ids
|
||||
|
||||
-
|
||||
Test hierarchical search in M2M with child ID1
|
||||
-
|
||||
!python {model: res.partner }: |
|
||||
ids = self.search(cr, uid, [('category_id', 'child_of','Components Supplier')])
|
||||
assert len(ids) >= 1, ids
|
||||
-
|
||||
Test hierarchical search in M2M with child ID2
|
||||
-
|
||||
!python {model: res.partner }: |
|
||||
ids = self.search(cr, uid, [('category_id', 'child_of','Miscellaneous Suppliers')])
|
||||
assert len(ids) >= 1, ids
|
||||
|
||||
-
|
||||
"1.0 Setup test partner categories: parent root"
|
||||
-
|
||||
!record {model: res.partner.category, id: categ_root}:
|
||||
name: Root category
|
||||
-
|
||||
"1.1 Setup test partner categories: parent category"
|
||||
-
|
||||
!record {model: res.partner.category, id: categ_0}:
|
||||
name: Parent category
|
||||
parent_id: categ_root
|
||||
-
|
||||
"1.2 Setup test partner categories: child 1"
|
||||
-
|
||||
!record {model: res.partner.category, id: categ_1}:
|
||||
name: Child 1
|
||||
parent_id: categ_0
|
||||
-
|
||||
Test hierarchical search in M2M with child ID (list of ids)
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_root')])])
|
||||
assert len(ids) == 3, ids
|
||||
-
|
||||
Test hierarchical search in M2M with child ID (single id)
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'child_of',ref('categ_root'))])
|
||||
assert len(ids) == 3, ids
|
||||
-
|
||||
Test hierarchical search in M2M with child IDs
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1'), ref('categ_0')])])
|
||||
assert len(ids) == 2, ids
|
||||
-
|
||||
Test hierarchical search in M2M with child IDs
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_0')])])
|
||||
assert len(ids) == 1, ids
|
||||
-
|
||||
Testing that some domain expressions work
|
||||
-
|
||||
@@ -40,7 +101,7 @@
|
||||
-
|
||||
!assert {model: res.partner, search: "[('category_id', '=', False)]"}:
|
||||
- category_id in (False, None, [])
|
||||
-
|
||||
-
|
||||
Filtering on invalid value across x2many relationship should return an empty set
|
||||
-
|
||||
!assert {model: res.partner, search: "[('address.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"}
|
||||
|
||||
+1
-2
@@ -24,7 +24,6 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import cgitb
|
||||
import errno
|
||||
import heapq
|
||||
import logging
|
||||
@@ -440,7 +439,7 @@ class OpenERPDispatcher:
|
||||
except Exception, e:
|
||||
self.log('exception', tools.exception_to_unicode(e))
|
||||
tb = getattr(e, 'traceback', sys.exc_info())
|
||||
tb_s = cgitb.text(tb)
|
||||
tb_s = "".join(traceback.format_exception(*tb))
|
||||
if tools.config['debug_mode'] and isinstance(tb, types.TracebackType):
|
||||
import pdb
|
||||
pdb.post_mortem(tb[2])
|
||||
|
||||
+23
-21
@@ -173,6 +173,20 @@ class expression(object):
|
||||
return ids + rg(ids2, table, parent)
|
||||
return [(left, 'in', rg(ids, table, parent or table._parent_name))]
|
||||
|
||||
def child_of_right_to_ids(value):
|
||||
""" Normalize a single id, or a string, or a list of ids to a list of ids.
|
||||
|
||||
This function is always used with _rec_get() above, so it should be
|
||||
called directly from _rec_get instead of repeatedly before _rec_get.
|
||||
|
||||
"""
|
||||
if isinstance(value, basestring):
|
||||
return [x[0] for x in field_obj.name_search(cr, uid, value, [], 'ilike', context=context, limit=None)]
|
||||
elif isinstance(value, (int, long)):
|
||||
return [value]
|
||||
else:
|
||||
return list(value)
|
||||
|
||||
self.__main_table = table
|
||||
self.__all_tables.add(table)
|
||||
|
||||
@@ -203,7 +217,8 @@ class expression(object):
|
||||
field = working_table._columns.get(fargs[0], False)
|
||||
if not field:
|
||||
if left == 'id' and operator == 'child_of':
|
||||
dom = _rec_get(right, working_table)
|
||||
ids2 = child_of_right_to_ids(right)
|
||||
dom = _rec_get(ids2, working_table)
|
||||
self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
|
||||
continue
|
||||
|
||||
@@ -249,10 +264,7 @@ class expression(object):
|
||||
elif field._type == 'one2many':
|
||||
# Applying recursivity on field(one2many)
|
||||
if operator == 'child_of':
|
||||
if isinstance(right, basestring):
|
||||
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], 'like', context=context, limit=None)]
|
||||
else:
|
||||
ids2 = list(right)
|
||||
ids2 = child_of_right_to_ids(right)
|
||||
if field._obj != working_table._name:
|
||||
dom = _rec_get(ids2, field_obj, left=left, prefix=field._obj)
|
||||
else:
|
||||
@@ -296,16 +308,12 @@ class expression(object):
|
||||
elif field._type == 'many2many':
|
||||
#FIXME
|
||||
if operator == 'child_of':
|
||||
if isinstance(right, basestring):
|
||||
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], 'like', context=context, limit=None)]
|
||||
else:
|
||||
ids2 = list(right)
|
||||
|
||||
def _rec_convert(ids):
|
||||
if field_obj == table:
|
||||
return ids
|
||||
return self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, ids, operator, field._type)
|
||||
|
||||
ids2 = child_of_right_to_ids(right)
|
||||
dom = _rec_get(ids2, field_obj)
|
||||
ids2 = field_obj.search(cr, uid, dom, context=context)
|
||||
self.__exp[i] = ('id', 'in', _rec_convert(ids2))
|
||||
@@ -344,13 +352,7 @@ class expression(object):
|
||||
|
||||
elif field._type == 'many2one':
|
||||
if operator == 'child_of':
|
||||
if isinstance(right, basestring):
|
||||
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], 'like', limit=None)]
|
||||
elif isinstance(right, (int, long)):
|
||||
ids2 = list([right])
|
||||
else:
|
||||
ids2 = list(right)
|
||||
|
||||
ids2 = child_of_right_to_ids(right)
|
||||
self.__operator = 'in'
|
||||
if field._obj != working_table._name:
|
||||
dom = _rec_get(ids2, field_obj, left=left, prefix=field._obj)
|
||||
@@ -360,12 +362,12 @@ class expression(object):
|
||||
else:
|
||||
def _get_expression(field_obj,cr, uid, left, right, operator, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
context = {}
|
||||
c = context.copy()
|
||||
c['active_test'] = False
|
||||
#Special treatment to ill-formed domains
|
||||
operator = ( operator in ['<','>','<=','>='] ) and 'in' or operator
|
||||
|
||||
|
||||
dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in','<>':'not in'}
|
||||
if isinstance(right,tuple):
|
||||
right = list(right)
|
||||
@@ -387,7 +389,7 @@ class expression(object):
|
||||
elif isinstance(right,(list,tuple)):
|
||||
m2o_str = True
|
||||
for ele in right:
|
||||
if not isinstance(ele, basestring):
|
||||
if not isinstance(ele, basestring):
|
||||
m2o_str = False
|
||||
break
|
||||
elif right == []:
|
||||
@@ -403,7 +405,7 @@ class expression(object):
|
||||
new_op = '!='
|
||||
#Is it ok to put 'left' and not 'id' ?
|
||||
self.__exp[i] = (left,new_op,False)
|
||||
|
||||
|
||||
if m2o_str:
|
||||
self.__exp[i] = _get_expression(field_obj,cr, uid, left, right, operator, context=context)
|
||||
else:
|
||||
|
||||
+3
-2
@@ -3514,9 +3514,10 @@ class orm(orm_template):
|
||||
# Removing the ir_model_data reference if the record being deleted is a record created by xml/csv file,
|
||||
# as these are not connected with real database foreign keys, and would be dangling references.
|
||||
# Step 1. Calling unlink of ir_model_data only for the affected IDS.
|
||||
referenced_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context)
|
||||
reference_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context)
|
||||
# Step 2. Marching towards the real deletion of referenced records
|
||||
pool_model_data.unlink(cr, uid, referenced_ids, context=context)
|
||||
if reference_ids:
|
||||
pool_model_data.unlink(cr, uid, reference_ids, context=context)
|
||||
|
||||
# For the same reason, removing the record relevant to ir_values
|
||||
ir_value_ids = ir_values_obj.search(cr, uid,
|
||||
|
||||
@@ -301,14 +301,12 @@ form: module.record_id""" % (xml_id,)
|
||||
pass
|
||||
if ids:
|
||||
self.pool.get(d_model).unlink(cr, self.uid, ids)
|
||||
self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids)
|
||||
|
||||
def _remove_ir_values(self, cr, name, value, model):
|
||||
ir_values_obj = self.pool.get('ir.values')
|
||||
ir_value_ids = ir_values_obj.search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)])
|
||||
if ir_value_ids:
|
||||
ir_values_obj.unlink(cr, self.uid, ir_value_ids)
|
||||
self.pool.get('ir.model.data')._unlink(cr, self.uid, 'ir.values', ir_value_ids)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -643,7 +643,6 @@ class YamlInterpreter(object):
|
||||
ids = [self.get_id(node.id)]
|
||||
if len(ids):
|
||||
self.pool.get(node.model).unlink(self.cr, self.uid, ids)
|
||||
self.pool.get('ir.model.data')._unlink(self.cr, 1, node.model, ids)
|
||||
else:
|
||||
self.logger.log(logging.TEST, "Record not deleted.")
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ if os.name == 'nt':
|
||||
"pydot", "asyncore","asynchat", "reportlab", "vobject",
|
||||
"HTMLParser", "select", "mako", "poplib",
|
||||
"imaplib", "smtplib", "email", "yaml", "DAV",
|
||||
"uuid", "commands", "openerp", # TODO is it necessary to include cgitb?
|
||||
"uuid", "commands", "openerp",
|
||||
],
|
||||
"excludes" : ["Tkconstants","Tkinter","tcl"],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user