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
This commit is contained in:
Nicolas Évrard
2018-12-20 18:44:31 +01:00
parent 47026d0076
commit 5798cf5cbc
3 changed files with 155 additions and 11 deletions
+74 -7
View File
@@ -638,11 +638,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);
@@ -707,12 +702,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) {
@@ -2199,6 +2211,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 {
@@ -2218,6 +2234,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;
+13 -4
View File
@@ -1911,8 +1911,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) {
@@ -2442,10 +2442,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);
@@ -2522,8 +2531,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) {
+68
View File
@@ -2344,6 +2344,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]]]),
@@ -2367,6 +2379,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({