diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-11-22 17:52:57 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-11-22 17:52:57 +0100 |
| commit | b09f624f20781d65baf2060df40383898e6f86e5 (patch) | |
| tree | fbaf29a0fca1ce63e616698717435fd1a8413921 /odoo | |
| parent | bab2a191d292737d1c2bc6b1650a1581614b0cc1 (diff) | |
| parent | 263b388c5045bebc77cc27847f7500784f63c7f5 (diff) | |
[MERGE] forward port branch 11.0 up to 263b388c504
Diffstat (limited to 'odoo')
| -rw-r--r-- | odoo/addons/base/data/res.country.state.csv | 2 | ||||
| -rw-r--r-- | odoo/addons/base/models/ir_actions_report.py | 14 | ||||
| -rw-r--r-- | odoo/addons/base/models/ir_property.py | 97 | ||||
| -rw-r--r-- | odoo/addons/test_new_api/models.py | 2 | ||||
| -rw-r--r-- | odoo/addons/test_new_api/tests/test_new_fields.py | 26 | ||||
| -rw-r--r-- | odoo/http.py | 1 | ||||
| -rw-r--r-- | odoo/tools/cache.py | 24 |
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 |
