[MERGE] forward port of branch 7.0 up to revid 5270 chs@openerp.com-20140403084524-9rb174osjrbmhgwc
bzr revid: chs@openerp.com-20140402083506-w4cywcf0kxxx9xmk bzr revid: chs@openerp.com-20140312174526-a5rhh83g0fw8djuc bzr revid: chs@openerp.com-20140318105837-53vsx5g7fm517cuc bzr revid: dle@openerp.com-20140326092548-bu4bqinhvco8j5wj bzr revid: chs@openerp.com-20140402092735-3a23yjl169vvt0iv bzr revid: chs@openerp.com-20140402112825-ky8rcb3p467ikitc bzr revid: chs@openerp.com-20140403084808-slnj7uis17kwi9js
This commit is contained in:
commit
1c3ee251f0
|
@ -296,7 +296,12 @@ instance.web.Session.include( /** @lends instance.web.Session# */{
|
||||||
for(var i=0; i<cookies.length; ++i) {
|
for(var i=0; i<cookies.length; ++i) {
|
||||||
var cookie = cookies[i].replace(/^\s*/, '');
|
var cookie = cookies[i].replace(/^\s*/, '');
|
||||||
if(cookie.indexOf(nameEQ) === 0) {
|
if(cookie.indexOf(nameEQ) === 0) {
|
||||||
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
|
try {
|
||||||
|
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
|
||||||
|
} catch(err) {
|
||||||
|
// wrong cookie, delete it
|
||||||
|
this.set_cookie(name, '', -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -50,15 +50,21 @@ class change_password_wizard(osv.TransientModel):
|
||||||
|
|
||||||
def change_password_button(self, cr, uid, id, context=None):
|
def change_password_button(self, cr, uid, id, context=None):
|
||||||
wizard = self.browse(cr, uid, id, context=context)[0]
|
wizard = self.browse(cr, uid, id, context=context)[0]
|
||||||
user_ids = []
|
need_reload = any(uid == user.user_id.id for user in wizard.user_ids)
|
||||||
for user in wizard.user_ids:
|
line_ids = [user.id for user in wizard.user_ids]
|
||||||
user_ids.append(user.id)
|
|
||||||
self.pool.get('change.password.user').change_password_button(cr, uid, user_ids, context=context)
|
self.pool.get('change.password.user').change_password_button(cr, uid, line_ids, context=context)
|
||||||
# don't keep temporary password copies in the database longer than necessary
|
# don't keep temporary password copies in the database longer than necessary
|
||||||
self.pool.get('change.password.user').write(cr, uid, user_ids, {'new_passwd': False})
|
self.pool.get('change.password.user').write(cr, uid, line_ids, {'new_passwd': False}, context=context)
|
||||||
return {
|
|
||||||
'type': 'ir.actions.act_window_close',
|
if need_reload:
|
||||||
}
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'reload'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|
||||||
|
|
||||||
class change_password_user(osv.TransientModel):
|
class change_password_user(osv.TransientModel):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -439,5 +439,18 @@ class test_expression(common.TransactionCase):
|
||||||
partner_parent_id_col._auto_join = False
|
partner_parent_id_col._auto_join = False
|
||||||
state_country_id_col._auto_join = False
|
state_country_id_col._auto_join = False
|
||||||
|
|
||||||
|
def test_translate_search(self):
|
||||||
|
Country = self.registry('res.country')
|
||||||
|
be = self.ref('base.be')
|
||||||
|
domains = [
|
||||||
|
[('name', '=', 'Belgium')],
|
||||||
|
[('name', 'ilike', 'Belgi')],
|
||||||
|
[('name', 'in', ['Belgium', 'Care Bears'])],
|
||||||
|
]
|
||||||
|
|
||||||
|
for domain in domains:
|
||||||
|
ids = Country.search(self.cr, self.uid, domain)
|
||||||
|
self.assertListEqual([be], ids)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest2.main()
|
unittest2.main()
|
||||||
|
|
|
@ -107,8 +107,15 @@ def run_test_file(dbname, test_file):
|
||||||
registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=config['init'] or config['update'])
|
registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=config['init'] or config['update'])
|
||||||
cr = registry.db.cursor()
|
cr = registry.db.cursor()
|
||||||
_logger.info('loading test file %s', test_file)
|
_logger.info('loading test file %s', test_file)
|
||||||
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
|
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'init')
|
||||||
cr.rollback()
|
|
||||||
|
if config['test_commit']:
|
||||||
|
_logger.info('test %s has been commited', test_file)
|
||||||
|
cr.commit()
|
||||||
|
else:
|
||||||
|
_logger.info('test %s has been rollbacked', test_file)
|
||||||
|
cr.rollback()
|
||||||
|
|
||||||
cr.close()
|
cr.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
_logger.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file)
|
_logger.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
# Copyright (C) 2004-2012 OpenERP SA (<http://www.openerp.com>)
|
# Copyright (C) 2004-2014 OpenERP SA (<http://www.openerp.com>)
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# 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)
|
record.levelname = COLOR_PATTERN % (30 + fg_color, 40 + bg_color, record.levelname)
|
||||||
return DBFormatter.format(self, record)
|
return DBFormatter.format(self, record)
|
||||||
|
|
||||||
|
_logger_init = False
|
||||||
def init_logger():
|
def init_logger():
|
||||||
|
global _logger_init
|
||||||
|
if _logger_init:
|
||||||
|
return
|
||||||
|
_logger_init = True
|
||||||
|
|
||||||
from tools.translate import resetlocale
|
from tools.translate import resetlocale
|
||||||
resetlocale()
|
resetlocale()
|
||||||
|
|
||||||
|
@ -137,6 +143,8 @@ def init_logger():
|
||||||
formatter = DBFormatter(format)
|
formatter = DBFormatter(format)
|
||||||
handler.setFormatter(formatter)
|
handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
logging.getLogger().addHandler(handler)
|
||||||
|
|
||||||
# Configure handlers
|
# Configure handlers
|
||||||
pseudo_config = PSEUDOCONFIG_MAPPER.get(tools.config['log_level'], [])
|
pseudo_config = PSEUDOCONFIG_MAPPER.get(tools.config['log_level'], [])
|
||||||
|
|
||||||
|
@ -147,11 +155,7 @@ def init_logger():
|
||||||
loggername, level = logconfig_item.split(':')
|
loggername, level = logconfig_item.split(':')
|
||||||
level = getattr(logging, level, logging.INFO)
|
level = getattr(logging, level, logging.INFO)
|
||||||
logger = logging.getLogger(loggername)
|
logger = logging.getLogger(loggername)
|
||||||
logger.handlers = []
|
|
||||||
logger.setLevel(level)
|
logger.setLevel(level)
|
||||||
logger.addHandler(handler)
|
|
||||||
if loggername != '':
|
|
||||||
logger.propagate = False
|
|
||||||
|
|
||||||
for logconfig_item in logging_configurations:
|
for logconfig_item in logging_configurations:
|
||||||
_logger.debug('logger level set: "%s"', logconfig_item)
|
_logger.debug('logger level set: "%s"', logconfig_item)
|
||||||
|
|
|
@ -1019,6 +1019,7 @@ class expression(object):
|
||||||
push(create_substitution_leaf(leaf, (left, operator, right), working_model))
|
push(create_substitution_leaf(leaf, (left, operator, right), working_model))
|
||||||
|
|
||||||
elif field.translate and right:
|
elif field.translate and right:
|
||||||
|
field = left
|
||||||
need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
|
need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
|
||||||
sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
|
sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
|
||||||
if need_wildcard:
|
if need_wildcard:
|
||||||
|
@ -1030,33 +1031,40 @@ class expression(object):
|
||||||
sql_operator = sql_operator[4:] if sql_operator[:3] == 'not' else '='
|
sql_operator = sql_operator[4:] if sql_operator[:3] == 'not' else '='
|
||||||
inselect_operator = 'not inselect'
|
inselect_operator = 'not inselect'
|
||||||
|
|
||||||
subselect = '( SELECT res_id' \
|
trans_left = 'value'
|
||||||
' FROM ir_translation' \
|
left = '"%s"' % (left,)
|
||||||
' WHERE name = %s' \
|
instr = '%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 + ")"
|
|
||||||
|
|
||||||
params = [working_model._name + ',' + left,
|
if self.has_unaccent and sql_operator.endswith('like'):
|
||||||
context.get('lang', False) or 'en_US',
|
assert isinstance(right, basestring)
|
||||||
'model',
|
trans_left = 'unaccent(value)'
|
||||||
right,
|
left = 'unaccent(%s)' % (left,)
|
||||||
right,
|
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))
|
push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -1175,7 +1183,7 @@ class expression(object):
|
||||||
|
|
||||||
if left in model._columns:
|
if left in model._columns:
|
||||||
format = need_wildcard and '%s' or model._columns[left]._symbol_set[0]
|
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)
|
query = '(unaccent(%s."%s") %s unaccent(%s))' % (table_alias, left, sql_operator, format)
|
||||||
else:
|
else:
|
||||||
query = '(%s."%s" %s %s)' % (table_alias, left, sql_operator, format)
|
query = '(%s."%s" %s %s)' % (table_alias, left, sql_operator, format)
|
||||||
|
|
|
@ -602,7 +602,10 @@ class one2many(_column):
|
||||||
else:
|
else:
|
||||||
cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],))
|
cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],))
|
||||||
elif act[0] == 4:
|
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():
|
if not cr.fetchone():
|
||||||
# Must use write() to recompute parent_store structure if needed and check access rules
|
# 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 {})
|
obj.write(cr, user, [act[1]], {self._fields_id:id}, context=context or {})
|
||||||
|
|
|
@ -3256,7 +3256,7 @@ class BaseModel(object):
|
||||||
msg = "Table '%s': dropping index for column '%s' of type '%s' as it is not required anymore"
|
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)
|
_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]
|
dest_model = self.pool[f._obj]
|
||||||
if dest_model._table != 'ir_actions':
|
if dest_model._table != 'ir_actions':
|
||||||
self._m2o_fix_foreign_key(cr, self._table, k, dest_model, f.ondelete)
|
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)))
|
todo_end.append((order, self._update_store, (f, k)))
|
||||||
|
|
||||||
# and add constraints if needed
|
# 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:
|
if f._obj not in self.pool:
|
||||||
raise except_orm('Programming Error', 'There is no reference available for %s' % (f._obj,))
|
raise except_orm('Programming Error', 'There is no reference available for %s' % (f._obj,))
|
||||||
dest_model = self.pool[f._obj]
|
dest_model = self.pool[f._obj]
|
||||||
|
|
|
@ -85,50 +85,30 @@ def _open_image(filename, path=None):
|
||||||
class NumberedCanvas(canvas.Canvas):
|
class NumberedCanvas(canvas.Canvas):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
canvas.Canvas.__init__(self, *args, **kwargs)
|
canvas.Canvas.__init__(self, *args, **kwargs)
|
||||||
self._codes = []
|
self._saved_page_states = []
|
||||||
self._flag=False
|
|
||||||
self._pageCount=0
|
|
||||||
self._currentPage =0
|
|
||||||
self._pageCounter=0
|
|
||||||
self.pages={}
|
|
||||||
|
|
||||||
def showPage(self):
|
def showPage(self):
|
||||||
self._currentPage +=1
|
self._saved_page_states.append(dict(self.__dict__))
|
||||||
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._startPage()
|
self._startPage()
|
||||||
self._flag=False
|
|
||||||
|
|
||||||
def pageCount(self):
|
def save(self):
|
||||||
if self.pages.get(self._pageCounter,False):
|
"""add page info to each page (page x of y)"""
|
||||||
self._pageNumber=0
|
for state in self._saved_page_states:
|
||||||
self._pageCounter +=1
|
self.__dict__.update(state)
|
||||||
key=self._pageCounter
|
self.draw_page_number()
|
||||||
if not self.pages.get(key,False):
|
canvas.Canvas.showPage(self)
|
||||||
while not self.pages.get(key,False):
|
canvas.Canvas.save(self)
|
||||||
key += 1
|
|
||||||
|
def draw_page_number(self):
|
||||||
|
page_count = len(self._saved_page_states)
|
||||||
self.setFont("Helvetica", 8)
|
self.setFont("Helvetica", 8)
|
||||||
self.drawRightString((self._pagesize[0]-30), (self._pagesize[1]-40),
|
self.drawRightString((self._pagesize[0]-30), (self._pagesize[1]-40),
|
||||||
" %(this)i / %(total)i" % {
|
" %(this)i / %(total)i" % {
|
||||||
'this': self._pageNumber+1,
|
'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):
|
class PageCount(platypus.Flowable):
|
||||||
def __init__(self, story_count=0):
|
def __init__(self, story_count=0):
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence
|
# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence
|
||||||
# This assume an existing database.
|
# This assume an existing database.
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
import psycopg2.errorcodes
|
||||||
import unittest2
|
import unittest2
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
|
@ -111,11 +112,11 @@ class test_ir_sequence_no_gap(unittest2.TestCase):
|
||||||
cr0 = cursor()
|
cr0 = cursor()
|
||||||
cr1 = cursor()
|
cr1 = cursor()
|
||||||
cr1._default_log_exceptions = False # Prevent logging a traceback
|
cr1._default_log_exceptions = False # Prevent logging a traceback
|
||||||
msg_re = '^could not obtain lock on row in relation "ir_sequence"$'
|
with self.assertRaises(psycopg2.OperationalError) as e:
|
||||||
with self.assertRaisesRegexp(psycopg2.OperationalError, msg_re):
|
|
||||||
n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {})
|
n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {})
|
||||||
assert n0
|
assert n0
|
||||||
n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {})
|
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()
|
cr0.close()
|
||||||
cr1.close()
|
cr1.close()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue