From 7618f84beb3e3252f0e62de0650d4bcb33398b29 Mon Sep 17 00:00:00 2001 From: Mathieu Duckerts-Antoine Date: Mon, 5 Nov 2018 13:17:46 +0000 Subject: [PATCH] [FIX] web: sort pivot rows in comparison mode Before this commit, it was not possible to sort the rows of a pivot view while in comparison mode. This fix makes it now possible. Note that in comparison mode, a click on a header of type "measure" will sort the rows according to the column values coming from the data of interest. closes odoo/odoo#28411 --- .../src/js/views/pivot/pivot_controller.js | 3 +- .../static/src/js/views/pivot/pivot_model.js | 33 +++- .../src/js/views/pivot/pivot_renderer.js | 29 +++- addons/web/static/tests/views/pivot_tests.js | 144 +++++++++++++++++- 4 files changed, 198 insertions(+), 11 deletions(-) diff --git a/addons/web/static/src/js/views/pivot/pivot_controller.js b/addons/web/static/src/js/views/pivot/pivot_controller.js index 48b5fb033fa..a573a6fa4cb 100644 --- a/addons/web/static/src/js/views/pivot/pivot_controller.js +++ b/addons/web/static/src/js/views/pivot/pivot_controller.js @@ -336,7 +336,8 @@ var PivotController = AbstractController.extend({ var col_id = $target.data('id'); var measure = $target.data('measure'); var isAscending = $target.hasClass('o_pivot_measure_row_sorted_asc'); - this.model.sortRows(col_id, measure, isAscending); + var dataType = $target.data('data_type'); + this.model.sortRows(col_id, measure, isAscending, dataType); this.update({}, {reload: false}); }, /** diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js index 1a0d3625440..5a6423fbe34 100644 --- a/addons/web/static/src/js/views/pivot/pivot_model.js +++ b/addons/web/static/src/js/views/pivot/pivot_model.js @@ -457,16 +457,23 @@ var PivotModel = AbstractModel.extend({ * @param {any} col_id * @param {any} measure * @param {any} descending + * @param {'data'|'comparisonData'|'variation'} [dataType] */ - sortRows: function (col_id, measure, descending) { + sortRows: function (col_id, measure, descending, dataType) { var cells = this.data.cells; + var comparisonFunction = compare; + if (this.data.compare) { + dataType = dataType || 'data'; + comparisonFunction = specialCompare; + } this._traverseTree(this.data.main_row.root, function (header) { - header.children.sort(compare); + header.children.sort(comparisonFunction); }); this.data.sorted_column = { id: col_id, measure: measure, order: descending ? 'desc' : 'asc', + dataType: dataType, }; function _getValue (id1, id2) { if ((id1 in cells) && (id2 in cells[id1])) { @@ -476,12 +483,26 @@ var PivotModel = AbstractModel.extend({ } function compare (row1, row2) { - var values1 = _getValue(row1.id, col_id), - values2 = _getValue(row2.id, col_id), - value1 = values1 ? values1[measure] : 0, - value2 = values2 ? values2[measure] : 0; + var values1 = _getValue(row1.id, col_id); + var values2 = _getValue(row2.id, col_id); + var value1 = values1 ? values1[measure] : 0; + var value2 = values2 ? values2[measure] : 0; return descending ? value1 - value2 : value2 - value1; } + function specialCompare (row1, row2) { + var values1 = _getValue(row1.id, col_id); + var values2 = _getValue(row2.id, col_id); + var value1 = values1 ? values1[measure] : {data: 0, comparisonData: 0, variation: {magnitude: 0}}; + var value2 = values2 ? values2[measure] : {data: 0, comparisonData: 0, variation: {magnitude: 0}}; + if (dataType === 'variation') { + return descending ? + value1[dataType].magnitude - value2[dataType].magnitude: + value2[dataType].magnitude - value1[dataType].magnitude; + } + return descending ? + value1[dataType] - value2[dataType]: + value2[dataType] - value1[dataType]; + } }, /** * Toggle the active state for a given measure, then reload the data. diff --git a/addons/web/static/src/js/views/pivot/pivot_renderer.js b/addons/web/static/src/js/views/pivot/pivot_renderer.js index 68f2f4bf86d..d49550ab81e 100644 --- a/addons/web/static/src/js/views/pivot/pivot_renderer.js +++ b/addons/web/static/src/js/views/pivot/pivot_renderer.js @@ -116,6 +116,8 @@ var PivotRenderer = AbstractRenderer.extend({ _renderHeaders: function ($thead, headers, nbrCols) { var self = this; var i, j, cell, $row, $cell; + var measure, dataType; + var id, measureCellIds = []; var groupbyLabels = _.map(this.state.colGroupBys, function (gb) { return self.state.fields[gb.split(':')[0]].string; @@ -144,10 +146,13 @@ var PivotRenderer = AbstractRenderer.extend({ $cell.data('id', cell.id); } if (cell.measure) { + measure = cell.measure; + measureCellIds.push(cell.id); $cell.addClass('o_pivot_measure_row text-muted') - .text(this.state.fields[cell.measure].string); - $cell.data('id', cell.id).data('measure', cell.measure); - if (!this.compare && cell.id === this.state.sortedColumn.id && cell.measure === this.state.sortedColumn.measure) { + .text(this.state.fields[measure].string); + $cell.data('id', cell.id).data('measure', measure); + if (cell.id === this.state.sortedColumn.id && + measure === this.state.sortedColumn.measure) { $cell.addClass('o_pivot_measure_row_sorted_' + this.state.sortedColumn.order); if (this.state.sortedColumn.order == 'asc') { $cell.attr('aria-sorted', 'ascending'); @@ -167,12 +172,30 @@ var PivotRenderer = AbstractRenderer.extend({ } if (this.compare) { var colLabels = [this.timeRangeDescription, this.comparisonTimeRangeDescription, 'Variation']; + var dataTypes = ['data', 'comparisonData', 'variation']; $row = $(''); for (i = 0; i < 3 * nbrCols; i++) { + id = measureCellIds[~~(i / 3)]; + measure = this.state.measures[(~~(i / 3)) % this.state.measures.length]; + dataType = dataTypes[i % 3]; $cell = $('') + .addClass('o_pivot_measure_row text-muted') + .data('data_type', dataType) + .data('id', id) + .data('measure', measure) .text(colLabels[i % 3]) .attr('rowspan', 1) .attr('colspan', 1); + if (dataType === this.state.sortedColumn.dataType && + id === this.state.sortedColumn.id && + measure === this.state.sortedColumn.measure) { + $cell.addClass('o_pivot_measure_row_sorted_' + this.state.sortedColumn.order); + if (this.state.sortedColumn.order === 'asc') { + $cell.attr('aria-sorted', 'ascending'); + } else { + $cell.attr('aria-sorted', 'descending'); + } + } $row.append($cell); } $thead.append($row); diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js index 8642a1e8e35..a665f91af10 100644 --- a/addons/web/static/tests/views/pivot_tests.js +++ b/addons/web/static/tests/views/pivot_tests.js @@ -1417,7 +1417,7 @@ QUnit.module('Views', { actionManager.destroy(); }); - QUnit.test('export data in excel with comparison', function (assert) { + QUnit.test('export data in excel with comparison', function (assert) { assert.expect(10); this.data.partner.records[0].date = '2016-12-15'; @@ -1572,5 +1572,147 @@ QUnit.module('Views', { unpatchDate(); actionManager.destroy(); }); + + QUnit.module('Sort in comparison mode', { + beforeEach: function () { + this.data.partner.records[0].date = '2016-12-15'; + this.data.partner.records[1].date = '2016-12-17'; + this.data.partner.records[2].date = '2016-11-22'; + this.data.partner.records[3].date = '2016-11-03'; + + this.data.partner.fields.company_type = {string: "Company Type", type: "selection", selection: [["company", "Company"], ["individual", "individual"]], searchable: true, store: true, sortable: true}; + + this.data.partner.records[0].company_type = 'company'; + this.data.partner.records[1].company_type = 'individual'; + this.data.partner.records[2].company_type = 'company'; + this.data.partner.records[3].company_type = 'individual'; + + + this.unpatchDate = patchDate(2016, 11, 20, 1, 0, 0); + + this.actualResult = function () { + var actualResult = $('.o_pivot .o_pivot_cell_value div').map(function() { + return $( this ).text(); + }).get().join(); + return actualResult; + }; + + // create an action manager to test the interactions with the search view + this.actionManager = createActionManager({ + data: this.data, + archs: { + 'partner,false,pivot': '' + + '' + + '' + + '' + + '', + 'partner,false,search': '', + }, + debug: 1, + }); + + this.actionManager.doAction({ + res_model: 'partner', + type: 'ir.actions.act_window', + views: [[false, 'pivot']], + flags: { + pivot: { + additionalMeasures: ['product_id'], + } + } + }); + + // open time range menu + testUtils.dom.click($('.o_control_panel .o_time_range_menu_button')); + // select 'Today' as range + testUtils.fields.editInput($('.o_control_panel .o_time_range_selector'), 'this_month'); + // check checkbox 'Compare To' + testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); + // Click on 'Apply' button + testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range')); + // We are in comparison mode + }, + afterEach: function () { + this.unpatchDate(); + this.actionManager.destroy(); + }, + }, function () { + QUnit.test('when clicking on measure, sort by "This Month" (period of interest)', function (assert) { + assert.expect(1); + + // click on 'Foo' in column Total/Company + testUtils.dom.click($('.o_pivot_measure_row').eq(0)); + var results = [ + "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", + "12", "0", "100%", "12", "0" , "100%", + "1", "0", "100%", "1" , "0", "100%", + "0", "17", "-100%", "0", "17", "-100%", + "0", "2", "-100%", "0" , "2" , "-100%" + ]; + assert.strictEqual(this.actualResult(), results.join()); + }); + + QUnit.test( + 'click on a period of interest header sort according to the appropriate column ' + + 'first in ascending order then in descending order', + function (assert) { + assert.expect(2); + + // click on 'This Month' in column Total/Individual/Foo + testUtils.dom.click($('.o_pivot_measure_row').eq(6)); + var results = [ + "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", + "1", "0", "100%", "1" , "0", "100%", + "12", "0", "100%", "12", "0" , "100%", + "0", "17", "-100%", "0", "17", "-100%", + "0", "2", "-100%", "0" , "2" , "-100%" + ]; + var actualResult = $('.o_pivot .o_pivot_cell_value div').text(); + assert.strictEqual(actualResult, results.join('')); + + // click once again on 'This Month' in column Total/Individual/Foo + testUtils.dom.click($('.o_pivot_measure_row').eq(6)); + results = [ + "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", + "12", "0", "100%", "12", "0" , "100%", + "0", "17", "-100%", "0", "17", "-100%", + "0", "2", "-100%", "0" , "2" , "-100%", + "1", "0", "100%", "1" , "0", "100%" + ]; + assert.strictEqual(this.actualResult(), results.join()); + }); + + QUnit.test('click on a period of comparison header sort according to appropriate column', + function (assert) { + assert.expect(1); + + // click on 'Previous Period' in column Total/Individual/Foo + testUtils.dom.click($('.o_pivot_measure_row').eq(7)); + var results = [ + "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", + "0", "2", "-100%", "0" , "2" , "-100%", + "12", "0", "100%", "12", "0" , "100%", + "1", "0", "100%", "1" , "0", "100%", + "0", "17", "-100%", "0", "17", "-100%" + ]; + assert.strictEqual(this.actualResult(), results.join()); + }); + + QUnit.test('click on a variation header sort according to appropriate column', + function (assert) { + assert.expect(1); + + // click on 'Variation' in column Total/Individual/Foo + testUtils.dom.click($('.o_pivot_measure_row').eq(11)); + var results = [ + "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", + "12", "0", "100%", "12", "0" , "100%", + "1", "0", "100%", "1" , "0", "100%", + "0", "17", "-100%", "0", "17", "-100%", + "0", "2", "-100%", "0" , "2" , "-100%" + ]; + assert.strictEqual(this.actualResult(), results.join()); + }); + }); }); });