diff --git a/odex25_base/query_deluxe/__init__.py b/odex25_base/query_deluxe/__init__.py
new file mode 100644
index 000000000..cf6c429c6
--- /dev/null
+++ b/odex25_base/query_deluxe/__init__.py
@@ -0,0 +1,3 @@
+from . import wizard
+from . import report
+from . import models
diff --git a/odex25_base/query_deluxe/__manifest__.py b/odex25_base/query_deluxe/__manifest__.py
new file mode 100644
index 000000000..33dc306c0
--- /dev/null
+++ b/odex25_base/query_deluxe/__manifest__.py
@@ -0,0 +1,28 @@
+{
+ 'name': 'PostgreSQL Query Deluxe',
+ 'description': 'Execute postgreSQL query into Odoo interface',
+ 'author': 'Yvan Dotet',
+ 'depends': ['base', 'mail'],
+ 'application': True,
+ 'version': '14.0.1.0.4',
+ 'license': 'AGPL-3',
+ 'support': 'yvandotet@yahoo.fr',
+ 'website': 'https://github.com/YvanDotet/query_deluxe/',
+ 'installable': True,
+
+ 'data': [
+ 'security/security.xml',
+ 'security/ir.model.access.csv',
+
+ 'views/query_deluxe_views.xml',
+
+ 'wizard/pdforientation.xml',
+
+ 'report/print_pdf.xml',
+
+ 'datas/data.xml'
+ ],
+
+ 'images': ['static/description/banner.gif']
+}
+
diff --git a/odex25_base/query_deluxe/datas/data.xml b/odex25_base/query_deluxe/datas/data.xml
new file mode 100644
index 000000000..394a8e68e
--- /dev/null
+++ b/odex25_base/query_deluxe/datas/data.xml
@@ -0,0 +1,85 @@
+
+
+
+ SELECT name,phone,email FROM res_partner;
+ Display all the records of res.partner's model, with name, phone and email attributes.
+
+
+
+ SELECT * FROM pg_catalog.pg_tables;
+ Display all the tables inside that database
+
+
+
+ SELECT datname FROM pg_database;
+ List of all the databases inside that postgreSQL
+
+
+
+ SELECT * FROM pg_user;
+ List of all the users using that postgreSQL
+
+
+
+ SELECT version();
+ The version of that postgreSQL
+
+
+
+ SELECT * FROM sale_order WHERE partner_id IN (SELECT id FROM res_partner WHERE name ILIKE '%Johnson%') LIMIT 5;
+ Show only the 5 first records of sale.order's model where their client have 'Johnson' in their name
+
+
+
+
+ WITH temporary_table AS (
+ SELECT pt.id AS pt_id, pp.id AS pp_id
+ FROM product_template pt
+ LEFT JOIN product_product pp
+ ON pp.product_tmpl_id = pt.id
+ )
+ SELECT * FROM temporary_table ORDER BY pt_id;
+
+ Associate each product template with their product variant
+
+
+
+ UPDATE res_users SET password = 'my_45_password' WHERE id = 10;
+ Modify the password to 'my_45_password' for the user with id = 10
+
+
+
+ UPDATE res_partner AS a SET email = CONCAT(a.name,'@company_mail.com');
+ Modify all the email of the contact within the rule 'name of the contact'+'@company_mail.com'
+
+
+
+ DELETE FROM sale_order WHERE write_date <= '2017-12-31'::date;
+ Delete old sale_orders that was last modified before the 2018 year
+
+
+
+ SELECT a.name,b.name FROM res_partner a INNER JOIN sale_order b ON a.id=b.partner_id;
+ Select the clients linked with their sales orders
+
+
+
+ CREATE TABLE mytable ( id Integer , name char(10) , description char(40) );
+ Create a table 'mytable' with a column for id,name and description
+
+
+
+ INSERT INTO mytable VALUES ( 30 , 'first rec' , 'this is a the first record' );
+ Insert row in the table 'mytable' with the corresponding column and type
+
+
+
+ ALTER DATABASE mycurrentdatabasename RENAME TO newnamefordatabase;
+ Give a new name to a database
+
+
+
+ DROP TABLE mytable;
+ Drop the table 'mytable'
+
+
diff --git a/odex25_base/query_deluxe/doc/index.rst b/odex25_base/query_deluxe/doc/index.rst
new file mode 100644
index 000000000..a761b2e0e
--- /dev/null
+++ b/odex25_base/query_deluxe/doc/index.rst
@@ -0,0 +1,39 @@
+==============
+query_deluxe
+==============
+
+This module is usefull to make postgreSQL's queries directly from an Odoo interface.
+
+You can type queries involving SELECT statement and many clauses like WHERE, AND, etc ...
+
+The result is correctly presented in a table form.
+
+You can also make UPDATE, DELETE, CREATE, INSERT, ALTER and DROP statements.
+
+Usage
+=====
+
+Go to "Apps" menu and type "query_deluxe" into the search box.
+
+Odoo version 14
+
+Credits
+=======
+
+Authors
+~~~~~~~
+
+* Yvan Dotet
+
+Maintainers
+~~~~~~~~~~~
+
+* This module is maintained by Yvan Dotet.
+
+Contact
+~~~~~~~
+
+* Mail address of Yvan Dotet : Yvandotet@yahoo.fr
+* website :
+ 1) https://github.com/YvanDotet/query_deluxe
+ 2) https://be.linkedin.com/in/yvan-dotet-19ba67135
diff --git a/odex25_base/query_deluxe/i18n/fr_BE.po b/odex25_base/query_deluxe/i18n/fr_BE.po
new file mode 100644
index 000000000..30f876dba
--- /dev/null
+++ b/odex25_base/query_deluxe/i18n/fr_BE.po
@@ -0,0 +1,493 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * query_deluxe
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-11-17 19:50+0000\n"
+"PO-Revision-Date: 2022-11-17 19:50+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: query_deluxe
+#: model:res.groups,name:query_deluxe.group_query_deluxe
+msgid "Access query_deluxe"
+msgstr "Accès query_deluxe"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_needaction
+msgid "Action Needed"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_ids
+msgid "Activities"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_exception_decoration
+msgid "Activity Exception Decoration"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_state
+msgid "Activity State"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_type_icon
+msgid "Activity Type Icon"
+msgstr ""
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.with_product_table
+msgid "Associate each product template with their product variant"
+msgstr "Associe chaque produit template avec leurs produits variants"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_attachment_count
+msgid "Attachment Count"
+msgstr ""
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.pdforientation_form
+msgid "Cancel"
+msgstr "Annuler"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Copy"
+msgstr "Copier"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.create_table_mytable
+msgid "Create a table 'mytable' with a column for id,name and description"
+msgstr ""
+"Créée une table 'mytable' avec une colonne pour l'id, le nom et la "
+"description"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__create_uid
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__create_uid
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__create_uid
+msgid "Created by"
+msgstr "Créé par"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__create_date
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__create_date
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__create_date
+msgid "Created on"
+msgstr "Créé le"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.delete_sale_order
+msgid "Delete old sale_orders that was last modified before the 2018 year"
+msgstr ""
+"Supprime les anciens devis qui ont été modifiés pour la dernière fois avant "
+"l'année 2018"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__tips_description
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__description
+#: model_terms:ir.ui.view,arch_db:query_deluxe.tips_queries_view_tree
+msgid "Description"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__display_name
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__display_name
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_res_partner
+msgid ""
+"Display all the records of res.partner's model, with name, phone and email "
+"attributes."
+msgstr ""
+"Affiche tous les enregistrements du modèle de res.partner, avec leur noms, "
+"numéros de téléphone et emails."
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_pg_catalog_pg_table
+msgid "Display all the tables inside that database"
+msgstr "Affiche toutes les tables de cette base de données"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.drop_table_mytable
+msgid "Drop the table 'mytable'"
+msgstr "Efface la table 'mytable'"
+
+#. module: query_deluxe
+#: model:ir.actions.act_window,name:query_deluxe.query_deluxe_submenu_tipsqueries_action
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__tips
+#: model:ir.ui.menu,name:query_deluxe.query_deluxe_submenu_tipsqueries
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Examples"
+msgstr "Exemples"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Examples :"
+msgstr "Exemples :"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Execute"
+msgstr "Exécuter"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_follower_ids
+msgid "Followers"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_channel_ids
+msgid "Followers (Channels)"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_partner_ids
+msgid "Followers (Partners)"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__activity_type_icon
+msgid "Font awesome icon e.g. fa-tasks"
+msgstr ""
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.alter_database_rename
+msgid "Give a new name to a database"
+msgstr "Donne un nouveau nom à une base de données"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__html
+msgid "HTML"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__id
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__id
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__id
+msgid "ID"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_exception_icon
+msgid "Icon"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__activity_exception_icon
+msgid "Icon to indicate an exception activity."
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__message_needaction
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__message_unread
+msgid "If checked, new messages require your attention."
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__message_has_error
+msgid "If checked, some messages have a delivery error."
+msgstr ""
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.insert_into_mytable
+msgid ""
+"Insert row in the table 'mytable' with the corresponding column and type"
+msgstr ""
+"Insére une ligne dans la table 'mytable' avec la colonne et le type "
+"correspondants"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_is_follower
+msgid "Is Follower"
+msgstr ""
+
+#. module: query_deluxe
+#: code:addons/query_deluxe/wizard/pdforientation.py:0
+#, python-format
+msgid "Landscape"
+msgstr "Paysage"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation____last_update
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe____last_update
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries____last_update
+msgid "Last Modified on"
+msgstr "Dernière modification le"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__write_uid
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__write_uid
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__write_uid
+msgid "Last Updated by"
+msgstr "Dernière mise à jour par"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__write_date
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__write_date
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__write_date
+msgid "Last Updated on"
+msgstr "Dernière mise à jour le"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_datname_pg_database
+msgid "List of all the databases inside that postgreSQL"
+msgstr "Liste de toutes les bases de données à l'intérieur de ce postgreSQL"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_pg_user
+msgid "List of all the users using that postgreSQL"
+msgstr "Liste de tous les utilisateurs utilisant ce postgreSQL"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_main_attachment_id
+msgid "Main Attachment"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_has_error
+msgid "Message Delivery error"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_ids
+msgid "Messages"
+msgstr ""
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.update_res_partner_email
+msgid ""
+"Modify all the email of the contact within the rule 'name of the "
+"contact'+'@company_mail.com'"
+msgstr ""
+"Modifie tous les emails de contact avec la règle suivante : 'nom du "
+"contact'+'@company_mail.com'"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.update_res_users_password
+msgid "Modify the password to 'my_45_password' for the user with id = 10"
+msgstr ""
+"Modifie le mot de passe en 'my_45_password' pour l'utilisateur d'id = 10"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__my_activity_date_deadline
+msgid "My Activity Deadline"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_date_deadline
+msgid "Next Activity Deadline"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_summary
+msgid "Next Activity Summary"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_type_id
+msgid "Next Activity Type"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_needaction_counter
+msgid "Number of Actions"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_has_error_counter
+msgid "Number of errors"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__message_needaction_counter
+msgid "Number of messages which requires an action"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__message_has_error_counter
+msgid "Number of messages with delivery error"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__message_unread_counter
+msgid "Number of unread messages"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__orientation
+msgid "PDF orientation"
+msgstr "Orientation du PDF"
+
+#. module: query_deluxe
+#: code:addons/query_deluxe/wizard/pdforientation.py:0
+#, python-format
+msgid "Portrait"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model,name:query_deluxe.model_querydeluxe
+msgid "Postgres queries from Odoo interface"
+msgstr "Requête PostgreSQL depuis l'interface Odoo"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.pdforientation_form
+msgid "Print"
+msgstr "Imprimer"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Print PDF"
+msgstr "Imprimer PDF"
+
+#. module: query_deluxe
+#: model:ir.actions.act_window,name:query_deluxe.query_deluxe_submenu_querydeluxe_action
+#: model:ir.ui.menu,name:query_deluxe.query_deluxe_submenu_querydeluxe
+msgid "Queries"
+msgstr "Requêtes"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_pdforientation__query_name
+#: model:ir.model.fields,field_description:query_deluxe.field_tipsqueries__name
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_tree
+#: model_terms:ir.ui.view,arch_db:query_deluxe.tips_queries_view_tree
+msgid "Query"
+msgstr "Requête"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Query :"
+msgstr "Requête :"
+
+#. module: query_deluxe
+#: model:ir.ui.menu,name:query_deluxe.query_deluxe_menu
+msgid "Query Deluxe"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.actions.report,name:query_deluxe.action_print_pdf
+msgid "Query result"
+msgstr "Résultat de la requête"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__raw_output
+msgid "Raw output"
+msgstr "Données brutes"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__activity_user_id
+msgid "Responsible User"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__rowcount
+msgid "Rowcount"
+msgstr ""
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "SELECT * FROM res_partner"
+msgstr ""
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.tips_queries_view_search
+msgid "Search"
+msgstr ""
+
+#. module: query_deluxe
+#: code:addons/query_deluxe/models/query_deluxe.py:0
+#, python-format
+msgid "Select orientation of the PDF's result"
+msgstr "Sélectionner l'orientation du PDF"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_res_partner_inner_join_sale_order
+msgid "Select the clients linked with their sales orders"
+msgstr "Sélectionne les clients liés à leurs devis"
+
+#. module: query_deluxe
+#: model:ir.model,name:query_deluxe.model_pdforientation
+msgid "Select the orientation of the pdf"
+msgstr "Sélectionner l'orientation du PDF"
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_sale_order
+msgid ""
+"Show only the 5 first records of sale.order's model where their client have "
+"'Johnson' in their name"
+msgstr ""
+"Affiche uniquement les 5 premiers enregistrements du modèle de sale.order où"
+" leur client possède 'Johnson' dans leur nom"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__show_raw_output
+msgid "Show the raw output of the query"
+msgstr "Montrer les données brutes de la requête"
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__activity_state
+msgid ""
+"Status based on activities\n"
+"Overdue: Due date is already passed\n"
+"Today: Activity date is today\n"
+"Planned: Future activities."
+msgstr ""
+
+#. module: query_deluxe
+#: model:tipsqueries,description:query_deluxe.select_versions
+msgid "The version of that postgreSQL"
+msgstr "La version de ce postgreSQL"
+
+#. module: query_deluxe
+#: model:ir.model,name:query_deluxe.model_tipsqueries
+msgid "Tips for queries"
+msgstr "Conseils pour les requêtes"
+
+#. module: query_deluxe
+#: model_terms:ir.ui.view,arch_db:query_deluxe.query_deluxe_view_form
+msgid "Type a query"
+msgstr "Ecrivez une requête"
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__name
+msgid "Type a query : "
+msgstr "Ecrivez une requête :"
+
+#. module: query_deluxe
+#: model:ir.model.fields,help:query_deluxe.field_querydeluxe__activity_exception_decoration
+msgid "Type of the exception activity on record."
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_unread
+msgid "Unread Messages"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__message_unread_counter
+msgid "Unread Messages Counter"
+msgstr ""
+
+#. module: query_deluxe
+#: model:ir.model.fields,field_description:query_deluxe.field_querydeluxe__valid_query_name
+msgid "Valid Query Name"
+msgstr ""
+
+#. module: query_deluxe
+#: code:addons/query_deluxe/models/query_deluxe.py:0
+#, python-format
+msgid "{0} row{1} processed"
+msgstr "{0} ligne{1} traitée{1}"
diff --git a/odex25_base/query_deluxe/models/__init__.py b/odex25_base/query_deluxe/models/__init__.py
new file mode 100644
index 000000000..d347c2ec3
--- /dev/null
+++ b/odex25_base/query_deluxe/models/__init__.py
@@ -0,0 +1 @@
+from . import query_deluxe
diff --git a/odex25_base/query_deluxe/models/query_deluxe.py b/odex25_base/query_deluxe/models/query_deluxe.py
new file mode 100644
index 000000000..aadffcc19
--- /dev/null
+++ b/odex25_base/query_deluxe/models/query_deluxe.py
@@ -0,0 +1,115 @@
+from odoo import api, fields, models, _
+from odoo.exceptions import UserError
+
+
+class QueryDeluxe(models.Model):
+ _name = "querydeluxe"
+ _description = "Postgres queries from Odoo interface"
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+
+ tips = fields.Many2one('tipsqueries', string="Examples")
+ tips_description = fields.Text(related='tips.description')
+
+ rowcount = fields.Text(string='Rowcount')
+ html = fields.Html(string='HTML')
+
+ name = fields.Text(string='Type a query : ')
+ valid_query_name = fields.Text()
+
+ show_raw_output = fields.Boolean(string='Show the raw output of the query')
+ raw_output = fields.Text(string='Raw output')
+
+ def print_result(self):
+ self.ensure_one()
+
+ return {
+ 'name': _("Select orientation of the PDF's result"),
+ 'view_mode': 'form',
+ 'res_model': 'pdforientation',
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'context': {
+ 'default_query_name': self.valid_query_name
+ },
+ }
+
+ def copy_query(self):
+ self.ensure_one()
+
+ if self.tips:
+ self.name = self.tips.name
+
+ def execute(self):
+ self = self.sudo()
+ self.ensure_one()
+
+ self.show_raw_output = False
+ self.raw_output = ''
+
+ self.rowcount = ''
+ self.html = '
'
+
+ self.valid_query_name = ''
+
+ if self.name:
+ self.tips = False
+ self.message_post(body=str(self.name))
+
+ headers = []
+ datas = []
+
+ try:
+ self.env.cr.execute(self.name)
+ except Exception as e:
+ raise UserError(e)
+
+ try:
+ if self.env.cr.description:
+ headers = [d[0] for d in self.env.cr.description]
+ datas = self.env.cr.fetchall()
+ except Exception as e:
+ raise UserError(e)
+
+ rowcount = self.env.cr.rowcount
+ self.rowcount = _("{0} row{1} processed").format(rowcount, 's' if 1 < rowcount else '')
+
+ if headers and datas:
+ self.valid_query_name = self.name
+ self.raw_output = datas
+
+ header_html = "
| "
+ header_html += "".join(["" + str(header) + " | " for header in headers])
+ header_html += "
"
+
+ body_html = ""
+ i = 0
+ for data in datas:
+ i += 1
+ body_line = " | {1} | ".format('cyan' if i%2 == 0 else 'white', i)
+ for value in data:
+ display_value = ''
+ if value is not None:
+ display_value = str(value).replace("&", "&").replace("<", "<").replace(">", ">")
+ body_line += "{0} | ".format(display_value)
+ body_line += "
"
+ body_html += body_line
+
+ self.html = """
+
+""".format(header_html, body_html)
+
+
+class TipsQueries(models.Model):
+ _name = 'tipsqueries'
+ _description = "Tips for queries"
+
+ name = fields.Text(string='Query', required=True)
+ description = fields.Text(string="Description", translate=True)
diff --git a/odex25_base/query_deluxe/report/__init__.py b/odex25_base/query_deluxe/report/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/odex25_base/query_deluxe/report/print_pdf.xml b/odex25_base/query_deluxe/report/print_pdf.xml
new file mode 100644
index 000000000..47906e19b
--- /dev/null
+++ b/odex25_base/query_deluxe/report/print_pdf.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Paperformat query deluxe
+
+ A4
+ 0
+ 0
+ Landscape
+ 3
+ 3
+ 3
+ 3
+
+ 3
+ 80
+
+
+
+ Query result
+ pdforientation
+ query_deluxe.pdf
+ qweb-pdf
+
+
+
diff --git a/odex25_base/query_deluxe/security/ir.model.access.csv b/odex25_base/query_deluxe/security/ir.model.access.csv
new file mode 100644
index 000000000..8b0ff727a
--- /dev/null
+++ b/odex25_base/query_deluxe/security/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_querydeluxe,querydeluxe access,query_deluxe.model_querydeluxe,query_deluxe.group_query_deluxe,1,1,1,1
+access_pdforientation,pdforientation access,query_deluxe.model_pdforientation,query_deluxe.group_query_deluxe,1,1,1,1
+access_tipsqueries,tipsqueries access,query_deluxe.model_tipsqueries,query_deluxe.group_query_deluxe,1,1,1,1
diff --git a/odex25_base/query_deluxe/security/security.xml b/odex25_base/query_deluxe/security/security.xml
new file mode 100644
index 000000000..8dfd31516
--- /dev/null
+++ b/odex25_base/query_deluxe/security/security.xml
@@ -0,0 +1,14 @@
+
+
+
+ Access query_deluxe
+
+
+
+
+
+
+
+
+
+
diff --git a/odex25_base/query_deluxe/static/description/banner.gif b/odex25_base/query_deluxe/static/description/banner.gif
new file mode 100644
index 000000000..995dd2b0a
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/banner.gif differ
diff --git a/odex25_base/query_deluxe/static/description/copy_query.png b/odex25_base/query_deluxe/static/description/copy_query.png
new file mode 100644
index 000000000..3bad42175
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/copy_query.png differ
diff --git a/odex25_base/query_deluxe/static/description/example_query.png b/odex25_base/query_deluxe/static/description/example_query.png
new file mode 100644
index 000000000..e304aa2e5
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/example_query.png differ
diff --git a/odex25_base/query_deluxe/static/description/find_example.png b/odex25_base/query_deluxe/static/description/find_example.png
new file mode 100644
index 000000000..716876129
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/find_example.png differ
diff --git a/odex25_base/query_deluxe/static/description/history.png b/odex25_base/query_deluxe/static/description/history.png
new file mode 100644
index 000000000..cc7b1b55e
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/history.png differ
diff --git a/odex25_base/query_deluxe/static/description/icon.png b/odex25_base/query_deluxe/static/description/icon.png
new file mode 100644
index 000000000..6dfd0a2f1
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/icon.png differ
diff --git a/odex25_base/query_deluxe/static/description/index.html b/odex25_base/query_deluxe/static/description/index.html
new file mode 100644
index 000000000..6bc0fe124
--- /dev/null
+++ b/odex25_base/query_deluxe/static/description/index.html
@@ -0,0 +1,100 @@
+
+
+
+

+
+
+
+
+
+
+
The complete app for making easy queries in PostgreSQL
+
Explore your PostgreSQL database with query into an Odoo interface
+
+

+
+
+ You can use SELECT, UPDATE, DELETE, CREATE, INSERT, ALTER and DROP statements.
+
+
+
+
+
+
+
Find examples
+
Remember useful queries
+
+

+
+
+
+
+ Get a description of what the query does.
+
+
+
+
+

+
+
+
+
+
+
+
Memorize your own example
+
Save repetitive query
+
+
+ You can store your own query to re-use it quickly.
+
+
+

+
+
+
+
+
+
+
+
+
Print your result
+
PDF format
+
+ Print your table's result in a PDF format, landscape or portrait orientation.
+
+
+
+

+
+
+

+
+
+
+
+
+
+
History
+
History of your previous queries
+
+
+ You can retrieve the last queries you have typed.
+
+
+
+

+
+
+
+
+
diff --git a/odex25_base/query_deluxe/static/description/own_example.png b/odex25_base/query_deluxe/static/description/own_example.png
new file mode 100644
index 000000000..d0a4acb38
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/own_example.png differ
diff --git a/odex25_base/query_deluxe/static/description/pdf.png b/odex25_base/query_deluxe/static/description/pdf.png
new file mode 100644
index 000000000..9684f0dd6
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/pdf.png differ
diff --git a/odex25_base/query_deluxe/static/description/print_pdf.png b/odex25_base/query_deluxe/static/description/print_pdf.png
new file mode 100644
index 000000000..df91aa5f0
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/print_pdf.png differ
diff --git a/odex25_base/query_deluxe/static/description/simple_query.png b/odex25_base/query_deluxe/static/description/simple_query.png
new file mode 100644
index 000000000..47dd57975
Binary files /dev/null and b/odex25_base/query_deluxe/static/description/simple_query.png differ
diff --git a/odex25_base/query_deluxe/views/query_deluxe_views.xml b/odex25_base/query_deluxe/views/query_deluxe_views.xml
new file mode 100644
index 000000000..509a170a7
--- /dev/null
+++ b/odex25_base/query_deluxe/views/query_deluxe_views.xml
@@ -0,0 +1,110 @@
+
+
+
+
+ Type a query tree
+ querydeluxe
+
+
+
+
+
+
+
+
+ Type a query form
+ querydeluxe
+
+
+
+
+
+
+
+
+ Memorize a query tree
+ tipsqueries
+
+
+
+
+
+
+
+
+
+ Search a query
+ tipsqueries
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/odex25_base/query_deluxe/wizard/__init__.py b/odex25_base/query_deluxe/wizard/__init__.py
new file mode 100644
index 000000000..68c701d23
--- /dev/null
+++ b/odex25_base/query_deluxe/wizard/__init__.py
@@ -0,0 +1 @@
+from . import pdforientation
diff --git a/odex25_base/query_deluxe/wizard/pdforientation.py b/odex25_base/query_deluxe/wizard/pdforientation.py
new file mode 100644
index 000000000..de475ec48
--- /dev/null
+++ b/odex25_base/query_deluxe/wizard/pdforientation.py
@@ -0,0 +1,40 @@
+from odoo import api, fields, models, _
+from odoo.exceptions import UserError
+
+
+class PdfOrientation(models.TransientModel):
+ _name = 'pdforientation'
+ _description = "Select the orientation of the pdf"
+
+ def orientation_choices(self):
+ return [('landscape', _('Landscape')), ('portrait', _('Portrait'))]
+
+ orientation = fields.Selection(string="PDF orientation", selection=orientation_choices, default='landscape')
+ query_name = fields.Text(string="Query")
+
+ def print_pdf(self):
+ self = self.sudo()
+ try:
+ self.env.cr.execute(self.query_name)
+ except Exception as e:
+ raise UserError(e)
+
+ try:
+ if self.env.cr.description:
+ headers = [d[0] for d in self.env.cr.description]
+ bodies = self.env.cr.fetchall()
+ except Exception as e:
+ raise UserError(e)
+
+ action_print_pdf = self.env.ref('query_deluxe.action_print_pdf')
+ if self.orientation == 'landscape':
+ action_print_pdf.paperformat_id.orientation = "Landscape"
+ elif self.orientation == 'portrait':
+ action_print_pdf.paperformat_id.orientation = "Portrait"
+
+ append_data = {
+ 'query_name': self.query_name,
+ 'headers': headers,
+ 'bodies': bodies
+ }
+ return action_print_pdf.report_action(self, data=append_data)
diff --git a/odex25_base/query_deluxe/wizard/pdforientation.xml b/odex25_base/query_deluxe/wizard/pdforientation.xml
new file mode 100644
index 000000000..c653a9155
--- /dev/null
+++ b/odex25_base/query_deluxe/wizard/pdforientation.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ pdforientation.form
+ pdforientation
+
+
+
+
+