diff --git a/sql_export/__manifest__.py b/sql_export/__manifest__.py
index 856215656..e140d22cd 100644
--- a/sql_export/__manifest__.py
+++ b/sql_export/__manifest__.py
@@ -3,24 +3,24 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
- 'name': 'SQL Export',
- 'version': '12.0.1.1.1',
- 'author': 'Akretion,Odoo Community Association (OCA)',
- 'website': 'http://www.akretion.com',
- 'license': 'AGPL-3',
- 'category': 'Generic Modules/Others',
- 'summary': 'Export data in csv file with SQL requests',
- 'depends': [
- 'sql_request_abstract',
+ "name": "SQL Export",
+ "version": "12.0.1.1.1",
+ "author": "Akretion,Odoo Community Association (OCA)",
+ "website": "https://github.com/OCA/server-tools",
+ "license": "AGPL-3",
+ "category": "Generic Modules/Others",
+ "summary": "Export data in csv file with SQL requests",
+ "depends": [
+ "sql_request_abstract",
],
- 'data': [
- 'views/sql_export_view.xml',
- 'wizard/wizard_file_view.xml',
- 'security/sql_export_security.xml',
- 'security/ir.model.access.csv',
+ "data": [
+ "views/sql_export_view.xml",
+ "wizard/wizard_file_view.xml",
+ "security/sql_export_security.xml",
+ "security/ir.model.access.csv",
],
- 'demo': [
- 'demo/sql_export.xml',
+ "demo": [
+ "demo/sql_export.xml",
],
- 'installable': True,
- }
+ "installable": True,
+}
diff --git a/sql_export/demo/sql_export.xml b/sql_export/demo/sql_export.xml
index 4635ec089..5cf18ec6f 100644
--- a/sql_export/demo/sql_export.xml
+++ b/sql_export/demo/sql_export.xml
@@ -1,17 +1,16 @@
-
+
-
x_date
Date
date
-
+
sql.file.wizard
manual
@@ -20,7 +19,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
x_id
x_ID
integer
-
+
sql.file.wizard
manual
@@ -29,7 +28,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
x_partner_categ_ids
Partner Categories
many2many
-
+
sql.file.wizard
manual
res.partner.category
@@ -40,14 +39,27 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
SELECT name, street FROM res_partner;
-
+
Export Partners With Variables (Demo Data)
- SELECT p.id FROM res_partner p LEFT JOIN res_partner_res_partner_category_rel rel ON rel.partner_id = p.id WHERE create_date < %(x_date)s AND id = %(x_id)s AND rel.category_id in %(x_partner_categ_ids)s
-
+ SELECT p.id FROM res_partner p LEFT JOIN res_partner_res_partner_category_rel rel ON rel.partner_id = p.id WHERE create_date < %(x_date)s AND id = %(x_id)s AND rel.category_id in %(x_partner_categ_ids)s
+
-
+
diff --git a/sql_export/models/sql_export.py b/sql_export/models/sql_export.py
index 15a0bffea..5b5436712 100644
--- a/sql_export/models/sql_export.py
+++ b/sql_export/models/sql_export.py
@@ -1,70 +1,77 @@
# Copyright (C) 2015 Akretion ()
# @author: Florian da Costa
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-from odoo import models, fields
+from odoo import fields, models
class SqlExport(models.Model):
_name = "sql.export"
- _inherit = ['sql.request.mixin']
+ _inherit = ["sql.request.mixin"]
_description = "SQL export"
- _sql_request_groups_relation = 'groups_sqlquery_rel'
+ _sql_request_groups_relation = "groups_sqlquery_rel"
- _sql_request_users_relation = 'users_sqlquery_rel'
+ _sql_request_users_relation = "users_sqlquery_rel"
_check_execution_enabled = False
copy_options = fields.Char(
- string='Copy Options', required=False,
- default="CSV HEADER DELIMITER ';'")
+ string="Copy Options", required=False, default="CSV HEADER DELIMITER ';'"
+ )
- file_format = fields.Selection(
- [('csv', 'CSV')],
- default='csv',
- required=True)
+ file_format = fields.Selection([("csv", "CSV")], default="csv", required=True)
field_ids = fields.Many2many(
- 'ir.model.fields',
- 'fields_sqlquery_rel',
- 'sql_id',
- 'field_id',
- 'Parameters',
- domain=[('model', '=', 'sql.file.wizard')])
+ "ir.model.fields",
+ "fields_sqlquery_rel",
+ "sql_id",
+ "field_id",
+ "Parameters",
+ domain=[("model", "=", "sql.file.wizard")],
+ )
encoding = fields.Selection(
- [('utf-8', 'utf-8'), ('utf-16', 'utf-16'),
- ('windows-1252', 'windows-1252'), ('latin1', 'latin1'),
- ('latin2', 'latin2'), ('big5', 'big5'), ('gb18030', 'gb18030'),
- ('shift_jis', 'shift_jis'), ('windows-1251', 'windows-1251'),
- ('koir8_r', 'koir8_r')], string='Encoding', required=True,
- default='utf-8')
+ [
+ ("utf-8", "utf-8"),
+ ("utf-16", "utf-16"),
+ ("windows-1252", "windows-1252"),
+ ("latin1", "latin1"),
+ ("latin2", "latin2"),
+ ("big5", "big5"),
+ ("gb18030", "gb18030"),
+ ("shift_jis", "shift_jis"),
+ ("windows-1251", "windows-1251"),
+ ("koir8_r", "koir8_r"),
+ ],
+ string="Encoding",
+ required=True,
+ default="utf-8",
+ )
def export_sql_query(self):
self.ensure_one()
- wiz = self.env['sql.file.wizard'].create({
- 'sql_export_id': self.id})
+ wiz = self.env["sql.file.wizard"].create({"sql_export_id": self.id})
return {
- 'view_mode': 'form',
- 'res_model': 'sql.file.wizard',
- 'res_id': wiz.id,
- 'type': 'ir.actions.act_window',
- 'target': 'new',
- 'context': self.env.context,
- 'nodestroy': True,
+ "view_mode": "form",
+ "res_model": "sql.file.wizard",
+ "res_id": wiz.id,
+ "type": "ir.actions.act_window",
+ "target": "new",
+ "context": self.env.context,
+ "nodestroy": True,
}
def _get_file_extension(self):
self.ensure_one()
- if self.file_format == 'csv':
- return 'csv'
+ if self.file_format == "csv":
+ return "csv"
def csv_get_data_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)
+ 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/readme/USAGE.rst b/sql_export/readme/USAGE.rst
index db24ef73b..33178ae36 100644
--- a/sql_export/readme/USAGE.rst
+++ b/sql_export/readme/USAGE.rst
@@ -6,5 +6,5 @@ Dashboards > Sql Export
- `%(company_id)s` allows to set in the query the company id of the user
- `%(user_id)s` allows to set in the query the user id
-- for any created field with `Sql Export Variables` menu, you can use it with `%(x_field_example)s` syntax
+- for any created field with `Sql Export Variables` menu, you can use it with `%(x_field_example)s` syntax
(Limitation for relational fields)
diff --git a/sql_export/security/sql_export_security.xml b/sql_export/security/sql_export_security.xml
index 7bc29279a..0b6ac56c0 100644
--- a/sql_export/security/sql_export_security.xml
+++ b/sql_export/security/sql_export_security.xml
@@ -1,14 +1,16 @@
-
+
- SQL Export users and groups rules
-
-
-
-
-
- ['|', ('user_ids','=',user.id), ('group_ids','in', [x.id for x in user.groups_id])]
+ SQL Export users and groups rules
+
+
+
+
+
+ ['|', ('user_ids','=',user.id), ('group_ids','in', [x.id for x in user.groups_id])]
diff --git a/sql_export/tests/test_sql_query.py b/sql_export/tests/test_sql_query.py
index 7b0c48b73..f794b8abb 100644
--- a/sql_export/tests/test_sql_query.py
+++ b/sql_export/tests/test_sql_query.py
@@ -3,28 +3,30 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import base64
-from odoo.tests.common import TransactionCase, post_install
-from odoo.exceptions import UserError
+
from odoo import fields
+from odoo.exceptions import UserError
+from odoo.tests.common import TransactionCase, post_install
@post_install(True)
class TestExportSqlQuery(TransactionCase):
-
def setUp(self):
super(TestExportSqlQuery, self).setUp()
- self.sql_export_obj = self.env['sql.export']
- self.wizard_obj = self.env['sql.file.wizard']
- self.sql_report_demo = self.env.ref('sql_export.sql_export_partner')
+ self.sql_export_obj = self.env["sql.export"]
+ self.wizard_obj = self.env["sql.file.wizard"]
+ self.sql_report_demo = self.env.ref("sql_export.sql_export_partner")
def test_sql_query(self):
- wizard = self.wizard_obj.create({
- 'sql_export_id': self.sql_report_demo.id,
- })
+ wizard = self.wizard_obj.create(
+ {
+ "sql_export_id": self.sql_report_demo.id,
+ }
+ )
wizard.export_sql()
- export = base64.b64decode(wizard.binary_file).decode('utf-8')
- self.assertEqual(export.split(';')[0], 'name')
- self.assertTrue(len(export.split(';')) > 6)
+ export = base64.b64decode(wizard.binary_file).decode("utf-8")
+ self.assertEqual(export.split(";")[0], "name")
+ self.assertTrue(len(export.split(";")) > 6)
def test_prohibited_queries(self):
prohibited_queries = [
@@ -39,9 +41,9 @@ class TestExportSqlQuery(TransactionCase):
]
for query in prohibited_queries:
with self.assertRaises(UserError):
- sql_export = self.sql_export_obj.create({
- 'name': 'test_prohibited',
- 'query': query})
+ sql_export = self.sql_export_obj.create(
+ {"name": "test_prohibited", "query": query}
+ )
sql_export.button_validate_sql_expression()
def test_authorized_queries(self):
@@ -50,23 +52,25 @@ class TestExportSqlQuery(TransactionCase):
]
for query in authorized_queries:
- sql_export = self.sql_export_obj.create({
- 'name': 'test_authorized',
- 'query': query})
+ sql_export = self.sql_export_obj.create(
+ {"name": "test_authorized", "query": query}
+ )
sql_export.button_validate_sql_expression()
self.assertEqual(
- sql_export.state, 'sql_valid',
- "%s is a valid request" % (query))
+ sql_export.state, "sql_valid", "%s is a valid request" % (query)
+ )
def test_sql_query_with_params(self):
- query = self.env.ref('sql_export.sql_export_partner_with_variables')
- categ_id = self.env.ref('base.res_partner_category_0').id
- wizard = self.wizard_obj.create({
- 'sql_export_id': query.id,
- 'x_date': fields.Date.today(),
- 'x_id': 1,
- 'x_partner_categ_ids': [(6, 0, [categ_id])]
- })
+ query = self.env.ref("sql_export.sql_export_partner_with_variables")
+ categ_id = self.env.ref("base.res_partner_category_0").id
+ wizard = self.wizard_obj.create(
+ {
+ "sql_export_id": query.id,
+ "x_date": fields.Date.today(),
+ "x_id": 1,
+ "x_partner_categ_ids": [(6, 0, [categ_id])],
+ }
+ )
wizard.export_sql()
export = base64.b64decode(wizard.binary_file)
self.assertTrue(export)
diff --git a/sql_export/views/sql_export_view.xml b/sql_export/views/sql_export_view.xml
index 12b48e479..f6350ec95 100644
--- a/sql_export/views/sql_export_view.xml
+++ b/sql_export/views/sql_export_view.xml
@@ -1,4 +1,4 @@
-
+
Sql_export_form_view
@@ -6,37 +6,71 @@
@@ -61,31 +100,43 @@
SQL Export
sql.export
- form
tree,form
-
+
-
+
Sql_parameter_form_view
ir.model.fields
- 150
+ 150
@@ -93,13 +144,13 @@
Sql_parameter_tree_view
ir.model.fields
- 150
+ 150
-
-
-
-
+
+
+
+
@@ -107,26 +158,35 @@
SQL Parameter
ir.model.fields
- form
tree,form
-
+
[('model','=','sql.file.wizard')]
-
+
tree
-
-
+
+
-
+
form
-
-
+
+
-
+
diff --git a/sql_export/wizard/wizard_file.py b/sql_export/wizard/wizard_file.py
index 5b6ed3dc5..224448821 100644
--- a/sql_export/wizard/wizard_file.py
+++ b/sql_export/wizard/wizard_file.py
@@ -3,9 +3,10 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from datetime import datetime
+
from lxml import etree
-from odoo import models, fields, api, osv
+from odoo import api, fields, models, osv
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
@@ -13,43 +14,41 @@ class SqlFileWizard(models.TransientModel):
_name = "sql.file.wizard"
_description = "Allow the user to save the file with sql request's data"
- binary_file = fields.Binary('File', readonly=True)
- file_name = fields.Char('File Name', readonly=True)
- sql_export_id = fields.Many2one(comodel_name='sql.export', required=True)
+ binary_file = fields.Binary("File", readonly=True)
+ file_name = fields.Char("File Name", readonly=True)
+ sql_export_id = fields.Many2one(comodel_name="sql.export", required=True)
@api.model
- def fields_view_get(self, view_id=None, view_type='form',
- toolbar=False, submenu=False):
+ def fields_view_get(
+ self, view_id=None, view_type="form", toolbar=False, submenu=False
+ ):
"""
Display dynamically parameter fields depending on the sql_export.
"""
res = super(SqlFileWizard, self).fields_view_get(
- view_id=view_id, view_type=view_type, toolbar=toolbar,
- submenu=submenu)
- export_obj = self.env['sql.export']
- if view_type == 'form':
- sql_export = export_obj.browse(self.env.context.get('active_id'))
+ view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu
+ )
+ export_obj = self.env["sql.export"]
+ if view_type == "form":
+ sql_export = export_obj.browse(self.env.context.get("active_id"))
if sql_export.field_ids:
- eview = etree.fromstring(res['arch'])
- group = etree.Element(
- 'group', name="variables_group", colspan="4")
+ eview = etree.fromstring(res["arch"])
+ group = etree.Element("group", name="variables_group", colspan="4")
toupdate_fields = []
for field in sql_export.field_ids:
toupdate_fields.append(field.name)
- attrib = {'name': field.name}
+ attrib = {"name": field.name}
if field.required:
- attrib['required'] = 'True'
- view_field = etree.SubElement(
- group, 'field', attrib=attrib)
- osv.orm.setup_modifiers(
- view_field, self.fields_get(field.name))
+ attrib["required"] = "True"
+ view_field = etree.SubElement(group, "field", attrib=attrib)
+ osv.orm.setup_modifiers(view_field, self.fields_get(field.name))
- res['fields'].update(self.fields_get(toupdate_fields))
+ res["fields"].update(self.fields_get(toupdate_fields))
placeholder = eview.xpath(
- "//separator[@string='variables_placeholder']")[0]
- placeholder.getparent().replace(
- placeholder, group)
- res['arch'] = etree.tostring(eview, pretty_print=True)
+ "//separator[@string='variables_placeholder']"
+ )[0]
+ placeholder.getparent().replace(placeholder, group)
+ res["arch"] = etree.tostring(eview, pretty_print=True)
return res
def export_sql(self):
@@ -62,37 +61,39 @@ class SqlFileWizard(models.TransientModel):
date = now_tz.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
if sql_export.field_ids:
for field in sql_export.field_ids:
- if field.ttype == 'many2one':
+ if field.ttype == "many2one":
variable_dict[field.name] = self[field.name].id
- elif field.ttype == 'many2many':
+ elif field.ttype == "many2many":
variable_dict[field.name] = tuple(self[field.name].ids)
else:
variable_dict[field.name] = self[field.name]
if "%(company_id)s" in sql_export.query:
company_id = self.env.context.get(
- 'force_company', self.env.user.company_id.id)
- variable_dict['company_id'] = company_id
+ "force_company", self.env.user.company_id.id
+ )
+ variable_dict["company_id"] = company_id
if "%(user_id)s" in sql_export.query:
- user_id = self.env.context.get(
- 'force_user', self._uid)
- variable_dict['user_id'] = user_id
+ user_id = self.env.context.get("force_user", self._uid)
+ variable_dict["user_id"] = user_id
# Call different method depending on file_type since the logic will be
# different
- method_name = '%s_get_data_from_query' % sql_export.file_format
+ 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': data,
- 'file_name': '%(name)s_%(date)s.%(extension)s' % {
- 'name': sql_export.name, 'date': date, 'extension': extension}
- })
+ self.write(
+ {
+ "binary_file": data,
+ "file_name": "%(name)s_%(date)s.%(extension)s"
+ % {"name": sql_export.name, "date": date, "extension": extension},
+ }
+ )
return {
- 'view_mode': 'form',
- 'res_model': 'sql.file.wizard',
- 'res_id': self.id,
- 'type': 'ir.actions.act_window',
- 'target': 'new',
- 'context': self.env.context,
- 'nodestroy': True,
+ "view_mode": "form",
+ "res_model": "sql.file.wizard",
+ "res_id": self.id,
+ "type": "ir.actions.act_window",
+ "target": "new",
+ "context": self.env.context,
+ "nodestroy": True,
}
diff --git a/sql_export/wizard/wizard_file_view.xml b/sql_export/wizard/wizard_file_view.xml
index 3b6be8bfb..219ad6f5d 100644
--- a/sql_export/wizard/wizard_file_view.xml
+++ b/sql_export/wizard/wizard_file_view.xml
@@ -1,4 +1,4 @@
-
+
@@ -7,17 +7,32 @@
sql.file.wizard