changeset 1e0aeb0854b5 in sao:5.0
details: https://hg.tryton.org/sao?cmd=changeset;node=1e0aeb0854b5
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 c15b1ead26db -r 1e0aeb0854b5 src/common.js
--- a/src/common.js     Wed Nov 28 10:01:32 2018 +0100
+++ b/src/common.js     Thu Dec 20 18:44:31 2018 +0100
@@ -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;
diff -r c15b1ead26db -r 1e0aeb0854b5 src/model.js
--- a/src/model.js      Wed Nov 28 10:01:32 2018 +0100
+++ b/src/model.js      Thu Dec 20 18:44:31 2018 +0100
@@ -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) {
diff -r c15b1ead26db -r 1e0aeb0854b5 tests/sao.js
--- a/tests/sao.js      Wed Nov 28 10:01:32 2018 +0100
+++ b/tests/sao.js      Thu Dec 20 18:44:31 2018 +0100
@@ -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({

Reply via email to