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: