diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/test_xlsx_export | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/test_xlsx_export')
| -rw-r--r-- | addons/test_xlsx_export/__init__.py | 1 | ||||
| -rw-r--r-- | addons/test_xlsx_export/__manifest__.py | 13 | ||||
| -rw-r--r-- | addons/test_xlsx_export/ir.model.access.csv | 4 | ||||
| -rw-r--r-- | addons/test_xlsx_export/models.py | 36 | ||||
| -rw-r--r-- | addons/test_xlsx_export/tests/__init__.py | 4 | ||||
| -rw-r--r-- | addons/test_xlsx_export/tests/test_export.py | 371 |
6 files changed, 429 insertions, 0 deletions
diff --git a/addons/test_xlsx_export/__init__.py b/addons/test_xlsx_export/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/addons/test_xlsx_export/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/addons/test_xlsx_export/__manifest__.py b/addons/test_xlsx_export/__manifest__.py new file mode 100644 index 00000000..df22ffcd --- /dev/null +++ b/addons/test_xlsx_export/__manifest__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': 'test xlsx export', + 'version': '0.1', + 'category': 'Hidden/Tests', + 'description': """A module to test xlsx export.""", + 'depends': ['web', 'test_mail'], + 'data': ['ir.model.access.csv'], + 'installable': True, + 'auto_install': False, + 'license': 'LGPL-3', +} diff --git a/addons/test_xlsx_export/ir.model.access.csv b/addons/test_xlsx_export/ir.model.access.csv new file mode 100644 index 00000000..cb43b225 --- /dev/null +++ b/addons/test_xlsx_export/ir.model.access.csv @@ -0,0 +1,4 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +access_export_group_operator,access_export_group_operator,model_export_group_operator,,1,1,1,1 +access_export_group_operator_one2many,access_export_group_operator_one2many,model_export_group_operator_one2many,,1,1,1,1 +access_export_integer,access_export_integer,model_export_integer,,1,1,1,1 diff --git a/addons/test_xlsx_export/models.py b/addons/test_xlsx_export/models.py new file mode 100644 index 00000000..830917c0 --- /dev/null +++ b/addons/test_xlsx_export/models.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + +class NewModel(models.Model): + _name = 'export.integer' + _description = 'Export: Integer' + + value = fields.Integer(default=4) + + def name_get(self): + return [(record.id, "%s:%s" % (self._name, record.value)) for record in self] + +class GroupOperator(models.Model): + _name = 'export.group_operator' + _description = 'Export Group Operator' + + int_sum = fields.Integer(group_operator='sum') + int_max = fields.Integer(group_operator='max') + float_min = fields.Float(group_operator='min') + float_avg = fields.Float(group_operator='avg') + float_monetary = fields.Monetary(currency_field='currency_id',group_operator='sum') + currency_id = fields.Many2one('res.currency') + date_max = fields.Date(group_operator='max') + bool_and = fields.Boolean(group_operator='bool_and') + bool_or = fields.Boolean(group_operator='bool_or') + many2one = fields.Many2one('export.integer') + one2many = fields.One2many('export.group_operator.one2many', 'parent_id') + +class GroupOperatorO2M(models.Model): + _name = 'export.group_operator.one2many' + _description = 'Export Group Operator One2Many' + + parent_id = fields.Many2one('export.group_operator') + value = fields.Integer() diff --git a/addons/test_xlsx_export/tests/__init__.py b/addons/test_xlsx_export/tests/__init__.py new file mode 100644 index 00000000..ff41d3a8 --- /dev/null +++ b/addons/test_xlsx_export/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import test_export + diff --git a/addons/test_xlsx_export/tests/test_export.py b/addons/test_xlsx_export/tests/test_export.py new file mode 100644 index 00000000..0ee3a05d --- /dev/null +++ b/addons/test_xlsx_export/tests/test_export.py @@ -0,0 +1,371 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import json +from datetime import date +from unittest.mock import patch + +from odoo import http +from odoo.tests import common, tagged +from odoo.addons.web.controllers.main import ExportXlsxWriter +from odoo.addons.mail.tests.common import mail_new_test_user + + +class XlsxCreatorCase(common.HttpCase): + model_name = False + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.model = None + + def setUp(self): + super().setUp() + self.model = self.env[self.model_name] + + mail_new_test_user(self.env, login='fof', password='123456789', groups='base.group_user,base.group_allow_export') + self.session = self.authenticate('fof', '123456789') + + self.worksheet = {} # mock worksheet + + self.default_params = { + 'domain': [], + 'fields': [{'name': field.name, 'label': field.string} for field in self.model._fields.values()], + 'groupby': [], + 'ids': False, + 'import_compat': False, + 'model': self.model._name, + } + + def _mock_write(self, row, column, value, style=None): + self.worksheet[row, column] = str(value) + + def make(self, values, context=None): + return self.model.with_context(**(context or {})).create(values) + + def export(self, values, fields=[], params={}, context=None): + self.worksheet = {} + self.make(values, context=context) + + if fields and 'fields' not in params: + params['fields'] = [{ + 'name': self.model._fields[f].name, + 'label': self.model._fields[f].string, + 'type': self.model._fields[f].type, + } for f in fields] + + with patch.object(ExportXlsxWriter, 'write', self._mock_write): + self.url_open('/web/export/xlsx', data={ + 'data': json.dumps(dict(self.default_params, **params)), + 'token': 'dummy', + 'csrf_token': http.WebRequest.csrf_token(self), + }) + return self.worksheet + + def assertExportEqual(self, value, expected): + for row in range(len(expected)): + for column in range(len(expected[row])): + cell_value = value.pop((row, column), '') + expected_value = expected[row][column] + self.assertEqual(cell_value, expected_value, "Cell %s, %s have a wrong value" % (row, column)) + self.assertFalse(value, "There are unexpected cells in the export") + + +@tagged('-at_install', 'post_install') +class TestGroupedExport(XlsxCreatorCase): + model_name = 'export.group_operator' + + def test_int_sum_max(self): + values = [ + {'int_sum': 10, 'int_max': 20}, + {'int_sum': 10, 'int_max': 50}, + {'int_sum': 20,'int_max': 30}, + ] + export = self.export(values, fields=['int_sum', 'int_max'], params={'groupby': ['int_sum', 'int_max']}) + self.assertExportEqual(export, [ + ['Int Sum' ,'Int Max'], + ['10 (2)' ,'50'], + [' 20 (1)' ,'20'], + ['10' ,'20'], + [' 50 (1)' ,'50'], + ['10' ,'50'], + ['20 (1)' ,'30'], + [' 30 (1)' ,'30'], + ['20' ,'30'], + ]) + + export = self.export([], fields=['int_max', 'int_sum'], params={'groupby': ['int_sum', 'int_max']}) + + self.assertExportEqual(export, [ + ['Int Max' ,'Int Sum'], + ['10 (2)' ,'20'], + [' 20 (1)' ,'10'], + ['20' ,'10'], + [' 50 (1)' ,'10'], + ['50' ,'10'], + ['20 (1)' ,'20'], + [' 30 (1)' ,'20'], + ['30' ,'20'], + ]) + + def test_float_min(self): + values = [ + {'int_sum': 10, 'float_min': 111.0}, + {'int_sum': 10, 'float_min': 222.0}, + {'int_sum': 20, 'float_min': 333.0}, + ] + export = self.export(values, fields=['int_sum', 'float_min'], params={'groupby': ['int_sum', 'float_min']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Float Min'], + ['10 (2)' ,'111.00'], + [' 111.0 (1)','111.00'], + ['10' ,'111.0'], + [' 222.0 (1)','222.00'], + ['10' ,'222.0'], + ['20 (1)' ,'333.00'], + [' 333.0 (1)','333.00'], + ['20' ,'333.0'], + ]) + + def test_float_avg(self): + values = [ + {'int_sum': 10, 'float_avg': 100.0}, + {'int_sum': 10, 'float_avg': 200.0}, + {'int_sum': 20, 'float_avg': 300.0}, + ] + export = self.export(values, fields=['int_sum', 'float_avg'], params={'groupby': ['int_sum', 'float_avg']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Float Avg'], + ['10 (2)' ,'150.00'], + [' 100.0 (1)','100.00'], + ['10' ,'100.0'], + [' 200.0 (1)','200.00'], + ['10' ,'200.0'], + ['20 (1)' ,'300.00'], + [' 300.0 (1)','300.00'], + ['20' ,'300.0'], + ]) + + def test_float_avg_nested(self): + """ With more than one nested level (avg aggregation) """ + values = [ + {'int_sum': 10, 'int_max': 30, 'float_avg': 100.0}, + {'int_sum': 10, 'int_max': 30, 'float_avg': 200.0}, + {'int_sum': 10, 'int_max': 20, 'float_avg': 600.0}, + ] + export = self.export(values, fields=['int_sum', 'float_avg'], params={'groupby': ['int_sum', 'int_max', 'float_avg']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Float Avg'], + ['10 (3)' ,'300.00'], + [' 20 (1)' ,'600.00'], + [' 600.0 (1)','600.00'], + ['10' ,'600.0'], + [' 30 (2)' ,'150.00'], + [' 100.0 (1)','100.00'], + ['10' ,'100.0'], + [' 200.0 (1)','200.00'], + ['10' ,'200.0'], + ]) + + def test_float_avg_nested_no_value(self): + """ With more than one nested level (avg aggregation is done on 0, not False) """ + values = [ + {'int_sum': 10, 'int_max': 20, 'float_avg': False}, + {'int_sum': 10, 'int_max': 30, 'float_avg': False}, + {'int_sum': 10, 'int_max': 30, 'float_avg': False}, + ] + export = self.export(values, fields=['int_sum', 'float_avg'], params={'groupby': ['int_sum', 'int_max', 'float_avg']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Float Avg'], + ['10 (3)' ,'0.00'], + [' 20 (1)' ,'0.00'], + [' Undefined (1)','0.00'], + ['10' ,'0.0'], + [' 30 (2)' ,'0.00'], + [' Undefined (2)','0.00'], + ['10' ,'0.0'], + ['10' ,'0.0'], + ]) + + def test_date_max(self): + values = [ + {'int_sum': 10, 'date_max': date(2019, 1, 1)}, + {'int_sum': 10, 'date_max': date(2000, 1, 1)}, + {'int_sum': 20, 'date_max': date(1980, 1, 1)}, + ] + export = self.export(values, fields=['int_sum', 'date_max'], params={'groupby': ['int_sum', 'date_max:month']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Date Max'], + ['10 (2)' ,'2019-01-01'], + [' January 2000 (1)' ,'2000-01-01'], + ['10' ,'2000-01-01'], + [' January 2019 (1)' ,'2019-01-01'], + ['10' ,'2019-01-01'], + ['20 (1)' ,'1980-01-01'], + [' January 1980 (1)' ,'1980-01-01'], + ['20' ,'1980-01-01'], + ]) + + def test_bool_and(self): + values = [ + {'int_sum': 10, 'bool_and': True}, + {'int_sum': 10, 'bool_and': True}, + {'int_sum': 20, 'bool_and': True}, + {'int_sum': 20, 'bool_and': False}, + ] + export = self.export(values, fields=['int_sum', 'bool_and'], params={'groupby': ['int_sum', 'bool_and']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Bool And'], + ['10 (2)' ,'True'], + [' True (2)' ,'True'], + ['10' ,'True'], + ['10' ,'True'], + ['20 (2)' ,'False'], + [' False (1)' ,'False'], + ['20' ,'False'], + [' True (1)' ,'True'], + ['20' ,'True'], + ]) + + def test_bool_or(self): + values = [ + {'int_sum': 10, 'bool_or': True}, + {'int_sum': 10, 'bool_or': False}, + {'int_sum': 20, 'bool_or': False}, + {'int_sum': 20, 'bool_or': False}, + ] + export = self.export(values, fields=['int_sum', 'bool_or'], params={'groupby': ['int_sum', 'bool_or']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Bool Or'], + ['10 (2)' ,'True'], + [' False (1)' ,'False'], + ['10' ,'False'], + [' True (1)' ,'True'], + ['10' ,'True'], + ['20 (2)' ,'False'], + [' False (2)' ,'False'], + ['20' ,'False'], + ['20' ,'False'], + ]) + + def test_many2one(self): + values = [ + {'int_sum': 10, 'many2one': self.env['export.integer'].create({}).id}, + {'int_sum': 10}, + ] + export = self.export(values, fields=['int_sum', 'many2one'], params={'groupby': ['int_sum', 'many2one']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Many2One'], + ['10 (2)' ,''], + [' export.integer:4 (1)' ,''], + ['10' ,'export.integer:4'], + [' Undefined (1)' ,''], + ['10' ,'False'], + ]) + + def test_nested_records(self): + """ + aggregated values currently not supported for nested record export, but it should not crash + e.g. export 'many2one/const' + """ + values = [{'int_sum': 10, + 'date_max': date(2019, 1, 1), + 'many2one': self.env['export.integer'].create({}).id, + }, { + 'int_sum': 10, + 'date_max': date(2000, 1, 1), + 'many2one': self.env['export.integer'].create({}).id, + },] + export = self.export(values, + params={ + 'groupby': ['int_sum', 'date_max:month'], + 'fields': [ + {'name': 'int_sum', 'label': 'Int Sum'}, + {'name': 'date_max', 'label': 'Date Max'}, + {'name': 'many2one/value', 'label': 'Many2One/Value'}, + ] + }) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Date Max' ,'Many2One/Value'], + ['10 (2)' ,'2019-01-01' ,''], + [' January 2000 (1)' ,'2000-01-01' ,''], + ['10' ,'2000-01-01' ,'4'], + [' January 2019 (1)' ,'2019-01-01' ,''], + ['10' ,'2019-01-01' ,'4'], + ]) + + def test_one2many(self): + values = [{ + 'int_sum': 10, + 'one2many': [ + (0, 0, {'value': 8}), + (0, 0, {'value': 9}), + ], + }] + export = self.export(values, + params={ + 'groupby': ['int_sum',], + 'fields': [ + {'name': 'int_sum', 'label': 'Int Sum'}, + {'name': 'one2many/value', 'label': 'One2many/Value'}, + ] + }) + self.assertExportEqual(export, [ + ['Int Sum' ,'One2many/Value'], + ['10 (1)' ,''], + ['10' ,'8'], + ['' ,'9'], + ]) + + def test_unset_date_values(self): + values = [ + {'int_sum': 10, 'date_max': date(2019, 1, 1)}, + {'int_sum': 10, 'date_max': False}, + ] + # Group and aggregate by date, but date fields are not set for all records + export = self.export(values, fields=['int_sum', 'date_max'], params={'groupby': ['int_sum', 'date_max:month']}) + + self.assertExportEqual(export, [ + ['Int Sum' ,'Date Max'], + ['10 (2)' ,'2019-01-01'], + [' January 2019 (1)' ,'2019-01-01'], + ['10' ,'2019-01-01'], + [' Undefined (1)' ,''], + ['10' ,''], + ]) + + def test_float_representation(self): + currency = self.env['res.currency'].create({ + 'name': "bottlecap", + 'symbol': "b", + 'rounding': 0.001, + 'decimal_places': 3, + }) + + values = [ + {'int_sum': 1, 'currency_id': currency.id, 'float_monetary': 60739.2000000004}, + {'int_sum': 2, 'currency_id': currency.id, 'float_monetary': 2.0}, + {'int_sum': 3, 'currency_id': currency.id, 'float_monetary': 999.9995999}, + ] + export = self.export(values, fields=['int_sum', 'float_monetary'], params={'groupby': ['int_sum', 'float_monetary']}) + + self.assertExportEqual(export, [ + ['Int Sum', 'Float Monetary'], + ['1 (1)','60739.200'], + [' 60739.2 (1)','60739.200'], + ['1','60739.2'], + ['2 (1)','2.000'], + [' 2.0 (1)','2.000'], + ['2','2.0'], + ['3 (1)','1000.000'], + [' 1000.0 (1)','1000.000'], + ['3','1000.0'], + ]) |
