summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-11-22 17:52:57 +0100
committerChristophe Simonis <chs@odoo.com>2018-11-22 17:52:57 +0100
commitb09f624f20781d65baf2060df40383898e6f86e5 (patch)
treefbaf29a0fca1ce63e616698717435fd1a8413921 /odoo
parentbab2a191d292737d1c2bc6b1650a1581614b0cc1 (diff)
parent263b388c5045bebc77cc27847f7500784f63c7f5 (diff)
[MERGE] forward port branch 11.0 up to 263b388c504
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/data/res.country.state.csv2
-rw-r--r--odoo/addons/base/models/ir_actions_report.py14
-rw-r--r--odoo/addons/base/models/ir_property.py97
-rw-r--r--odoo/addons/test_new_api/models.py2
-rw-r--r--odoo/addons/test_new_api/tests/test_new_fields.py26
-rw-r--r--odoo/http.py1
-rw-r--r--odoo/tools/cache.py24
7 files changed, 115 insertions, 51 deletions
diff --git a/odoo/addons/base/data/res.country.state.csv b/odoo/addons/base/data/res.country.state.csv
index b64c8f78f12..1f2c8f1cbb8 100644
--- a/odoo/addons/base/data/res.country.state.csv
+++ b/odoo/addons/base/data/res.country.state.csv
@@ -551,7 +551,7 @@ state_ae_fu,ae,"Fujairah","FU"
state_ae_rk,ae,"Ras al-Khaimah","RK"
state_ae_sh,ae,"Sharjah","SH"
state_ae_uq,ae,"Umm al-Quwain","UQ"
-state_ar_c,ar,"Buenos Aires City","C"
+state_ar_c,ar,"Ciudad Autónoma de Buenos Aires","C"
state_ar_b,ar,"Buenos Aires","B"
state_ar_k,ar,"Catamarca","K"
state_ar_h,ar,"Chaco","H"
diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py
index 36326217f42..d051e501466 100644
--- a/odoo/addons/base/models/ir_actions_report.py
+++ b/odoo/addons/base/models/ir_actions_report.py
@@ -44,6 +44,7 @@ def _get_wkhtmltopdf_bin():
# Check the presence of Wkhtmltopdf and return its version at Odoo start-up
wkhtmltopdf_state = 'install'
+wkhtmltopdf_dpi_zoom_ratio = False
try:
process = subprocess.Popen(
[_get_wkhtmltopdf_bin(), '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE
@@ -61,6 +62,8 @@ else:
wkhtmltopdf_state = 'upgrade'
else:
wkhtmltopdf_state = 'ok'
+ if LooseVersion(version) >= LooseVersion('0.12.2'):
+ wkhtmltopdf_dpi_zoom_ratio = True
if config['workers'] == 1:
_logger.info('You need to start Odoo with at least two workers to print a pdf version of the reports.')
@@ -237,14 +240,19 @@ class IrActionsReport(models.Model):
else:
command_args.extend(['--margin-top', str(paperformat_id.margin_top)])
+ dpi = None
if specific_paperformat_args and specific_paperformat_args.get('data-report-dpi'):
- command_args.extend(['--dpi', str(specific_paperformat_args['data-report-dpi'])])
+ dpi = int(specific_paperformat_args['data-report-dpi'])
elif paperformat_id.dpi:
if os.name == 'nt' and int(paperformat_id.dpi) <= 95:
_logger.info("Generating PDF on Windows platform require DPI >= 96. Using 96 instead.")
- command_args.extend(['--dpi', '96'])
+ dpi = 96
else:
- command_args.extend(['--dpi', str(paperformat_id.dpi)])
+ dpi = paperformat_id.dpi
+ if dpi:
+ command_args.extend(['--dpi', str(dpi)])
+ if wkhtmltopdf_dpi_zoom_ratio:
+ command_args.extend(['--zoom', str(96.0 / dpi)])
if specific_paperformat_args and specific_paperformat_args.get('data-report-header-spacing'):
command_args.extend(['--header-spacing', str(specific_paperformat_args['data-report-header-spacing'])])
diff --git a/odoo/addons/base/models/ir_property.py b/odoo/addons/base/models/ir_property.py
index 4a7e0d7231b..8c789f1f4bf 100644
--- a/odoo/addons/base/models/ir_property.py
+++ b/odoo/addons/base/models/ir_property.py
@@ -20,6 +20,18 @@ TYPE2FIELD = {
'selection': 'value_text',
}
+TYPE2CLEAN = {
+ 'boolean': bool,
+ 'integer': lambda val: val or False,
+ 'float': lambda val: val or False,
+ 'char': lambda val: val or False,
+ 'text': lambda val: val or False,
+ 'selection': lambda val: val or False,
+ 'binary': lambda val: val or False,
+ 'date': lambda val: val or False,
+ 'datetime': lambda val: val or False,
+}
+
class Property(models.Model):
_name = 'ir.property'
@@ -147,48 +159,61 @@ class Property(models.Model):
if not ids:
return {}
- domain = self._get_domain(name, model)
- if domain is None:
- return dict.fromkeys(ids, False)
-
- # retrieve the values for the given ids and the default value, too
- refs = {('%s,%s' % (model, id)): id for id in ids}
- refs[False] = False
- domain += [('res_id', 'in', list(refs))]
-
- # note: order by 'company_id asc' will return non-null values first
- props = self.search(domain, order='company_id asc')
- result = {}
-
field = self.env[model]._fields[name]
+ field_id = self.env['ir.model.fields']._get(model, name).id
+ company_id = (
+ self._context.get('force_company')
+ or self.env['res.company']._company_default_get(model, field_id).id
+ )
+
if field.type == 'many2one':
- # optimization for many2one fields
- Comodel = self.env[field.comodel_name]
- co_ids = set()
- for prop in props:
- # for a given res_id, take the first property only
- id = refs.pop(prop.res_id, None)
- if id is not None:
- val = prop.value_reference
- if val:
- val = int(val.split(',')[1])
- co_ids.add(val)
- result[id] = val
- # check for existence in batch, and update result accordingly
- existing = {rec.id: rec for rec in Comodel.browse(co_ids).exists()}
- result = {id: existing.get(val, Comodel) for id, val in result.items()}
+ comodel = self.env[field.comodel_name]
+ model_pos = len(model) + 2
+ value_pos = len(comodel._name) + 2
+ # retrieve values: both p.res_id and p.value_reference are formatted
+ # as "<rec._name>,<rec.id>"; the purpose of the LEFT JOIN is to
+ # return the value id if it exists, NULL otherwise
+ query = """
+ SELECT substr(p.res_id, %s)::integer, r.id
+ FROM ir_property p
+ LEFT JOIN {} r ON substr(p.value_reference, %s)::integer=r.id
+ WHERE p.fields_id=%s
+ AND (p.company_id=%s OR p.company_id IS NULL)
+ AND (p.res_id IN %s OR p.res_id IS NULL)
+ ORDER BY p.company_id NULLS FIRST
+ """.format(comodel._table)
+ params = [model_pos, value_pos, field_id, company_id]
+ clean = comodel.browse
+
+ elif field.type in TYPE2FIELD:
+ model_pos = len(model) + 2
+ # retrieve values: p.res_id is formatted as "<rec._name>,<rec.id>"
+ query = """
+ SELECT substr(p.res_id, %s)::integer, p.{}
+ FROM ir_property p
+ WHERE p.fields_id=%s
+ AND (p.company_id=%s OR p.company_id IS NULL)
+ AND (p.res_id IN %s OR p.res_id IS NULL)
+ ORDER BY p.company_id NULLS FIRST
+ """.format(TYPE2FIELD[field.type])
+ params = [model_pos, field_id, company_id]
+ clean = TYPE2CLEAN[field.type]
else:
- for prop in props:
- # for a given res_id, take the first property only
- id = refs.pop(prop.res_id, None)
- if id is not None:
- result[id] = prop.get_by_record()
+ return dict.fromkeys(ids, False)
+
+ # retrieve values
+ cr = self.env.cr
+ result = {}
+ refs = {"%s,%s" % (model, id) for id in ids}
+ for sub_refs in cr.split_for_in_conditions(refs):
+ cr.execute(query, params + [sub_refs])
+ result.update(cr.fetchall())
- # set the default value to the ids that are not in result
- default_value = result.pop(False, False)
+ # remove default value, add missing values, and format them
+ default = result.pop(None, None)
for id in ids:
- result.setdefault(id, default_value)
+ result[id] = clean(result.get(id, default))
return result
diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py
index 4f5fbb5ea5e..20f48fd235e 100644
--- a/odoo/addons/test_new_api/models.py
+++ b/odoo/addons/test_new_api/models.py
@@ -389,6 +389,8 @@ class CompanyDependent(models.Model):
_name = 'test_new_api.company'
foo = fields.Char(company_dependent=True)
+ date = fields.Date(company_dependent=True)
+ moment = fields.Datetime(company_dependent=True)
tag_id = fields.Many2one('test_new_api.multi.tag', company_dependent=True)
diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py
index 05e736c7361..266847481cc 100644
--- a/odoo/addons/test_new_api/tests/test_new_fields.py
+++ b/odoo/addons/test_new_api/tests/test_new_fields.py
@@ -670,20 +670,42 @@ class TestFields(common.TransactionCase):
'value': tag0, 'type': 'many2one'})
# create/modify a record, and check the value for each user
- record = self.env['test_new_api.company'].create({'foo': 'main', 'tag_id': tag1})
+ record = self.env['test_new_api.company'].create({
+ 'foo': 'main',
+ 'date': '1932-11-09',
+ 'moment': '1932-11-09 00:00:00',
+ 'tag_id': tag1.id,
+ })
record.invalidate_cache()
self.assertEqual(record.sudo(user0).foo, 'main')
self.assertEqual(record.sudo(user1).foo, 'default')
self.assertEqual(record.sudo(user2).foo, 'default')
+ self.assertEqual(record.sudo(user0).date, '1932-11-09')
+ self.assertEqual(record.sudo(user1).date, False)
+ self.assertEqual(record.sudo(user2).date, False)
+ self.assertEqual(record.sudo(user0).moment, '1932-11-09 00:00:00')
+ self.assertEqual(record.sudo(user1).moment, False)
+ self.assertEqual(record.sudo(user2).moment, False)
self.assertEqual(record.sudo(user0).tag_id, tag1)
self.assertEqual(record.sudo(user1).tag_id, tag0)
self.assertEqual(record.sudo(user2).tag_id, tag0)
- record.sudo(user1).write({'foo': 'alpha', 'tag_id': tag2.id})
+ record.sudo(user1).write({
+ 'foo': 'alpha',
+ 'date': '1932-12-10',
+ 'moment': '1932-12-10 23:59:59',
+ 'tag_id': tag2.id,
+ })
record.invalidate_cache()
self.assertEqual(record.sudo(user0).foo, 'main')
self.assertEqual(record.sudo(user1).foo, 'alpha')
self.assertEqual(record.sudo(user2).foo, 'default')
+ self.assertEqual(record.sudo(user0).date, '1932-11-09')
+ self.assertEqual(record.sudo(user1).date, '1932-12-10')
+ self.assertEqual(record.sudo(user2).date, False)
+ self.assertEqual(record.sudo(user0).moment, '1932-11-09 00:00:00')
+ self.assertEqual(record.sudo(user1).moment, '1932-12-10 23:59:59')
+ self.assertEqual(record.sudo(user2).moment, False)
self.assertEqual(record.sudo(user0).tag_id, tag1)
self.assertEqual(record.sudo(user1).tag_id, tag2)
self.assertEqual(record.sudo(user2).tag_id, tag0)
diff --git a/odoo/http.py b/odoo/http.py
index 03f41977bbc..cadf11bbd28 100644
--- a/odoo/http.py
+++ b/odoo/http.py
@@ -578,6 +578,7 @@ class JsonRequest(WebRequest):
super(JsonRequest, self).__init__(*args)
self.jsonp_handler = None
+ self.params = {}
args = self.httprequest.args
jsonp = args.get('jsonp')
diff --git a/odoo/tools/cache.py b/odoo/tools/cache.py
index a4f49831d6c..052f89545a2 100644
--- a/odoo/tools/cache.py
+++ b/odoo/tools/cache.py
@@ -205,16 +205,22 @@ def log_ormcache_stats(sig=None, frame=None):
me = threading.currentThread()
me_dbname = getattr(me, 'dbname', 'n/a')
- entries = defaultdict(int)
- for dbname, reg in Registry.registries.items():
- for key in reg.cache:
- entries[(dbname,) + key[:2]] += 1
- for key, count in sorted(entries.items()):
- dbname, model_name, method = key
+
+ for dbname, reg in sorted(Registry.registries.items()):
+ # set logger prefix to dbname
me.dbname = dbname
- stat = STAT[key]
- _logger.info("%6d entries, %6d hit, %6d miss, %6d err, %4.1f%% ratio, for %s.%s",
- count, stat.hit, stat.miss, stat.err, stat.ratio, model_name, method.__name__)
+ entries = defaultdict(int)
+ # beware: we use .keys() on purpose here (reg.cache is not a real dict)
+ for key in reg.cache.keys():
+ entries[key[:2]] += 1
+ # show entries sorted by model name, method name
+ for key in sorted(entries, key=lambda key: (key[0], key[1].__name__)):
+ model, method = key
+ stat = STAT[(dbname, model, method)]
+ _logger.info(
+ "%6d entries, %6d hit, %6d miss, %6d err, %4.1f%% ratio, for %s.%s",
+ entries[key], stat.hit, stat.miss, stat.err, stat.ratio, model, method.__name__,
+ )
me.dbname = me_dbname