summaryrefslogtreecommitdiff
path: root/addons/web/tests
diff options
context:
space:
mode:
authorOdoo's Mergebot <xmo+roboto@odoo.com>2019-09-20 17:13:47 +0200
committerGitHub <noreply@github.com>2019-09-20 17:13:47 +0200
commitf1aa96b0a8120e7adfb9ef217c70c2b3f4a991bc (patch)
treecf9562a69cb67c5c05a7077c7e31b758b7034521 /addons/web/tests
parent3e21daaf457919087000e430e9ab1ba0ab93902b (diff)
parent5c4544fb2943e63fc1e0f5ae1e7e250a5a2b2cf1 (diff)
[MERGE] web: Re-implement the XLS grouped export
Purpose ======= The commit 2849b5c introduces a new export mechanism of grouped list views to xls files. The issue with this development is mainly that the displayed records are exported, instead of all the records that match the search parameters. To export all the records we cannot rely on the data from the web client. This implies to revert 2849b5c, and implement it in a better way. Functional Spec =============== Add the support of grouped exports. Allow the user to export all records in one click from the listview, without having to go through the export modal, taking into account the domain, groupbys, and visible fields. Technical Spec ============== When exporting (whether it is from the modal or from the shortcut), any groupby(s) set on the listview should be taken into account (all unfolded) - UNLESS the export is import-compatible - each subgroup header has an indentation compared to its parent - the 'group headers' in the exported file should contain the same info (label, field aggregates) as it has in the listview. New secondary button on the tree view with label 'EXPORT' (to be confirmed...) - the export shortcut disregard the selected records, it exports all records according to the domain. - the button is visible even if there is no selected records. - essentially the export shortcut does the same thing as the following: - select all records - hit 'action' then 'export' - hit 'export' Define a boolean attribute on <tree> to specify whether or not the export shortcut should be displayed Task 2072910 closes odoo/odoo#37087 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Diffstat (limited to 'addons/web/tests')
-rw-r--r--addons/web/tests/__init__.py2
-rw-r--r--addons/web/tests/test_export.py176
-rw-r--r--addons/web/tests/test_list_controller.py75
3 files changed, 177 insertions, 76 deletions
diff --git a/addons/web/tests/__init__.py b/addons/web/tests/__init__.py
index 690fab494d3..b479a574e46 100644
--- a/addons/web/tests/__init__.py
+++ b/addons/web/tests/__init__.py
@@ -6,4 +6,4 @@ from . import test_js
from . import test_menu
from . import test_serving_base
from . import test_click_everywhere
-from . import test_list_controller
+from . import test_export
diff --git a/addons/web/tests/test_export.py b/addons/web/tests/test_export.py
new file mode 100644
index 00000000000..b0fed393e10
--- /dev/null
+++ b/addons/web/tests/test_export.py
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from unittest.mock import patch
+import json
+from odoo import http
+from odoo.tests import common, new_test_user
+from odoo.addons.web.controllers.main import ExportXlsxWriter
+
+
+class TestExport(common.HttpCase):
+
+ def setUp(self):
+ super().setUp()
+
+ # Archive demo partners
+ self.env['res.users'].search([]).active = False
+ self.env['res.partner'].search([]).active = False
+ new_test_user(self.env, login='fef', password='pwd')
+ self.authenticate('fef', 'pwd')
+
+ self.env['res.partner'].create([{
+ 'name': 'partner 1',
+ 'comment': 'yop',
+ 'website': 'yop.com',
+ 'credit_limit': 0,
+ },{
+ 'name': 'partner 2',
+ 'comment': 'yop',
+ 'website': 'blop.com',
+ 'credit_limit': 3,
+ },{
+ 'name': 'partner 3',
+ 'comment': 'yop',
+ 'website': 'blop.com',
+ 'credit_limit': 1,
+ }, {
+ 'name': 'partner 4',
+ 'comment': 'blop',
+ 'website': 'blop.com',
+ 'credit_limit': 2,
+ }])
+
+ self.worksheet = {} # mock worksheet
+
+ self.default_params = {
+ 'domain': [],
+ 'fields': [{
+ 'label': "Partner name",
+ 'name': 'name',
+ }, {
+ 'label': "Comment",
+ 'name': "comment",
+ }, {
+ 'label': 'Website',
+ 'name': 'website',
+ }],
+ 'groupby': [],
+ 'ids': False,
+ 'import_compat': False,
+ 'model': 'res.partner',
+ }
+
+ def mock_write(self, row, column, value, style=None):
+ self.worksheet[row, column] = value
+
+ def test_grouped_list_export(self):
+
+ with patch.object(ExportXlsxWriter, 'write', self.mock_write):
+ self.default_params['groupby'] = ['comment', 'website']
+ params = dict(self.default_params, **{
+ 'groupby': ['comment', 'website'],
+ 'fields': [*self.default_params['fields'], {'label': "Credit Limit", 'name': 'credit_limit'}]
+ })
+ self.url_open('/web/export/xlsx', data={
+ 'data': json.dumps(params),
+ 'token': 'dummy',
+ 'csrf_token': http.WebRequest.csrf_token(self),
+ })
+
+ # Main header
+ self.assertEqual(self.worksheet[0, 0], "Partner name", "It should display the list header")
+ self.assertEqual(self.worksheet[0, 1], "Comment", "It should display the list header")
+ self.assertEqual(self.worksheet[0, 2], "Website", "It should display the list header")
+ self.assertEqual(self.worksheet[0, 3], "Credit Limit", "It should display the list header")
+
+ # Header: Group Comment=blop
+ self.assertEqual(self.worksheet[1, 0], "blop (1)", "It should display the group header")
+ self.assertEqual(self.worksheet[1, 3], 2, "It should display the aggregated value")
+
+ # Header: Group Comment=blop > Website=http://blop.com
+ self.assertEqual(self.worksheet[2, 0], " http://blop.com (1)", "It should display the group header")
+ self.assertEqual(self.worksheet[2, 3], 2, "It should display the aggregated value")
+
+ # Data: Group Comment=blop > Website=http://blop.com
+ self.assertEqual(self.worksheet[3, 0], "partner 4")
+ self.assertEqual(self.worksheet[3, 1], "blop")
+ self.assertEqual(self.worksheet[3, 2], "http://blop.com")
+ self.assertEqual(self.worksheet[3, 3], 2)
+
+ # Header: Group Comment=yop
+ self.assertEqual(self.worksheet[4, 0], "yop (3)", "It should display the group header")
+ self.assertEqual(self.worksheet[4, 3], 4, "It should display the aggregated value")
+
+ # Header: Group Comment=yop > Website=http://blop.com
+ self.assertEqual(self.worksheet[5, 0], " http://blop.com (2)", "It should display the group header")
+ self.assertEqual(self.worksheet[5, 3], 4, "It should display the aggregated value")
+
+ # Data: Group Comment=yop > Website=http://blop.com
+ self.assertEqual(self.worksheet[6, 0], "partner 2")
+ self.assertEqual(self.worksheet[6, 1], "yop")
+ self.assertEqual(self.worksheet[6, 2], "http://blop.com")
+ self.assertEqual(self.worksheet[6, 3], 3)
+
+ self.assertEqual(self.worksheet[7, 0], "partner 3")
+ self.assertEqual(self.worksheet[7, 1], "yop")
+ self.assertEqual(self.worksheet[7, 2], "http://blop.com")
+ self.assertEqual(self.worksheet[7, 3], 1)
+
+ # Header: Group Comment=yop > Website=http://yop.com
+ self.assertEqual(self.worksheet[8, 0], " http://yop.com (1)", "It should display the group header")
+ self.assertEqual(self.worksheet[8, 3], '', "It should not have any aggregated value")
+
+ # Data: Group Comment=yop > Website=http://yop.com
+ self.assertEqual(self.worksheet[9, 0], "partner 1")
+ self.assertEqual(self.worksheet[9, 1], "yop")
+ self.assertEqual(self.worksheet[9, 2], "http://yop.com")
+ self.assertEqual(self.worksheet[9, 3], 0)
+
+ # Header: Group Comment=False
+ self.assertEqual(self.worksheet[10, 0], "Undefined (1)", "It should display the group header")
+ self.assertEqual(self.worksheet[10, 3], '', "It should not have any aggregated value")
+
+ # Header: Group Comment=False > Website=False
+ self.assertEqual(self.worksheet[11, 0], " Undefined (1)", "It should display the group header")
+ self.assertEqual(self.worksheet[11, 3], '', "It should not have any aggregated value")
+
+ # Data: Group Comment=False > Website=False
+ self.assertEqual(self.worksheet[12, 0], "fef (base.group_user)")
+ self.assertEqual(self.worksheet[12, 1], "")
+ self.assertEqual(self.worksheet[12, 2], "")
+ self.assertEqual(self.worksheet[12, 3], 0)
+
+ def test_list_export(self):
+
+ with patch.object(ExportXlsxWriter, 'write', self.mock_write):
+ self.url_open('/web/export/xlsx', data={
+ 'data': json.dumps(self.default_params),
+ 'token': 'dummy',
+ 'csrf_token': http.WebRequest.csrf_token(self),
+ })
+
+ # Main header
+ self.assertEqual(self.worksheet[0, 0], "Partner name", "It should display the list header")
+ self.assertEqual(self.worksheet[0, 1], "Comment", "It should display the list header")
+ self.assertEqual(self.worksheet[0, 2], "Website", "It should display the list header")
+
+ self.assertEqual(self.worksheet[1, 0], "fef (base.group_user)")
+ self.assertEqual(self.worksheet[1, 1], "")
+ self.assertEqual(self.worksheet[1, 2], "")
+
+ self.assertEqual(self.worksheet[2, 0], "partner 1")
+ self.assertEqual(self.worksheet[2, 1], "yop")
+ self.assertEqual(self.worksheet[2, 2], "http://yop.com")
+
+ self.assertEqual(self.worksheet[3, 0], "partner 2")
+ self.assertEqual(self.worksheet[3, 1], "yop")
+ self.assertEqual(self.worksheet[3, 2], "http://blop.com")
+
+ self.assertEqual(self.worksheet[4, 0], "partner 3")
+ self.assertEqual(self.worksheet[4, 1], "yop")
+ self.assertEqual(self.worksheet[4, 2], "http://blop.com")
+
+ self.assertEqual(self.worksheet[5, 0], "partner 4")
+ self.assertEqual(self.worksheet[5, 1], "blop")
+ self.assertEqual(self.worksheet[5, 2], "http://blop.com")
diff --git a/addons/web/tests/test_list_controller.py b/addons/web/tests/test_list_controller.py
deleted file mode 100644
index 311def2989f..00000000000
--- a/addons/web/tests/test_list_controller.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-from ..controllers.list_controller import TableListExporter
-from odoo.tests.common import HttpCase
-
-class WorksheetMock(dict):
-
- def write(self, x, y, value, style=None):
- if (x, y) in self:
- raise Exception("Cannot rewrite cell [{}, {}]".format(x, y))
- self[x, y] = value
-
-class ListController(HttpCase):
-
- def test_list_download(self):
- controller = TableListExporter()
-
- columns = [
- {'field': "foo", 'string': "Foo"},
- {'field': "bar", 'string': "Bar"},
- {'field': "int_field", 'aggregateValue': 19, 'string': "int_field"},
- ]
- groups = [{
- # Group "yop"
- 'isGrouped': True,
- 'count': 1,
- 'aggregateValues': {'int_field': 19},
- 'hideHeader': False,
- 'value': "yop",
- 'data': [{
- # Group "yop > true"
- 'isGrouped': False,
- 'count': 1,
- 'aggregateValues': {'int_field': 10},
- 'hideHeader': False,
- 'value': "true",
- 'data': [{'foo': "yop", 'bar': "True", 'int_field': 10}],
- }, {
- # Group "yop > false"
- 'isGrouped': False,
- 'count': 10,
- 'aggregateValues': {'int_field': 9},
- 'hideHeader': False,
- 'value': "false",
- 'data': [],
- }],
- }]
-
- worksheet = WorksheetMock()
- controller._write_worksheet(worksheet, {'columns': columns, 'groups': groups})
-
- # Header
- self.assertEqual(worksheet[0, 0], 'Foo')
- self.assertEqual(worksheet[0, 1], 'Bar')
- self.assertEqual(worksheet[0, 2], 'int_field')
-
- # Main group
- self.assertEqual(worksheet[1, 0], 'yop (1)', "Group header")
- self.assertEqual(worksheet[1, 2], 19, "int_field aggregate value")
-
- # First sub-group (open)
- self.assertEqual(worksheet[2, 0], '>true (1)', "subgroup header")
- self.assertEqual(worksheet[2, 2], 10, "int_field aggregate value")
-
- # data
- self.assertEqual(worksheet[3, 0], 'yop')
- self.assertEqual(worksheet[3, 1], 'True')
- self.assertEqual(worksheet[3, 2], 10)
-
- # second sub-group (closed)
- self.assertEqual(worksheet[4, 0], '>false (10)', "second sub-group header")
- self.assertEqual(worksheet[4, 2], 9, "int_field aggregate value")
-
- self.assertEqual(worksheet[5, 2], 19, "main list int_field aggregate value")