[MERGE] forward port of branch saas-3 up to revid 5112 chs@openerp.com-20140407144238-3s38zadkh7yxpdy7
bzr revid: chs@openerp.com-20140407160548-ttuc877kknuycoqw
This commit is contained in:
commit
0161666e8b
|
@ -945,6 +945,7 @@ class ir_actions_server(osv.osv):
|
|||
'user': user,
|
||||
'context': context,
|
||||
'workflow': workflow
|
||||
'Warning': openerp.exceptions.Warning,
|
||||
}
|
||||
|
||||
def run(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -85,8 +85,8 @@ class ir_http(osv.AbstractModel):
|
|||
return auth_method
|
||||
|
||||
def _handle_exception(self, exception):
|
||||
# If handle exception return something different than None, it will be used as a response
|
||||
raise
|
||||
# If handle_exception returns something different than None, it will be used as a response
|
||||
return request._handle_exception(exception)
|
||||
|
||||
def _dispatch(self):
|
||||
# locate the controller method
|
||||
|
|
|
@ -603,7 +603,7 @@ class DateTimeConverter(osv.AbstractModel):
|
|||
if isinstance(value, basestring):
|
||||
value = datetime.datetime.strptime(
|
||||
value, openerp.tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
value = column.context_timestamp(
|
||||
value = fields.datetime.context_timestamp(
|
||||
cr, uid, timestamp=value, context=context)
|
||||
|
||||
if options and 'format' in options:
|
||||
|
|
|
@ -73,12 +73,18 @@ class view_custom(osv.osv):
|
|||
class view(osv.osv):
|
||||
_name = 'ir.ui.view'
|
||||
|
||||
def _get_model_data(self, cr, uid, ids, *args, **kwargs):
|
||||
ir_model_data = self.pool.get('ir.model.data')
|
||||
data_ids = ir_model_data.search(cr, uid, [('model', '=', self._name), ('res_id', 'in', ids)])
|
||||
result = dict(zip(ids, data_ids))
|
||||
def _get_model_data(self, cr, uid, ids, fname, args, context=None):
|
||||
result = dict.fromkeys(ids, False)
|
||||
IMD = self.pool['ir.model.data']
|
||||
data_ids = IMD.search_read(cr, uid, [('res_id', 'in', ids), ('model', '=', 'ir.ui.view')], ['res_id'], context=context)
|
||||
result.update(map(itemgetter('res_id', 'id'), data_ids))
|
||||
return result
|
||||
|
||||
def _views_from_model_data(self, cr, uid, ids, context=None):
|
||||
IMD = self.pool['ir.model.data']
|
||||
data_ids = IMD.search_read(cr, uid, [('id', 'in', ids), ('model', '=', 'ir.ui.view')], ['res_id'], context=context)
|
||||
return map(itemgetter('res_id'), data_ids)
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('View Name', required=True),
|
||||
'model': fields.char('Object', select=True),
|
||||
|
@ -97,7 +103,11 @@ class view(osv.osv):
|
|||
'inherit_id': fields.many2one('ir.ui.view', 'Inherited View', ondelete='cascade', select=True),
|
||||
'inherit_children_ids': fields.one2many('ir.ui.view','inherit_id', 'Inherit Views'),
|
||||
'field_parent': fields.char('Child Field'),
|
||||
'model_data_id': fields.function(_get_model_data, type='many2one', relation='ir.model.data', string="Model Data", store=True),
|
||||
'model_data_id': fields.function(_get_model_data, type='many2one', relation='ir.model.data', string="Model Data",
|
||||
store={
|
||||
_name: (lambda s, c, u, i, ctx=None: i, None, 10),
|
||||
'ir.model.data': (_views_from_model_data, ['model', 'res_id'], 10),
|
||||
}),
|
||||
'xml_id': fields.function(osv.osv.get_xml_id, type='char', size=128, string="External ID",
|
||||
help="ID of the view defined in xml file"),
|
||||
'groups_id': fields.many2many('res.groups', 'ir_ui_view_group_rel', 'view_id', 'group_id',
|
||||
|
|
|
@ -37,6 +37,23 @@ and Ubuntu distros, we have to override the search path, too.
|
|||
"""
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# Alternatives for the [broken] builtin PDF fonts. Default order chosen to match
|
||||
# the pre-v8 mapping from openerp.report.render.rml2pdf.customfonts.CustomTTFonts.
|
||||
# Format: [ (BuiltinFontFamily, mode, [AlternativeFontName, ...]), ...]
|
||||
BUILTIN_ALTERNATIVES = [
|
||||
('Helvetica', "normal", ["DejaVuSans", "LiberationSans"]),
|
||||
('Helvetica', "bold", ["DejaVuSans-Bold", "LiberationSans-Bold"]),
|
||||
('Helvetica', 'italic', ["DejaVuSans-Oblique", "LiberationSans-Italic"]),
|
||||
('Helvetica', 'bolditalic', ["DejaVuSans-BoldOblique", "LiberationSans-BoldItalic"]),
|
||||
('Times', 'normal', ["LiberationSerif", "DejaVuSerif"]),
|
||||
('Times', 'bold', ["LiberationSerif-Bold", "DejaVuSerif-Bold"]),
|
||||
('Times', 'italic', ["LiberationSerif-Italic", "DejaVuSerif-Italic"]),
|
||||
('Times', 'bolditalic', ["LiberationSerif-BoldItalic", "DejaVuSerif-BoldItalic"]),
|
||||
('Courier', 'normal', ["FreeMono", "DejaVuSansMono"]),
|
||||
('Courier', 'bold', ["FreeMonoBold", "DejaVuSansMono-Bold"]),
|
||||
('Courier', 'italic', ["FreeMonoOblique", "DejaVuSansMono-Oblique"]),
|
||||
('Courier', 'bolditalic', ["FreeMonoBoldOblique", "DejaVuSansMono-BoldOblique"]),
|
||||
]
|
||||
|
||||
class res_font(osv.Model):
|
||||
_name = "res.font"
|
||||
|
@ -113,9 +130,32 @@ class res_font(osv.Model):
|
|||
def _sync(self, cr, uid, context=None):
|
||||
"""Set the customfonts.CustomTTFonts list to the content of the database"""
|
||||
customfonts.CustomTTFonts = []
|
||||
local_family_modes = set()
|
||||
local_font_paths = {}
|
||||
found_fonts_ids = self.search(cr, uid, [('path', '!=', '/dev/null')], context=context)
|
||||
for font in self.browse(cr, uid, found_fonts_ids, context=None):
|
||||
local_family_modes.add((font.family, font.mode))
|
||||
local_font_paths[font.name] = font.path
|
||||
customfonts.CustomTTFonts.append((font.family, font.name, font.path, font.mode))
|
||||
|
||||
# Attempt to remap the builtin fonts (Helvetica, Times, Courier) to better alternatives
|
||||
# if available, because they only support a very small subset of unicode
|
||||
# (missing 'č' for example)
|
||||
for builtin_font_family, mode, alts in BUILTIN_ALTERNATIVES:
|
||||
if (builtin_font_family, mode) not in local_family_modes:
|
||||
# No local font exists with that name, try alternatives
|
||||
for altern_font in alts:
|
||||
if local_font_paths.get(altern_font):
|
||||
altern_def = (builtin_font_family, altern_font,
|
||||
local_font_paths[altern_font], mode)
|
||||
customfonts.CustomTTFonts.append(altern_def)
|
||||
_logger.debug("Builtin remapping %r", altern_def)
|
||||
break
|
||||
else:
|
||||
_logger.warning("No local alternative found for builtin font `%s` (%s mode)."
|
||||
"Consider installing the DejaVu fonts if you have problems "
|
||||
"with unicode characters in RML reports",
|
||||
builtin_font_family, mode)
|
||||
return True
|
||||
|
||||
def clear_caches(self):
|
||||
|
|
|
@ -28,6 +28,7 @@ import openerp
|
|||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.osv.expression import get_unaccent_wrapper
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class format_address(object):
|
||||
|
@ -228,10 +229,10 @@ class res_partner(osv.osv, format_address):
|
|||
_order = "display_name"
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=128, required=True, select=True),
|
||||
'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers),
|
||||
'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers, select=True),
|
||||
'date': fields.date('Date', select=1),
|
||||
'title': fields.many2one('res.partner.title', 'Title'),
|
||||
'parent_id': fields.many2one('res.partner', 'Related Company'),
|
||||
'parent_id': fields.many2one('res.partner', 'Related Company', select=True),
|
||||
'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override
|
||||
'ref': fields.char('Reference', size=64, select=1),
|
||||
'lang': fields.selection(_lang_get, 'Language',
|
||||
|
@ -629,10 +630,17 @@ class res_partner(osv.osv, format_address):
|
|||
if operator in ('=ilike', '=like'):
|
||||
operator = operator[1:]
|
||||
|
||||
query = ('SELECT id FROM res_partner ' +
|
||||
where_str + '(email ' + operator + ''' %s
|
||||
OR display_name ''' + operator + ''' %s)
|
||||
ORDER BY display_name''')
|
||||
unaccent = get_unaccent_wrapper(cr)
|
||||
|
||||
query = """SELECT id
|
||||
FROM res_partner
|
||||
{where} ({email} {operator} {percent}
|
||||
OR {display_name} {operator} {percent})
|
||||
ORDER BY {display_name}
|
||||
""".format(where=where_str, operator=operator,
|
||||
email=unaccent('email'),
|
||||
display_name=unaccent('display_name'),
|
||||
percent=unaccent('%s'))
|
||||
|
||||
where_clause_params += [search_name, search_name]
|
||||
if limit:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import unittest2
|
||||
|
||||
import openerp
|
||||
from openerp.osv.expression import get_unaccent_wrapper
|
||||
from openerp.osv.orm import BaseModel
|
||||
import openerp.tests.common as common
|
||||
|
||||
|
@ -124,6 +125,7 @@ class test_expression(common.TransactionCase):
|
|||
|
||||
def test_20_auto_join(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
unaccent = get_unaccent_wrapper(cr)
|
||||
|
||||
# Get models
|
||||
partner_obj = registry('res.partner')
|
||||
|
@ -180,8 +182,11 @@ class test_expression(common.TransactionCase):
|
|||
sql_query = self.query_list[0].get_sql()
|
||||
self.assertIn('res_partner_bank', sql_query[0],
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect main table")
|
||||
self.assertIn('"res_partner_bank"."name" like %s', sql_query[1],
|
||||
|
||||
expected = "%s like %s" % (unaccent('"res_partner_bank"."name"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect where condition")
|
||||
|
||||
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect parameter")
|
||||
sql_query = self.query_list[2].get_sql()
|
||||
|
@ -217,8 +222,11 @@ class test_expression(common.TransactionCase):
|
|||
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect main table")
|
||||
self.assertIn('"res_partner_bank" as "res_partner__bank_ids"', sql_query[0],
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect join")
|
||||
self.assertIn('"res_partner__bank_ids"."name" like %s', sql_query[1],
|
||||
|
||||
expected = "%s like %s" % (unaccent('"res_partner__bank_ids"."name"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect where condition")
|
||||
|
||||
self.assertIn('"res_partner"."id"="res_partner__bank_ids"."partner_id"', sql_query[1],
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect join condition")
|
||||
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
|
||||
|
@ -296,8 +304,11 @@ class test_expression(common.TransactionCase):
|
|||
sql_query = self.query_list[0].get_sql()
|
||||
self.assertIn('"res_country"', sql_query[0],
|
||||
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect main table")
|
||||
self.assertIn('"res_country"."code" like %s', sql_query[1],
|
||||
|
||||
expected = "%s like %s" % (unaccent('"res_country"."code"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect where condition")
|
||||
|
||||
self.assertEqual(['%' + name_test + '%'], sql_query[2],
|
||||
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect parameter")
|
||||
sql_query = self.query_list[1].get_sql()
|
||||
|
@ -327,8 +338,11 @@ class test_expression(common.TransactionCase):
|
|||
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect main table")
|
||||
self.assertIn('"res_country" as "res_country_state__country_id"', sql_query[0],
|
||||
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect join")
|
||||
self.assertIn('"res_country_state__country_id"."code" like %s', sql_query[1],
|
||||
|
||||
expected = "%s like %s" % (unaccent('"res_country_state__country_id"."code"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect where condition")
|
||||
|
||||
self.assertIn('"res_country_state"."country_id"="res_country_state__country_id"."id"', sql_query[1],
|
||||
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect join condition")
|
||||
self.assertEqual(['%' + name_test + '%'], sql_query[2],
|
||||
|
@ -358,8 +372,11 @@ class test_expression(common.TransactionCase):
|
|||
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join")
|
||||
self.assertIn('"res_country" as "res_partner__state_id__country_id"', sql_query[0],
|
||||
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join")
|
||||
self.assertIn('"res_partner__state_id__country_id"."code" like %s', sql_query[1],
|
||||
|
||||
expected = "%s like %s" % (unaccent('"res_partner__state_id__country_id"."code"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect where condition")
|
||||
|
||||
self.assertIn('"res_partner"."state_id"="res_partner__state_id"."id"', sql_query[1],
|
||||
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join condition")
|
||||
self.assertIn('"res_partner__state_id"."country_id"="res_partner__state_id__country_id"."id"', sql_query[1],
|
||||
|
@ -385,7 +402,9 @@ class test_expression(common.TransactionCase):
|
|||
"_auto_join on one2many with domains incorrect result")
|
||||
# Test produced queries that domains effectively present
|
||||
sql_query = self.query_list[0].get_sql()
|
||||
self.assertIn('"res_partner__child_ids__bank_ids"."acc_number" like %s', sql_query[1],
|
||||
|
||||
expected = "%s like %s" % (unaccent('"res_partner__child_ids__bank_ids"."acc_number"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on one2many with domains incorrect result")
|
||||
# TDE TODO: check first domain has a correct table name
|
||||
self.assertIn('"res_partner__child_ids"."name" = %s', sql_query[1],
|
||||
|
@ -447,6 +466,19 @@ class test_expression(common.TransactionCase):
|
|||
domain = [('x', 'in', ['y', 'z']), ('a.v', '=', 'e'), '|', '|', ('a', '=', 'b'), '!', ('c', '>', 'd'), ('e', '!=', 'f'), ('g', '=', 'h')]
|
||||
norm_domain = ['&', '&', '&'] + domain
|
||||
assert norm_domain == expression.normalize_domain(domain), "Non-normalized domains should be properly normalized"
|
||||
|
||||
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__':
|
||||
unittest2.main()
|
||||
|
|
|
@ -29,6 +29,7 @@ GNU Public Licence.
|
|||
(c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
|
@ -78,16 +79,23 @@ def report_configuration():
|
|||
('database user', config['db_user'])]:
|
||||
_logger.info("%s: %s", name, value)
|
||||
|
||||
def rm_pid_file():
|
||||
config = openerp.tools.config
|
||||
if not openerp.evented and os.path.exists(config['pidfile']):
|
||||
os.unlink(config['pidfile'])
|
||||
|
||||
def setup_pid_file():
|
||||
""" Create a file with the process id written in it.
|
||||
|
||||
This function assumes the configuration has been initialized.
|
||||
"""
|
||||
config = openerp.tools.config
|
||||
if config['pidfile']:
|
||||
if not openerp.evented and config['pidfile']:
|
||||
with open(config['pidfile'], 'w') as fd:
|
||||
pidtext = "%d" % (os.getpid())
|
||||
fd.write(pidtext)
|
||||
atexit.register(rm_pid_file)
|
||||
|
||||
|
||||
def export_translation():
|
||||
config = openerp.tools.config
|
||||
|
@ -155,8 +163,6 @@ def main(args):
|
|||
|
||||
setup_pid_file()
|
||||
rc = openerp.service.server.start(preload=preload, stop=stop)
|
||||
if config['pidfile']:
|
||||
os.unlink(config['pidfile'])
|
||||
sys.exit(rc)
|
||||
|
||||
class Server(Command):
|
||||
|
|
|
@ -270,6 +270,13 @@ class WebRequest(object):
|
|||
self.endpoint = endpoint
|
||||
self.auth_method = auth
|
||||
|
||||
|
||||
def _handle_exception(self, exception):
|
||||
"""Called within an except block to allow converting exceptions
|
||||
to abitrary responses. Anything returned (except None) will
|
||||
be used as response."""
|
||||
raise
|
||||
|
||||
def _call_function(self, *args, **kwargs):
|
||||
request = self
|
||||
if self.endpoint.routing['type'] != self._request_type:
|
||||
|
@ -421,39 +428,15 @@ class JsonRequest(WebRequest):
|
|||
self.params = dict(self.jsonrequest.get("params", {}))
|
||||
self.context = self.params.pop('context', dict(self.session.context))
|
||||
|
||||
def dispatch(self):
|
||||
""" Calls the method asked for by the JSON-RPC2 or JSONP request
|
||||
"""
|
||||
if self.jsonp_handler:
|
||||
return self.jsonp_handler()
|
||||
response = {"jsonrpc": "2.0" }
|
||||
error = None
|
||||
|
||||
try:
|
||||
response['id'] = self.jsonrequest.get('id')
|
||||
response["result"] = self._call_function(**self.params)
|
||||
except AuthenticationError, e:
|
||||
_logger.exception("JSON-RPC AuthenticationError in %s.", self.httprequest.path)
|
||||
se = serialize_exception(e)
|
||||
error = {
|
||||
'code': 100,
|
||||
'message': "OpenERP Session Invalid",
|
||||
'data': se
|
||||
}
|
||||
self._failed = e # prevent tx commit
|
||||
except Exception, e:
|
||||
# Mute test cursor error for runbot
|
||||
if not (openerp.tools.config['test_enable'] and isinstance(e, psycopg2.OperationalError)):
|
||||
_logger.exception("JSON-RPC Exception in %s.", self.httprequest.path)
|
||||
se = serialize_exception(e)
|
||||
error = {
|
||||
'code': 200,
|
||||
'message': "OpenERP Server Error",
|
||||
'data': se
|
||||
}
|
||||
self._failed = e # prevent tx commit
|
||||
if error:
|
||||
response["error"] = error
|
||||
def _json_response(self, result=None, error=None):
|
||||
response = {
|
||||
'jsonrpc': '2.0',
|
||||
'id': self.jsonrequest.get('id')
|
||||
}
|
||||
if error is not None:
|
||||
response['error'] = error
|
||||
if result is not None:
|
||||
response['result'] = result
|
||||
|
||||
if self.jsonp:
|
||||
# If we use jsonp, that's mean we are called from another host
|
||||
|
@ -466,8 +449,36 @@ class JsonRequest(WebRequest):
|
|||
mime = 'application/json'
|
||||
body = simplejson.dumps(response)
|
||||
|
||||
r = Response(body, headers=[('Content-Type', mime), ('Content-Length', len(body))])
|
||||
return r
|
||||
return Response(
|
||||
body, headers=[('Content-Type', mime),
|
||||
('Content-Length', len(body))])
|
||||
|
||||
def _handle_exception(self, exception):
|
||||
"""Called within an except block to allow converting exceptions
|
||||
to abitrary responses. Anything returned (except None) will
|
||||
be used as response."""
|
||||
_logger.exception("Exception during JSON request handling.")
|
||||
self._failed = exception # prevent tx commit
|
||||
error = {
|
||||
'code': 200,
|
||||
'message': "OpenERP Server Error",
|
||||
'data': serialize_exception(exception)
|
||||
}
|
||||
if isinstance(exception, AuthenticationError):
|
||||
error['code'] = 100
|
||||
error['message'] = "OpenERP Session Invalid"
|
||||
return self._json_response(error=error)
|
||||
|
||||
def dispatch(self):
|
||||
""" Calls the method asked for by the JSON-RPC2 or JSONP request
|
||||
"""
|
||||
if self.jsonp_handler:
|
||||
return self.jsonp_handler()
|
||||
try:
|
||||
result = self._call_function(**self.params)
|
||||
return self._json_response(result)
|
||||
except Exception, e:
|
||||
return self._handle_exception(e)
|
||||
|
||||
def serialize_exception(e):
|
||||
tmp = {
|
||||
|
|
|
@ -429,6 +429,10 @@ def select_distinct_from_where_not_null(cr, select_field, from_table):
|
|||
cr.execute('SELECT distinct("%s") FROM "%s" where "%s" is not null' % (select_field, from_table, select_field))
|
||||
return [r[0] for r in cr.fetchall()]
|
||||
|
||||
def get_unaccent_wrapper(cr):
|
||||
if openerp.modules.registry.RegistryManager.get(cr.dbname).has_unaccent:
|
||||
return lambda x: "unaccent(%s)" % (x,)
|
||||
return lambda x: x
|
||||
|
||||
# --------------------------------------------------
|
||||
# ExtendedLeaf class for managing leafs and contexts
|
||||
|
@ -630,7 +634,7 @@ class expression(object):
|
|||
:attr list expression: the domain expression, that will be normalized
|
||||
and prepared
|
||||
"""
|
||||
self.has_unaccent = openerp.modules.registry.RegistryManager.get(cr.dbname).has_unaccent
|
||||
self._unaccent = get_unaccent_wrapper(cr)
|
||||
self.joins = []
|
||||
self.root_model = table
|
||||
|
||||
|
@ -1012,10 +1016,10 @@ class expression(object):
|
|||
|
||||
else:
|
||||
if field._type == 'datetime' and right and len(right) == 10:
|
||||
if operator in ('>', '>=', '='):
|
||||
right += ' 00:00:00'
|
||||
elif operator in ('<', '<='):
|
||||
if operator in ('>', '<='):
|
||||
right += ' 23:59:59'
|
||||
else:
|
||||
right += ' 00:00:00'
|
||||
push(create_substitution_leaf(leaf, (left, operator, right), working_model))
|
||||
|
||||
elif field.translate and right:
|
||||
|
@ -1030,33 +1034,37 @@ 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 + ")"
|
||||
unaccent = self._unaccent if sql_operator.endswith('like') else lambda x: x
|
||||
|
||||
params = [working_model._name + ',' + left,
|
||||
context.get('lang', False) or 'en_US',
|
||||
'model',
|
||||
right,
|
||||
right,
|
||||
]
|
||||
trans_left = unaccent('value')
|
||||
quote_left = unaccent(_quote(left))
|
||||
instr = unaccent('%s')
|
||||
|
||||
if 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=quote_left)
|
||||
|
||||
params = (
|
||||
working_model._name + ',' + left,
|
||||
context.get('lang') or 'en_US',
|
||||
'model',
|
||||
right,
|
||||
right,
|
||||
)
|
||||
push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model))
|
||||
|
||||
else:
|
||||
|
@ -1177,10 +1185,9 @@ 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'):
|
||||
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)
|
||||
unaccent = self._unaccent if sql_operator.endswith('like') else lambda x: x
|
||||
column = '%s.%s' % (table_alias, _quote(left))
|
||||
query = '(%s %s %s)' % (unaccent(column), sql_operator, unaccent(format))
|
||||
elif left in MAGIC_COLUMNS:
|
||||
query = "(%s.\"%s\" %s %%s)" % (table_alias, left, sql_operator)
|
||||
params = right
|
||||
|
|
|
@ -648,7 +648,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 {})
|
||||
|
|
|
@ -469,7 +469,12 @@ class browse_record(object):
|
|||
else:
|
||||
new_data[field_name] = browse_null()
|
||||
elif field_column._type in ('one2many', 'many2many') and len(result_line[field_name]):
|
||||
new_data[field_name] = self._list_class([browse_record(self._cr, self._uid, id, self._table.pool[field_column._obj], self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process) for id in result_line[field_name]], self._context)
|
||||
new_data[field_name] = self._list_class(
|
||||
(browse_record(self._cr, self._uid, id, self._table.pool.get(field_column._obj),
|
||||
self._cache, context=self._context, list_class=self._list_class,
|
||||
fields_process=self._fields_process)
|
||||
for id in result_line[field_name]),
|
||||
context=self._context)
|
||||
elif field_column._type == 'reference':
|
||||
if result_line[field_name]:
|
||||
if isinstance(result_line[field_name], browse_record):
|
||||
|
@ -1911,7 +1916,7 @@ class BaseModel(object):
|
|||
return result
|
||||
|
||||
def _view_look_dom_arch(self, cr, uid, node, view_id, context=None):
|
||||
return self['ir.ui.view'].postprocess_and_fields(
|
||||
return self.pool['ir.ui.view'].postprocess_and_fields(
|
||||
cr, uid, self._name, node, view_id, context=context)
|
||||
|
||||
def search_count(self, cr, user, args, context=None):
|
||||
|
@ -4250,7 +4255,7 @@ class BaseModel(object):
|
|||
if isinstance(select, (int, long)):
|
||||
return browse_record(cr, uid, select, self, cache, context=context, list_class=self._list_class, fields_process=fields_process)
|
||||
elif isinstance(select, list):
|
||||
return self._list_class([browse_record(cr, uid, id, self, cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context=context)
|
||||
return self._list_class((browse_record(cr, uid, id, self, cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select), context=context)
|
||||
else:
|
||||
return browse_null()
|
||||
|
||||
|
|
|
@ -88,50 +88,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):
|
||||
|
@ -303,6 +283,9 @@ class _rml_doc(object):
|
|||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
|
||||
if mode:
|
||||
mode = mode.lower()
|
||||
|
||||
if fontname not in pdfmetrics._fonts:
|
||||
pdfmetrics.registerFont(TTFont(fontname, filename))
|
||||
if mode == 'all':
|
||||
|
@ -310,14 +293,14 @@ class _rml_doc(object):
|
|||
addMapping(face, 0, 1, fontname) #italic
|
||||
addMapping(face, 1, 0, fontname) #bold
|
||||
addMapping(face, 1, 1, fontname) #italic and bold
|
||||
elif (mode== 'normal') or (mode == 'regular') or (mode == 'book'):
|
||||
addMapping(face, 0, 0, fontname) #normal
|
||||
elif mode == 'italic':
|
||||
elif mode in ['italic', 'oblique']:
|
||||
addMapping(face, 0, 1, fontname) #italic
|
||||
elif mode == 'bold':
|
||||
addMapping(face, 1, 0, fontname) #bold
|
||||
elif mode == 'bolditalic':
|
||||
elif mode in ('bolditalic', 'bold italic','boldoblique', 'bold oblique'):
|
||||
addMapping(face, 1, 1, fontname) #italic and bold
|
||||
else:
|
||||
addMapping(face, 0, 0, fontname) #normal
|
||||
|
||||
def _textual_image(self, node):
|
||||
rc = ''
|
||||
|
|
|
@ -440,7 +440,7 @@ class PreforkServer(CommonServer):
|
|||
sys.exit(0)
|
||||
|
||||
def long_polling_spawn(self):
|
||||
nargs = stripped_sys_argv('--pidfile', '--workers')
|
||||
nargs = stripped_sys_argv()
|
||||
cmd = nargs[0]
|
||||
cmd = os.path.join(os.path.dirname(cmd), "openerp-gevent")
|
||||
nargs[0] = cmd
|
||||
|
@ -834,8 +834,13 @@ def _reexec(updated_modules=None):
|
|||
|
||||
def load_test_file_yml(registry, test_file):
|
||||
with registry.cursor() as cr:
|
||||
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
|
||||
cr.rollback()
|
||||
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'init')
|
||||
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()
|
||||
|
||||
def load_test_file_py(registry, test_file):
|
||||
# Locate python module based on its filename and run the tests
|
||||
|
@ -887,10 +892,10 @@ def start(preload=None, stop=False):
|
|||
"""
|
||||
global server
|
||||
load_server_wide_modules()
|
||||
if config['workers']:
|
||||
server = PreforkServer(openerp.service.wsgi_server.application)
|
||||
elif openerp.evented:
|
||||
if openerp.evented:
|
||||
server = GeventServer(openerp.service.wsgi_server.application)
|
||||
elif config['workers']:
|
||||
server = PreforkServer(openerp.service.wsgi_server.application)
|
||||
else:
|
||||
server = ThreadedServer(openerp.service.wsgi_server.application)
|
||||
|
||||
|
|
|
@ -70,7 +70,11 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
|
|||
image_stream = StringIO.StringIO(base64_source.decode(encoding))
|
||||
image = Image.open(image_stream)
|
||||
# store filetype here, as Image.new below will lose image.format
|
||||
filetype = filetype or image.format
|
||||
filetype = (filetype or image.format).upper()
|
||||
|
||||
filetype = {
|
||||
'BMP': 'PNG',
|
||||
}.get(filetype, filetype)
|
||||
|
||||
asked_width, asked_height = size
|
||||
if asked_width is None:
|
||||
|
|
Loading…
Reference in New Issue