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: