changeset 71661984d777 in sao:4.6 details: https://hg.tryton.org/sao?cmd=changeset;node=71661984d777 description: Fix domain inversion of child_of mixing M2O and Reference fields
Domain inversion on Reference field does not work when using the dotted notation with a M2O field using child_of or parent_of. To solve this we correctly compute the localization of child_of leaves when using the dotted notation (which renders the inverse_leaf function useless). But we must also ensure that the selection used by reference fields restrict the choice to the right models. issue7869 review60441002 (grafted from 95501e406c46691362dd211e5883f8e62c59e856) diffstat: src/common.js | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/model.js | 17 +++++++++-- tests/sao.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 11 deletions(-) diffs (246 lines): diff -r 843bb22b8778 -r 71661984d777 src/common.js --- a/src/common.js Wed Nov 28 09:54:15 2018 +0100 +++ b/src/common.js Thu Dec 20 18:44:31 2018 +0100 @@ -622,11 +622,6 @@ return; } var domain = field.get_domain(record); - if (field.description.type == 'reference') { - // The domain on reference field is not only based on the - // selection so the selection can not be filtered. - domain = []; - } if (!('relation' in this.attributes)) { var change_with = this.attributes.selection_change_with || []; var value = record._get_on_change_args(change_with); @@ -691,12 +686,29 @@ if (jQuery.isEmptyObject(domain)) { return; } + var inversion = new Sao.common.DomainInversion(); - this.selection = this.selection.filter(function(value) { + var _value_evaluator = function(value) { var context = {}; context[this.field_name] = value[0]; return inversion.eval_domain(domain, context); - }.bind(this)); + }.bind(this); + + var _model_evaluator = function(allowed_models) { + return function(value) { + return allowed_models.includes(value[0]); + }; + }; + + var evaluator; + if (field.description.type == 'reference') { + var allowed_models = field.get_models(record); + evaluator = _model_evaluator(allowed_models); + } else { + evaluator = _value_evaluator; + } + + this.selection = this.selection.filter(evaluator); }; Sao.common.selection_mixin.get_inactive_selection = function(value) { if (!this.attributes.relation) { @@ -2176,6 +2188,10 @@ return domain; } else if (this.is_leaf(domain)) { if (domain[1].contains('child_of')) { + if (domain[0].split('.').length > 1) { + var target = domain[0].split('.').slice(1).join('.'); + return [target].concat(domain.slice(1)); + } if (domain.length == 3) { return domain; } else { @@ -2195,6 +2211,57 @@ }.bind(this)); } }, + prepare_reference_domain: function(domain, reference) { + if (~['AND', 'OR'].indexOf(domain)) { + return domain; + } else if (this.is_leaf(domain)) { + if ((domain[0].split('.').length > 1) && + (domain.length > 3)) { + var parts = domain[0].split('.'); + var local_name = parts[0]; + var target_name = parts.slice(1).join('.'); + + if (local_name == reference) { + var where = []; + where.push(target_name); + where = where.concat( + domain.slice(1, 3), domain.slice(4)); + return where; + } + return domain; + } + return domain; + } else { + return domain.map(function(d) { + return this.prepare_reference_domain(d, reference); + }.bind(this)); + } + }, + extract_reference_models: function(domain, field_name) { + if (~['AND', 'OR'].indexOf(domain)) { + return []; + } else if (this.is_leaf(domain)) { + var local_part = domain[0].split('.', 1)[0]; + if ((local_part == field_name) && + (domain.length > 3)) { + return [domain[3]]; + } + return []; + } else { + var models = []; + domain.map(function(d) { + var new_models = this.extract_reference_models( + d, field_name); + for (var i=0, len=new_models.length; i < len; i++) { + var model = new_models[i]; + if (!models.includes(model)) { + models.push(model); + } + } + }.bind(this)); + return models; + } + }, simplify: function(domain) { if (this.is_leaf(domain)) { return domain; diff -r 843bb22b8778 -r 71661984d777 src/model.js --- a/src/model.js Wed Nov 28 09:54:15 2018 +0100 +++ b/src/model.js Thu Dec 20 18:44:31 2018 +0100 @@ -1869,8 +1869,8 @@ var screen_domain = domains[0]; var attr_domain = domains[1]; var inversion = new Sao.common.DomainInversion(); - return inversion.concat([inversion.localize_domain( - inversion.inverse_leaf(screen_domain), this.name), + return inversion.concat([ + inversion.localize_domain(screen_domain, this.name), attr_domain]); }, get_on_change_value: function(record) { @@ -2398,10 +2398,19 @@ var screen_domain = domains[0]; var attr_domain = domains[1]; var inversion = new Sao.common.DomainInversion(); + screen_domain = inversion.prepare_reference_domain( + screen_domain, this.name); return inversion.concat([inversion.localize_domain( inversion.filter_leaf(screen_domain, this.name, model), true), attr_domain]); }, + get_models: function(record) { + var domains = this.get_domains(record); + var inversion = new Sao.common.DomainInversion(); + return inversion.extract_reference_models( + inversion.concat(domains[0], domains[1]), + this.name); + }, _is_empty: function(record) { var result = Sao.field.Reference._super._is_empty.call( this, record); @@ -2473,8 +2482,8 @@ var domains = this.get_domains(record); var screen_domain = domains[0]; var attr_domain = domains[1]; - return inversion.concat([inversion.localize_domain( - inversion.inverse_leaf(screen_domain)), + return inversion.concat([ + inversion.localize_domain(screen_domain), attr_domain]); }, date_format: function(record) { diff -r 843bb22b8778 -r 71661984d777 tests/sao.js --- a/tests/sao.js Wed Nov 28 09:54:15 2018 +0100 +++ b/tests/sao.js Thu Dec 20 18:44:31 2018 +0100 @@ -2249,6 +2249,18 @@ [['x', 'child_of', [1]]]), 'localize_domain(' + JSON.stringify(domain) + ', \'x\')'); + domain = [['x.y', 'child_of', [1], 'parent']]; + QUnit.ok(compare( + localize_domain(domain, 'x'), + [['y', 'child_of', [1], 'parent']]), + 'localize_domain(' + JSON.stringify(domain) + ', \'x\')'); + + domain = [['x.y.z', 'child_of', [1], 'parent', 'model']]; + QUnit.ok(compare( + localize_domain(domain, 'x'), + [['y.z', 'child_of', [1], 'parent', 'model']]), + 'localize_domain(' + JSON.stringify(domain) + ', \'x\')'); + domain = [['x', 'child_of', [1], 'y']]; QUnit.ok(compare(localize_domain(domain, 'x'), [['y', 'child_of', [1]]]), @@ -2272,6 +2284,62 @@ }); + QUnit.test('DomainInversion.prepare_reference_domain', function() { + var domain_inversion = new Sao.common.DomainInversion(); + var prepare_reference_domain = domain_inversion + .prepare_reference_domain.bind(domain_inversion); + var compare = Sao.common.compare; + + var domain = [['x', 'like', 'A%']]; + QUnit.ok(compare( + prepare_reference_domain(domain, 'x'), + [['x', 'like', 'A%']])); + + domain = [['x.y', 'like', 'A%', 'model']]; + QUnit.ok(compare( + prepare_reference_domain(domain, 'x'), + [['y', 'like', 'A%']])); + + domain = [['x.y', 'child_of', [1], 'model', 'parent']]; + QUnit.ok(compare( + prepare_reference_domain(domain, 'x'), + [['y', 'child_of', [1], 'parent']])); + }); + + QUnit.test('DomainInversion.extract_reference_models', function() { + var domain_inversion = new Sao.common.DomainInversion(); + var extract_models = domain_inversion + .extract_reference_models.bind(domain_inversion); + var compare = Sao.common.compare; + + var domain = [['x', 'like', 'A%']]; + QUnit.ok(compare( + extract_reference_models(domain, 'x'), + [])); + QUnit.ok(compare( + extract_reference_models(domain, 'y'), + [])); + + domain = [['x', 'like', 'A%', 'model']]; + QUnit.ok(compare( + extract_reference_models(domain, 'x'), + ['model'])); + QUnit.ok(compare( + extract_reference_models(domain, 'y'), + [])); + + domain = ['OR', + ['x', 'like', 'A%', 'model_A'], + ['x', 'like', 'B%', 'model_B'] + ]; + QUnit.ok(compare( + extract_reference_models(domain, 'x'), + ['model_A', 'model_B'])); + QUnit.ok(compare( + extract_reference_models(domain, 'y'), + [])); + }); + QUnit.test('DomainParser.completion', function() { var compare = Sao.common.compare; var parser = new Sao.common.DomainParser({