diff --git a/addons/crm/report/crm_opportunity_report_views.xml b/addons/crm/report/crm_opportunity_report_views.xml
index b97a0f6fc14..b6dbedda40b 100644
--- a/addons/crm/report/crm_opportunity_report_views.xml
+++ b/addons/crm/report/crm_opportunity_report_views.xml
@@ -36,6 +36,7 @@
+
@@ -48,6 +49,7 @@
+
diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml
index 0f0d55f1e75..1291ef671b9 100644
--- a/addons/crm/views/crm_lead_views.xml
+++ b/addons/crm/views/crm_lead_views.xml
@@ -746,6 +746,7 @@
+
diff --git a/addons/crm_iap_lead_website/views/crm_lead_view.xml b/addons/crm_iap_lead_website/views/crm_lead_view.xml
index f63d55f8a47..5bb287a5163 100644
--- a/addons/crm_iap_lead_website/views/crm_lead_view.xml
+++ b/addons/crm_iap_lead_website/views/crm_lead_view.xml
@@ -22,4 +22,48 @@
+
+
+ crm.lead.view.pivot.inherit.lead.website
+ crm.lead
+
+
+
+
+
+
+
+
+
+ crm.lead.view.graph.inherit.lead.website
+ crm.lead
+
+
+
+
+
+
+
+
+
+ crm.lead.view.graph.report.opportunity.inherit.lead.website
+ crm.lead
+
+
+
+
+
+
+
+
+
+ crm.lead.view.graph.report.lead.inherit.lead.website
+ crm.lead
+
+
+
+
+
+
+
diff --git a/addons/web/static/src/js/views/graph/graph_view.js b/addons/web/static/src/js/views/graph/graph_view.js
index 5293409cb8b..759817c898f 100644
--- a/addons/web/static/src/js/views/graph/graph_view.js
+++ b/addons/web/static/src/js/views/graph/graph_view.js
@@ -43,7 +43,7 @@ var GraphView = AbstractView.extend({
let measure;
const measures = {};
const measureStrings = {};
- const groupBys = [];
+ let groupBys = [];
const groupableFields = {};
this.fields.__count__ = { string: _t("Count"), type: 'integer' };
@@ -100,6 +100,20 @@ var GraphView = AbstractView.extend({
}
}
+ // Remove invisible fields from the measures
+ this.arch.children.forEach(field => {
+ let fieldName = field.attrs.name;
+ if (field.attrs.invisible && py.eval(field.attrs.invisible)) {
+ groupBys = groupBys.filter(groupBy => groupBy !== fieldName);
+ if (fieldName in groupableFields) {
+ delete groupableFields[fieldName];
+ }
+ if (!additionalMeasures.includes(fieldName)) {
+ delete measures[fieldName];
+ }
+ }
+ });
+
const sortedMeasures = Object.values(measures).sort((a, b) => {
const descA = a.description.toLowerCase();
const descB = b.description.toLowerCase();
diff --git a/addons/web/static/src/js/views/pivot/pivot_view.js b/addons/web/static/src/js/views/pivot/pivot_view.js
index 7c021d6e3c0..ea3ab9c7442 100644
--- a/addons/web/static/src/js/views/pivot/pivot_view.js
+++ b/addons/web/static/src/js/views/pivot/pivot_view.js
@@ -67,11 +67,15 @@ odoo.define('web.PivotView', function (require) {
this.arch.children.forEach(field => {
let name = field.attrs.name;
-
- // Remove invisible fields from the measures
+ // Remove invisible fields from the measures if not in additionalMeasures
if (field.attrs.invisible && py.eval(field.attrs.invisible)) {
- delete measures[name];
- return;
+ if (name in groupableFields) {
+ delete groupableFields[name];
+ }
+ if (!additionalMeasures.includes(name)) {
+ delete measures[name];
+ return;
+ }
}
if (field.attrs.interval) {
name += ':' + field.attrs.interval;
diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js
index 253c98d706a..fda4c5cb190 100644
--- a/addons/web/static/tests/views/graph_tests.js
+++ b/addons/web/static/tests/views/graph_tests.js
@@ -97,16 +97,17 @@ QUnit.module('Views', {
product_id: {string: "Product", type: "many2one", relation: 'product', store: true},
color_id: {string: "Color", type: "many2one", relation: 'color'},
date: {string: "Date", type: 'date', store: true, sortable: true},
+ revenue: {string: "Revenue", type: 'integer', store: true},
},
records: [
- {id: 1, foo: 3, bar: true, product_id: 37, date: "2016-01-01"},
- {id: 2, foo: 53, bar: true, product_id: 37, color_id: 7, date: "2016-01-03"},
- {id: 3, foo: 2, bar: true, product_id: 37, date: "2016-03-04"},
- {id: 4, foo: 24, bar: false, product_id: 37, date: "2016-03-07"},
- {id: 5, foo: 4, bar: false, product_id: 41, date: "2016-05-01"},
+ {id: 1, foo: 3, bar: true, product_id: 37, date: "2016-01-01", revenue: 1},
+ {id: 2, foo: 53, bar: true, product_id: 37, color_id: 7, date: "2016-01-03", revenue: 2},
+ {id: 3, foo: 2, bar: true, product_id: 37, date: "2016-03-04", revenue: 3},
+ {id: 4, foo: 24, bar: false, product_id: 37, date: "2016-03-07", revenue: 4},
+ {id: 5, foo: 4, bar: false, product_id: 41, date: "2016-05-01", revenue: 5},
{id: 6, foo: 63, bar: false, product_id: 41},
{id: 7, foo: 42, bar: false, product_id: 41},
- {id: 8, foo: 48, bar: false, product_id: 41, date: "2016-04-01"},
+ {id: 8, foo: 48, bar: false, product_id: 41, date: "2016-04-01", revenue: 8},
]
},
product: {
@@ -1216,6 +1217,47 @@ QUnit.module('Views', {
graph.destroy();
});
+ QUnit.test('graph view without invisible attribute on field', async function (assert) {
+ assert.expect(4);
+
+ const graph = await createView({
+ View: GraphView,
+ model: "foo",
+ data: this.data,
+ arch: ``,
+ });
+
+ await testUtils.dom.click(graph.$('.btn-group:first button'));
+ assert.containsN(graph, 'li.o_menu_item', 3,
+ "there should be three menu item in the measures dropdown (count, revenue and foo)");
+ assert.containsOnce(graph, 'li.o_menu_item a:contains("Revenue")');
+ assert.containsOnce(graph, 'li.o_menu_item a:contains("Foo")');
+ assert.containsOnce(graph, 'li.o_menu_item a:contains("Count")');
+
+ graph.destroy();
+ });
+
+ QUnit.test('graph view with invisible attribute on field', async function (assert) {
+ assert.expect(2);
+
+ const graph = await createView({
+ View: GraphView,
+ model: "foo",
+ data: this.data,
+ arch: `
+
+
+ `,
+ });
+
+ await testUtils.dom.click(graph.$('.btn-group:first button'));
+ assert.containsN(graph, 'li.o_menu_item', 2,
+ "there should be only two menu item in the measures dropdown (count and foo)");
+ assert.containsNone(graph, 'li.o_menu_item a:contains("Revenue")');
+
+ graph.destroy();
+ });
+
QUnit.test('graph view sort by measure', async function (assert) {
assert.expect(18);
diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js
index 48e67e8641e..026741ac682 100644
--- a/addons/web/static/tests/views/pivot_tests.js
+++ b/addons/web/static/tests/views/pivot_tests.js
@@ -192,7 +192,7 @@ QUnit.module('Views', {
});
QUnit.test('pivot rendering with invisible attribute on field', async function (assert) {
- assert.expect(2);
+ assert.expect(3);
// when invisible, a field should neither be an active measure,
// nor be a selectable measure.
_.extend(this.data.partner.fields, {
@@ -214,6 +214,9 @@ QUnit.module('Views', {
assert.containsOnce(pivot, '.o_pivot_measure_row');
// there should be only one measure besides count, as the other one is invisible
assert.containsN(pivot, '.o_cp_bottom_left .dropdown-item', 2);
+ // the invisible field souldn't be in the groupable fields neither
+ await testUtils.dom.click(pivot.$('.o_pivot_header_cell_closed:first'));
+ assert.containsNone(pivot, '.o_pivot_field_menu a[data-field="foo2"]');
pivot.destroy();
});
diff --git a/addons/website_crm_partner_assign/views/crm_lead_views.xml b/addons/website_crm_partner_assign/views/crm_lead_views.xml
index 89a564c0985..4645c09afda 100644
--- a/addons/website_crm_partner_assign/views/crm_lead_views.xml
+++ b/addons/website_crm_partner_assign/views/crm_lead_views.xml
@@ -89,4 +89,51 @@
+
+ crm.lead.view.pivot.inherit.partner.assign
+ crm.lead
+
+
+
+
+
+
+
+
+
+
+ crm.lead.view.graph.inherit.partner.assign
+ crm.lead
+
+
+
+
+
+
+
+
+
+
+ crm.lead.view.graph.report.opportunity.inherit.partner.assign
+ crm.lead
+
+
+
+
+
+
+
+
+
+
+ crm.lead.view.graph.report.lead.inherit.partner.assign
+ crm.lead
+
+
+
+
+
+
+
+
diff --git a/doc/reference/views.rst b/doc/reference/views.rst
index a336af9dbf6..1ad8253b3f1 100644
--- a/doc/reference/views.rst
+++ b/doc/reference/views.rst
@@ -497,6 +497,19 @@ attributes:
A field that can be aggregated. This field will be used to compute the values
for each cell. If not set, the cohort view will count the number of occurrences.
+```` (optional)
+ allows to specify a particular field in order to manage it from the available measures, it's
+ main use is for hiding a field from the selectable measures:
+ * ``name`` (required)
+ the name of the field to use in the view.
+ * ``string`` (optional)
+ the name that would be used to display the field in the cohort view, overrides the
+ default python String attribute of the field.
+ * ``invisible`` (optional)
+ if true, the field will not appear either in the active measures nor in the selectable
+ measures (useful for fields that do not make sense aggregated, such as fields in different
+ units, e.g. € and $).
+
.. _reference/views/dashboard:
Dashboard
@@ -1109,6 +1122,10 @@ following attributes:
``title`` (optional)
string displayed on the top of the graph.
+``invisible`` (optional)
+ if true, the field will not appear either in the active measures nor in the
+ selectable measures.
+
``type``
indicates whether the field should be used as a grouping criteria or as an
aggregated value within a group. Possible values are: