diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 3e2b93a8ead..066cccc7441 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -296,7 +296,12 @@ instance.web.Session.include( /** @lends instance.web.Session# */{ for(var i=0; i) +# Copyright (C) 2004-2014 OpenERP SA () # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -89,7 +89,13 @@ class ColoredFormatter(DBFormatter): record.levelname = COLOR_PATTERN % (30 + fg_color, 40 + bg_color, record.levelname) return DBFormatter.format(self, record) +_logger_init = False def init_logger(): + global _logger_init + if _logger_init: + return + _logger_init = True + from tools.translate import resetlocale resetlocale() @@ -137,6 +143,8 @@ def init_logger(): formatter = DBFormatter(format) handler.setFormatter(formatter) + logging.getLogger().addHandler(handler) + # Configure handlers pseudo_config = PSEUDOCONFIG_MAPPER.get(tools.config['log_level'], []) @@ -147,11 +155,7 @@ def init_logger(): loggername, level = logconfig_item.split(':') level = getattr(logging, level, logging.INFO) logger = logging.getLogger(loggername) - logger.handlers = [] logger.setLevel(level) - logger.addHandler(handler) - if loggername != '': - logger.propagate = False for logconfig_item in logging_configurations: _logger.debug('logger level set: "%s"', logconfig_item) diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index 4475e8dd20c..882861c4c2c 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -1019,6 +1019,7 @@ class expression(object): push(create_substitution_leaf(leaf, (left, operator, right), working_model)) elif field.translate and right: + field = left need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike') sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator) if need_wildcard: @@ -1030,33 +1031,40 @@ class expression(object): sql_operator = sql_operator[4:] if sql_operator[:3] == 'not' else '=' inselect_operator = 'not inselect' - subselect = '( SELECT res_id' \ - ' FROM ir_translation' \ - ' WHERE name = %s' \ - ' AND lang = %s' \ - ' AND type = %s' - instr = ' %s' - #Covering in,not in operators with operands (%s,%s) ,etc. - if sql_operator == 'in': - instr = ','.join(['%s'] * len(right)) - subselect += ' AND value ' + sql_operator + ' ' + " (" + instr + ")" \ - ') UNION (' \ - ' SELECT id' \ - ' FROM "' + working_model._table + '"' \ - ' WHERE "' + left + '" ' + sql_operator + ' ' + " (" + instr + "))" - else: - subselect += ' AND value ' + sql_operator + instr + \ - ') UNION (' \ - ' SELECT id' \ - ' FROM "' + working_model._table + '"' \ - ' WHERE "' + left + '" ' + sql_operator + instr + ")" + trans_left = 'value' + left = '"%s"' % (left,) + instr = '%s' - params = [working_model._name + ',' + left, - context.get('lang', False) or 'en_US', - 'model', - right, - right, - ] + if self.has_unaccent and sql_operator.endswith('like'): + assert isinstance(right, basestring) + trans_left = 'unaccent(value)' + left = 'unaccent(%s)' % (left,) + instr = 'unaccent(%s)' + elif sql_operator == 'in': + # params will be flatten by to_sql() => expand the placeholders + instr = '(%s)' % ', '.join(['%s'] * len(right)) + + subselect = """(SELECT res_id + FROM ir_translation + WHERE name = %s + AND lang = %s + AND type = %s + AND {trans_left} {operator} {right} + ) UNION ( + SELECT id + FROM "{table}" + WHERE {left} {operator} {right} + ) + """.format(trans_left=trans_left, operator=sql_operator, + right=instr, table=working_model._table, left=left) + + params = ( + working_model._name + ',' + field, + context.get('lang') or 'en_US', + 'model', + right, + right, + ) push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model)) else: @@ -1175,7 +1183,7 @@ class expression(object): if left in model._columns: format = need_wildcard and '%s' or model._columns[left]._symbol_set[0] - if self.has_unaccent and sql_operator in ('ilike', 'not ilike'): + if self.has_unaccent and sql_operator.endswith('like'): query = '(unaccent(%s."%s") %s unaccent(%s))' % (table_alias, left, sql_operator, format) else: query = '(%s."%s" %s %s)' % (table_alias, left, sql_operator, format) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 400f2c439ea..b4151eb00b4 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -602,7 +602,10 @@ class one2many(_column): else: cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],)) elif act[0] == 4: - cr.execute("select 1 from {0} where id=%s and {1}=%s".format(_table, self._fields_id), (act[1], id)) + # table of the field (parent_model in case of inherit) + field_model = self._fields_id in obj.pool[self._obj]._columns and self._obj or obj.pool[self._obj]._all_columns[self._fields_id].parent_model + field_table = obj.pool[field_model]._table + cr.execute("select 1 from {0} where id=%s and {1}=%s".format(field_table, self._fields_id), (act[1], id)) if not cr.fetchone(): # Must use write() to recompute parent_store structure if needed and check access rules obj.write(cr, user, [act[1]], {self._fields_id:id}, context=context or {}) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 6489540fc78..cc160ff75ad 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -3256,7 +3256,7 @@ class BaseModel(object): msg = "Table '%s': dropping index for column '%s' of type '%s' as it is not required anymore" _schema.debug(msg, self._table, k, f._type) - if isinstance(f, fields.many2one): + if isinstance(f, fields.many2one) or (isinstance(f, fields.function) and f._type == 'many2one' and f.store): dest_model = self.pool[f._obj] if dest_model._table != 'ir_actions': self._m2o_fix_foreign_key(cr, self._table, k, dest_model, f.ondelete) @@ -3291,7 +3291,7 @@ class BaseModel(object): todo_end.append((order, self._update_store, (f, k))) # and add constraints if needed - if isinstance(f, fields.many2one): + if isinstance(f, fields.many2one) or (isinstance(f, fields.function) and f._type == 'many2one' and f.store): if f._obj not in self.pool: raise except_orm('Programming Error', 'There is no reference available for %s' % (f._obj,)) dest_model = self.pool[f._obj] diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index b075b0f53ea..91dfc9dd79b 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -85,50 +85,30 @@ def _open_image(filename, path=None): class NumberedCanvas(canvas.Canvas): def __init__(self, *args, **kwargs): canvas.Canvas.__init__(self, *args, **kwargs) - self._codes = [] - self._flag=False - self._pageCount=0 - self._currentPage =0 - self._pageCounter=0 - self.pages={} + self._saved_page_states = [] def showPage(self): - self._currentPage +=1 - if not self._flag: - self._pageCount += 1 - else: - self.pages.update({self._currentPage:self._pageCount}) - self._codes.append({'code': self._code, 'stack': self._codeStack}) + self._saved_page_states.append(dict(self.__dict__)) self._startPage() - self._flag=False - def pageCount(self): - if self.pages.get(self._pageCounter,False): - self._pageNumber=0 - self._pageCounter +=1 - key=self._pageCounter - if not self.pages.get(key,False): - while not self.pages.get(key,False): - key += 1 + def save(self): + """add page info to each page (page x of y)""" + for state in self._saved_page_states: + self.__dict__.update(state) + self.draw_page_number() + canvas.Canvas.showPage(self) + canvas.Canvas.save(self) + + def draw_page_number(self): + page_count = len(self._saved_page_states) self.setFont("Helvetica", 8) self.drawRightString((self._pagesize[0]-30), (self._pagesize[1]-40), " %(this)i / %(total)i" % { 'this': self._pageNumber+1, - 'total': self.pages.get(key,False), + 'total': page_count, } ) - def save(self): - """add page info to each page (page x of y)""" - # reset page counter - self._pageNumber = 0 - for code in self._codes: - self._code = code['code'] - self._codeStack = code['stack'] - self.pageCount() - canvas.Canvas.showPage(self) -# self.restoreState() - self._doc.SaveToFile(self._filename, self) class PageCount(platypus.Flowable): def __init__(self, story_count=0): diff --git a/openerp/tests/test_ir_sequence.py b/openerp/tests/test_ir_sequence.py index cbb1a347038..0b47560f3a4 100644 --- a/openerp/tests/test_ir_sequence.py +++ b/openerp/tests/test_ir_sequence.py @@ -8,6 +8,7 @@ # OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence # This assume an existing database. import psycopg2 +import psycopg2.errorcodes import unittest2 import openerp @@ -111,11 +112,11 @@ class test_ir_sequence_no_gap(unittest2.TestCase): cr0 = cursor() cr1 = cursor() cr1._default_log_exceptions = False # Prevent logging a traceback - msg_re = '^could not obtain lock on row in relation "ir_sequence"$' - with self.assertRaisesRegexp(psycopg2.OperationalError, msg_re): + with self.assertRaises(psycopg2.OperationalError) as e: n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {}) assert n0 n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {}) + self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode") cr0.close() cr1.close()