From 8c305dd2fd70031705041ed2c83dceacc3ab4eab Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Sun, 28 Jul 2019 12:12:02 +0200 Subject: [PATCH 1/3] Add sql_export_excel --- sql_export_excel/README.rst | 47 ++++++++ sql_export_excel/__init__.py | 1 + sql_export_excel/__openerp__.py | 20 ++++ sql_export_excel/models/__init__.py | 1 + sql_export_excel/models/sql_export.py | 108 ++++++++++++++++++ sql_export_excel/readme/CONFIGURE.rst | 4 + sql_export_excel/readme/CONTRIBUTORS.rst | 1 + sql_export_excel/readme/DESCRIPTION.rst | 4 + sql_export_excel/tests/__init__.py | 2 + .../tests/test_sql_query_excel.py | 108 ++++++++++++++++++ sql_export_excel/views/sql_export_view.xml | 21 ++++ 11 files changed, 317 insertions(+) create mode 100644 sql_export_excel/README.rst create mode 100644 sql_export_excel/__init__.py create mode 100644 sql_export_excel/__openerp__.py create mode 100644 sql_export_excel/models/__init__.py create mode 100644 sql_export_excel/models/sql_export.py create mode 100644 sql_export_excel/readme/CONFIGURE.rst create mode 100644 sql_export_excel/readme/CONTRIBUTORS.rst create mode 100644 sql_export_excel/readme/DESCRIPTION.rst create mode 100644 sql_export_excel/tests/__init__.py create mode 100644 sql_export_excel/tests/test_sql_query_excel.py create mode 100644 sql_export_excel/views/sql_export_view.xml diff --git a/sql_export_excel/README.rst b/sql_export_excel/README.rst new file mode 100644 index 000000000..5fb7bb10c --- /dev/null +++ b/sql_export_excel/README.rst @@ -0,0 +1,47 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License: AGPL-3 + +SQL Export Excel +================ + +Add the possibility to extract data from a sql query toward an excel file. +It is also possible to provide an template excel file for a query. In this case, +the data will be inserted in the specified sheet of the provided excel file. This +is usefull when doing a lot of calculation in excel and the data is coming from Odoo. + +Known issues / Roadmap +====================== + +* It was designed to work with xlsx files only, xls format is not supported. + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Florian da Costa + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/sql_export_excel/__init__.py b/sql_export_excel/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/sql_export_excel/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/sql_export_excel/__openerp__.py b/sql_export_excel/__openerp__.py new file mode 100644 index 000000000..c130eece7 --- /dev/null +++ b/sql_export_excel/__openerp__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'SQL Export Excel', + 'version': '9.0.1.0.0', + 'author': 'Akretion,Odoo Community Association (OCA)', + 'website': 'http://github/oca/server-tools', + 'license': 'AGPL-3', + 'category': 'Generic Modules/Others', + 'summary': 'Allow to export a sql query to an excel file.', + 'depends': [ + 'sql_export', + ], + 'data': [ + 'views/sql_export_view.xml', + ], + 'installable': True, + } diff --git a/sql_export_excel/models/__init__.py b/sql_export_excel/models/__init__.py new file mode 100644 index 000000000..014462062 --- /dev/null +++ b/sql_export_excel/models/__init__.py @@ -0,0 +1 @@ +from . import sql_export diff --git a/sql_export_excel/models/sql_export.py b/sql_export_excel/models/sql_export.py new file mode 100644 index 000000000..bb1ea5e49 --- /dev/null +++ b/sql_export_excel/models/sql_export.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from openerp import api, exceptions, fields, models, _ +from cStringIO import StringIO +import logging +import base64 +_logger = logging.getLogger(__name__) + +try: + import openpyxl +except ImportError: + _logger.debug('Can not import openpyxl') + + +class SqlExport(models.Model): + _inherit = 'sql.export' + + file_format = fields.Selection( + selection_add=[('excel', 'Excel')]) + header = fields.Boolean( + default=True, + help="Indicate if the header should be exported to the file.") + attachment_id = fields.Many2one( + 'ir.attachment', string='Excel Template', + help="If you configure an excel file (in xlsx format) here, the " + "result of the query will be injected in it.\nIt is usefull to " + "feed data in a excel file pre-configured with calculation") + sheet_position = fields.Integer( + default=1, + help="Indicate the sheet's position of the excel template where the " + "result of the sql query should be injected.") + row_position = fields.Integer( + default=1, + help="Indicate from which row the result of the query should be " + "injected.") + col_position = fields.Integer( + string="Column Position", + default=1, + help="Indicate from which column the result of the query should be " + "injected.") + + @api.constrains('sheet_position') + def check_sheet_position(self): + for export in self: + if export.sheet_position < 1: + raise exceptions.ValidationError( + _("The sheet position can't be less than 1.")) + + @api.constrains('row_position') + def check_row_position(self): + for export in self: + if export.row_position < 1: + raise exceptions.ValidationError( + _("The row position can't be less than 1.")) + + @api.constrains('col_position') + def check_column_position(self): + for export in self: + if export.col_position < 1: + raise exceptions.ValidationError( + _("The column position can't be less than 1.")) + + @api.multi + def _get_file_extension(self): + self.ensure_one() + if self.file_format == 'excel': + return 'xlsx' + else: + return super(SqlExport, self)._get_file_extension() + + @api.multi + def excel_get_datas_from_query(self, variable_dict): + self.ensure_one() + res = self._execute_sql_request( + params=variable_dict, mode='fetchall', header=self.header) + # Case we insert data in an existing excel file. + if self.attachment_id: + datas = self.attachment_id.datas + infile = StringIO() + infile.write(base64.b64decode(datas)) + infile.seek(0) + wb = openpyxl.load_workbook(filename=infile) + sheets = wb.worksheets + try: + ws = sheets[self.sheet_position - 1] + except IndexError: + raise exceptions.ValidationError( + _("The Excel Template file contains less than %s sheets " + "Please, adjust the Sheet Position parameter.")) + row_position = self.row_position or 1 + col_position = self.col_position or 1 + # Case of excel file creation + else: + wb = openpyxl.Workbook() + ws = wb.active + row_position = 1 + col_position = 1 + for index, row in enumerate(res, row_position): + for col, val in enumerate(row, col_position): + ws.cell(row=index, column=col).value = val + output = StringIO() + wb.save(output) + output.getvalue() + output_datas = base64.b64encode(output.getvalue()) + output.close() + return output_datas diff --git a/sql_export_excel/readme/CONFIGURE.rst b/sql_export_excel/readme/CONFIGURE.rst new file mode 100644 index 000000000..abf9be6e1 --- /dev/null +++ b/sql_export_excel/readme/CONFIGURE.rst @@ -0,0 +1,4 @@ +If you want Odoo to update an existing excel file, you should create an attachment +with the excel file and configure this attachment on the query. +Then, you can configure the query to indicate if Odoo should export the header and where it should +insert the data. By default, it will insert it in the first sheet, at first row/column. diff --git a/sql_export_excel/readme/CONTRIBUTORS.rst b/sql_export_excel/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..0bddb053a --- /dev/null +++ b/sql_export_excel/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Florian da Costa diff --git a/sql_export_excel/readme/DESCRIPTION.rst b/sql_export_excel/readme/DESCRIPTION.rst new file mode 100644 index 000000000..4808db7b5 --- /dev/null +++ b/sql_export_excel/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +Add the possibility to extract data from a sql query toward an excel file. +It is also possible to provide an template excel file for a query. In this case, +the data will be inserted in the specified sheet of the provided excel file. This +is usefull when doing a lot of calculation in excel and the data is coming from Odoo. diff --git a/sql_export_excel/tests/__init__.py b/sql_export_excel/tests/__init__.py new file mode 100644 index 000000000..22c4421ab --- /dev/null +++ b/sql_export_excel/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import test_sql_query_excel diff --git a/sql_export_excel/tests/test_sql_query_excel.py b/sql_export_excel/tests/test_sql_query_excel.py new file mode 100644 index 000000000..a51423c67 --- /dev/null +++ b/sql_export_excel/tests/test_sql_query_excel.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2019 Akretion () +# @author: Florian da Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp.tests.common import TransactionCase +import base64 +from cStringIO import StringIO +import logging + +_logger = logging.getLogger(__name__) + +try: + import openpyxl +except ImportError: + _logger.debug('Can not import openpyxl') + + +class TestExportSqlQueryExcel(TransactionCase): + + def setUp(self): + super(TestExportSqlQueryExcel, self).setUp() + self.wizard_obj = self.env['sql.file.wizard'] + + def get_workbook_from_query(self, wizard): + wizard.export_sql() + decoded_data = base64.b64decode(wizard.binary_file) + xlsx_file = StringIO(decoded_data) + return openpyxl.load_workbook(xlsx_file) + + def test_excel_file_generation(self): + test_query = "SELECT 'testcol1' as firstcol, 2 as second_col" + query_vals = { + 'name': 'Test Query Excel', + 'query': test_query, + 'file_format': 'excel' + } + query = self.env['sql.export'].create(query_vals) + query.button_validate_sql_expression() + wizard = self.wizard_obj.create({ + 'sql_export_id': query.id, + }) + workbook = self.get_workbook_from_query(wizard) + ws = workbook.active + # Check values, header should be here by default + self.assertEqual(ws.cell(row=1, column=1).value, 'firstcol') + self.assertEqual(ws.cell(row=2, column=1).value, 'testcol1') + self.assertEqual(ws.cell(row=2, column=2).value, 2) + + query.write({'header': False}) + wb2 = self.get_workbook_from_query(wizard) + ws2 = wb2.active + # Check values, the header should not be present + self.assertEqual(ws2.cell(row=1, column=1).value, 'testcol1') + self.assertEqual(ws2.cell(row=1, column=2).value, 2) + + def test_excel_file_insert(self): + # Create excel file with 2 sheets. Create a header in second sheet + # where data will be inserted + wb = openpyxl.Workbook() + ws = wb.active + ws.cell(row=1, column=1, value="My Test Value") + ws2 = wb.create_sheet("data") + ws2.cell(row=1, column=1, value='Partner Id') + ws2.cell(row=1, column=2, value='Partner Name') + output = StringIO() + wb.save(output) + data = output.getvalue() + + # Create attachment with the created xlsx file which will be used as + # template in the sql query + attachmnent_vals = { + 'name': 'template xlsx sql export Res Partner', + 'datas': base64.b64encode(data), + } + attachment = self.env['ir.attachment'].create(attachmnent_vals) + + # Create the query and configure it to insert the data in the second + # sheet of the xlsx template file and start inserting data at the + # second row, ignoring header (because the template excel file + # already contains a header) + test_query = "SELECT id, name FROM res_partner" + query_vals = { + 'name': 'Test Query Excel', + 'query': test_query, + 'file_format': 'excel', + 'attachment_id': attachment.id, + 'sheet_position': 2, + 'header': False, + 'row_position': 2, + } + query = self.env['sql.export'].create(query_vals) + query.button_validate_sql_expression() + wizard = self.wizard_obj.create({ + 'sql_export_id': query.id, + }) + + # Check the generated excel file. The first sheet should still contain + # the same data and the second sheet should have kept the header and + # inserted data from the query + wb2 = self.get_workbook_from_query(wizard) + sheets = wb2.worksheets + ws1 = sheets[0] + # Check values, header should be here by default + self.assertEqual(ws1.cell(row=1, column=1).value, 'My Test Value') + ws2 = sheets[1] + self.assertEqual(ws2.cell(row=1, column=1).value, 'Partner Id') + self.assertTrue(ws2.cell(row=2, column=1).value) diff --git a/sql_export_excel/views/sql_export_view.xml b/sql_export_excel/views/sql_export_view.xml new file mode 100644 index 000000000..98fc3981c --- /dev/null +++ b/sql_export_excel/views/sql_export_view.xml @@ -0,0 +1,21 @@ + + + + + + + sql.export + + + + + + + + + + + + + + From 87627125f0b878ba6b35b927b4ede0d4537c659d Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Mon, 2 Sep 2019 13:06:36 +0200 Subject: [PATCH 2/3] Migrate sql_export_excel to v12 --- sql_export/models/sql_export.py | 22 ++++++++++++++++++- sql_export/views/sql_export_view.xml | 3 ++- sql_export/wizard/wizard_file.py | 17 +++++++------- .../{__openerp__.py => __manifest__.py} | 3 +-- sql_export_excel/models/sql_export.py | 7 +++--- sql_export_excel/tests/__init__.py | 1 - .../tests/test_sql_query_excel.py | 9 ++++---- .../models/sql_request_mixin.py | 11 +++++++++- 8 files changed, 49 insertions(+), 24 deletions(-) rename sql_export_excel/{__openerp__.py => __manifest__.py} (90%) diff --git a/sql_export/models/sql_export.py b/sql_export/models/sql_export.py index 7be136f84..5463a328a 100644 --- a/sql_export/models/sql_export.py +++ b/sql_export/models/sql_export.py @@ -16,9 +16,14 @@ class SqlExport(models.Model): _check_execution_enabled = False copy_options = fields.Char( - string='Copy Options', required=True, + string='Copy Options', required=False, default="CSV HEADER DELIMITER ';'") + file_format = fields.Selection( + [('csv', 'CSV')], + default='csv', + required=True) + field_ids = fields.Many2many( 'ir.model.fields', 'fields_sqlquery_rel', @@ -48,3 +53,18 @@ class SqlExport(models.Model): 'context': self.env.context, 'nodestroy': True, } + + def _get_file_extension(self): + self.ensure_one() + if self.file_format == 'csv': + return 'csv' + + def csv_get_datas_from_query(self, variable_dict): + self.ensure_one() + # Execute Request + res = self._execute_sql_request( + params=variable_dict, mode='stdout', + copy_options=self.copy_options) + if self.encoding: + res = res.decode(self.encoding) + return res diff --git a/sql_export/views/sql_export_view.xml b/sql_export/views/sql_export_view.xml index 53ac7f4f0..5a4d1b7d4 100644 --- a/sql_export/views/sql_export_view.xml +++ b/sql_export/views/sql_export_view.xml @@ -21,7 +21,8 @@ - + + diff --git a/sql_export/wizard/wizard_file.py b/sql_export/wizard/wizard_file.py index fad2c569c..52614f9e1 100644 --- a/sql_export/wizard/wizard_file.py +++ b/sql_export/wizard/wizard_file.py @@ -68,16 +68,15 @@ class SqlFileWizard(models.TransientModel): if "%(user_id)s" in sql_export.query: variable_dict['user_id'] = self.env.uid - # Execute Request - res = sql_export._execute_sql_request( - params=variable_dict, mode='stdout', - copy_options=sql_export.copy_options) - if self.sql_export_id.encoding: - res = res.decode(self.sql_export_id.encoding) + # Call different method depending on file_type since the logic will be + # different + method_name = '%s_get_datas_from_query' % sql_export.file_format + datas = getattr(sql_export, method_name)(variable_dict) + extension = sql_export._get_file_extension() self.write({ - 'binary_file': res, - 'file_name': '%(name)s_%(date)s.csv' % { - 'name': sql_export.name, 'date': date} + 'binary_file': datas, + 'file_name': '%(name)s_%(date)s.%(extension)s' % { + 'name': sql_export.name, 'date': date, 'extension': extension} }) return { 'view_mode': 'form', diff --git a/sql_export_excel/__openerp__.py b/sql_export_excel/__manifest__.py similarity index 90% rename from sql_export_excel/__openerp__.py rename to sql_export_excel/__manifest__.py index c130eece7..237b2df70 100644 --- a/sql_export_excel/__openerp__.py +++ b/sql_export_excel/__manifest__.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- # Copyright 2019 Akretion # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { 'name': 'SQL Export Excel', - 'version': '9.0.1.0.0', + 'version': '12.0.1.0.0', 'author': 'Akretion,Odoo Community Association (OCA)', 'website': 'http://github/oca/server-tools', 'license': 'AGPL-3', diff --git a/sql_export_excel/models/sql_export.py b/sql_export_excel/models/sql_export.py index bb1ea5e49..48a45cf90 100644 --- a/sql_export_excel/models/sql_export.py +++ b/sql_export_excel/models/sql_export.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- # Copyright 2019 Akretion # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from openerp import api, exceptions, fields, models, _ -from cStringIO import StringIO +from io import BytesIO import logging import base64 _logger = logging.getLogger(__name__) @@ -78,7 +77,7 @@ class SqlExport(models.Model): # Case we insert data in an existing excel file. if self.attachment_id: datas = self.attachment_id.datas - infile = StringIO() + infile = BytesIO() infile.write(base64.b64decode(datas)) infile.seek(0) wb = openpyxl.load_workbook(filename=infile) @@ -100,7 +99,7 @@ class SqlExport(models.Model): for index, row in enumerate(res, row_position): for col, val in enumerate(row, col_position): ws.cell(row=index, column=col).value = val - output = StringIO() + output = BytesIO() wb.save(output) output.getvalue() output_datas = base64.b64encode(output.getvalue()) diff --git a/sql_export_excel/tests/__init__.py b/sql_export_excel/tests/__init__.py index 22c4421ab..6d89d7607 100644 --- a/sql_export_excel/tests/__init__.py +++ b/sql_export_excel/tests/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- from . import test_sql_query_excel diff --git a/sql_export_excel/tests/test_sql_query_excel.py b/sql_export_excel/tests/test_sql_query_excel.py index a51423c67..b1433c55b 100644 --- a/sql_export_excel/tests/test_sql_query_excel.py +++ b/sql_export_excel/tests/test_sql_query_excel.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- # Copyright (C) 2019 Akretion () # @author: Florian da Costa # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.tests.common import TransactionCase +from odoo.tests.common import TransactionCase import base64 -from cStringIO import StringIO +from io import BytesIO import logging _logger = logging.getLogger(__name__) @@ -25,7 +24,7 @@ class TestExportSqlQueryExcel(TransactionCase): def get_workbook_from_query(self, wizard): wizard.export_sql() decoded_data = base64.b64decode(wizard.binary_file) - xlsx_file = StringIO(decoded_data) + xlsx_file = BytesIO(decoded_data) return openpyxl.load_workbook(xlsx_file) def test_excel_file_generation(self): @@ -63,7 +62,7 @@ class TestExportSqlQueryExcel(TransactionCase): ws2 = wb.create_sheet("data") ws2.cell(row=1, column=1, value='Partner Id') ws2.cell(row=1, column=2, value='Partner Name') - output = StringIO() + output = BytesIO() wb.save(output) data = output.getvalue() diff --git a/sql_request_abstract/models/sql_request_mixin.py b/sql_request_abstract/models/sql_request_mixin.py index cd2010355..71e3588c0 100644 --- a/sql_request_abstract/models/sql_request_mixin.py +++ b/sql_request_abstract/models/sql_request_mixin.py @@ -100,7 +100,8 @@ class SQLRequestMixin(models.AbstractModel): @api.multi def _execute_sql_request( self, params=None, mode='fetchall', rollback=True, - view_name=False, copy_options="CSV HEADER DELIMITER ';'"): + view_name=False, copy_options="CSV HEADER DELIMITER ';'", + header=False): """Execute a SQL request on the current database. ??? This function checks before if the user has the @@ -126,6 +127,9 @@ class SQLRequestMixin(models.AbstractModel): :param copy_options: (str) mentions extra options for "COPY request STDOUT WITH xxx" request. (Ignored if @mode != 'stdout') + :param header: (boolean) if true, the header of the query will be + returned as first element of the list if the mode is fetchall. + (Ignored if @mode != fetchall) ..note:: The following exceptions could be raised: psycopg2.ProgrammingError: Error in the SQL Request. @@ -175,6 +179,11 @@ class SQLRequestMixin(models.AbstractModel): self.env.cr.execute(query) if mode == 'fetchall': res = self.env.cr.fetchall() + if header: + colnames = [ + desc[0] for desc in self.env.cr.description + ] + res.insert(0, colnames) elif mode == 'fetchone': res = self.env.cr.fetchone() finally: From 68448cfa749d515a99aa08a418871078e80b94b1 Mon Sep 17 00:00:00 2001 From: Florian Date: Tue, 3 Sep 2019 11:37:56 +0200 Subject: [PATCH 3/3] Small fixes for v12/python3 standard Co-Authored-By: David Beal --- sql_export/models/sql_export.py | 2 +- sql_export/wizard/wizard_file.py | 6 +++--- sql_export_excel/models/sql_export.py | 6 +++--- sql_export_excel/tests/test_sql_query_excel.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql_export/models/sql_export.py b/sql_export/models/sql_export.py index 5463a328a..15a0bffea 100644 --- a/sql_export/models/sql_export.py +++ b/sql_export/models/sql_export.py @@ -59,7 +59,7 @@ class SqlExport(models.Model): if self.file_format == 'csv': return 'csv' - def csv_get_datas_from_query(self, variable_dict): + def csv_get_data_from_query(self, variable_dict): self.ensure_one() # Execute Request res = self._execute_sql_request( diff --git a/sql_export/wizard/wizard_file.py b/sql_export/wizard/wizard_file.py index 52614f9e1..a0439d1e4 100644 --- a/sql_export/wizard/wizard_file.py +++ b/sql_export/wizard/wizard_file.py @@ -70,11 +70,11 @@ class SqlFileWizard(models.TransientModel): # Call different method depending on file_type since the logic will be # different - method_name = '%s_get_datas_from_query' % sql_export.file_format - datas = getattr(sql_export, method_name)(variable_dict) + method_name = '%s_get_data_from_query' % sql_export.file_format + data = getattr(sql_export, method_name)(variable_dict) extension = sql_export._get_file_extension() self.write({ - 'binary_file': datas, + 'binary_file': data, 'file_name': '%(name)s_%(date)s.%(extension)s' % { 'name': sql_export.name, 'date': date, 'extension': extension} }) diff --git a/sql_export_excel/models/sql_export.py b/sql_export_excel/models/sql_export.py index 48a45cf90..3479481e3 100644 --- a/sql_export_excel/models/sql_export.py +++ b/sql_export_excel/models/sql_export.py @@ -1,7 +1,7 @@ # Copyright 2019 Akretion # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from openerp import api, exceptions, fields, models, _ +from odoo import api, exceptions, fields, models, _ from io import BytesIO import logging import base64 @@ -67,10 +67,10 @@ class SqlExport(models.Model): if self.file_format == 'excel': return 'xlsx' else: - return super(SqlExport, self)._get_file_extension() + return super()._get_file_extension() @api.multi - def excel_get_datas_from_query(self, variable_dict): + def excel_get_data_from_query(self, variable_dict): self.ensure_one() res = self._execute_sql_request( params=variable_dict, mode='fetchall', header=self.header) diff --git a/sql_export_excel/tests/test_sql_query_excel.py b/sql_export_excel/tests/test_sql_query_excel.py index b1433c55b..5711ccb7c 100644 --- a/sql_export_excel/tests/test_sql_query_excel.py +++ b/sql_export_excel/tests/test_sql_query_excel.py @@ -18,7 +18,7 @@ except ImportError: class TestExportSqlQueryExcel(TransactionCase): def setUp(self): - super(TestExportSqlQueryExcel, self).setUp() + super().setUp() self.wizard_obj = self.env['sql.file.wizard'] def get_workbook_from_query(self, wizard):