From 26cf0f9912ac6d3f8733424048b96ea886151dd0 Mon Sep 17 00:00:00 2001
From: Sylvain LE GAL <sylvain.legal@grap.coop>
Date: Fri, 12 Jan 2024 00:55:03 +0100
Subject: [PATCH 1/3] [IMP] bi_sql_editor: allow to generate form view. So It
 is possible to see data detail, when clicking on an item in a tree view

---
 bi_sql_editor/__manifest__.py                 |  2 +-
 .../migrations/16.0.2.0.0/post-migration.py   | 11 +++++++
 bi_sql_editor/models/bi_sql_view.py           | 30 +++++++++++++++++--
 bi_sql_editor/models/bi_sql_view_field.py     |  4 +++
 bi_sql_editor/static/description/index.html   |  1 +
 bi_sql_editor/views/view_bi_sql_view.xml      |  1 +
 6 files changed, 45 insertions(+), 4 deletions(-)
 create mode 100644 bi_sql_editor/migrations/16.0.2.0.0/post-migration.py

diff --git a/bi_sql_editor/__manifest__.py b/bi_sql_editor/__manifest__.py
index fab44975a3..32156216aa 100644
--- a/bi_sql_editor/__manifest__.py
+++ b/bi_sql_editor/__manifest__.py
@@ -5,7 +5,7 @@
 {
     "name": "BI SQL Editor",
     "summary": "BI Views builder, based on Materialized or Normal SQL Views",
-    "version": "16.0.1.2.0",
+    "version": "16.0.2.0.0",
     "license": "AGPL-3",
     "category": "Reporting",
     "author": "GRAP,Odoo Community Association (OCA)",
diff --git a/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py b/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py
new file mode 100644
index 0000000000..f30ae40708
--- /dev/null
+++ b/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py
@@ -0,0 +1,11 @@
+# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
+# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from openupgradelib import openupgrade
+
+
+@openupgrade.migrate()
+def migrate(env, version):
+    for view in env["bi.sql.view"].search([("state", "=", "ui_valid")]):
+        view.form_view_id = env["ir.ui.view"].create(view._prepare_form_view()).id
diff --git a/bi_sql_editor/models/bi_sql_view.py b/bi_sql_editor/models/bi_sql_view.py
index 97ccaf30e5..5a6e169096 100644
--- a/bi_sql_editor/models/bi_sql_view.py
+++ b/bi_sql_editor/models/bi_sql_view.py
@@ -78,7 +78,8 @@ class BiSQLView(models.Model):
         readonly=False,
         states={"ui_valid": [("readonly", True)]},
         default="pivot,graph,tree",
-        help="Comma-separated text. Possible values:" ' "graph", "pivot" or "tree"',
+        help="Comma-separated text. Possible values:"
+        ' "graph", "pivot", "tree" or "form"',
     )
 
     query = fields.Text(
@@ -126,6 +127,7 @@ class BiSQLView(models.Model):
     model_id = fields.Many2one(
         string="Odoo Model", comodel_name="ir.model", readonly=True
     )
+
     # UI related fields
     # 1. Editable fields, which can be set by the user (optional) before
     # creating the UI elements
@@ -151,6 +153,11 @@ def _default_parent_menu_id(self):
     )
 
     # 2. Readonly fields, non editable by the user
+
+    form_view_id = fields.Many2one(
+        string="Odoo Form View", comodel_name="ir.ui.view", readonly=True
+    )
+
     tree_view_id = fields.Many2one(
         string="Odoo Tree View", comodel_name="ir.ui.view", readonly=True
     )
@@ -207,9 +214,9 @@ def _check_view_order(self):
         for rec in self:
             if rec.view_order:
                 for vtype in rec.view_order.split(","):
-                    if vtype not in ("graph", "pivot", "tree"):
+                    if vtype not in ("graph", "pivot", "tree", "form"):
                         raise UserError(
-                            _("Only graph, pivot or tree views are supported")
+                            _("Only graph, pivot, tree or form views are supported")
                         )
 
     # Compute Section
@@ -324,6 +331,7 @@ def button_create_sql_view_and_model(self):
 
     def button_reset_to_model_valid(self):
         views = self.filtered(lambda x: x.state == "ui_valid")
+        views.mapped("form_view_id").unlink()
         views.mapped("tree_view_id").unlink()
         views.mapped("graph_view_id").unlink()
         views.mapped("pivot_view_id").unlink()
@@ -351,6 +359,7 @@ def button_set_draft(self):
         return super().button_set_draft()
 
     def button_create_ui(self):
+        self.form_view_id = self.env["ir.ui.view"].create(self._prepare_form_view()).id
         self.tree_view_id = self.env["ir.ui.view"].create(self._prepare_tree_view()).id
         self.graph_view_id = (
             self.env["ir.ui.view"].create(self._prepare_graph_view()).id
@@ -442,6 +451,19 @@ def _prepare_rule(self):
             "global": True,
         }
 
+    def _prepare_form_view(self):
+        self.ensure_one()
+        return {
+            "name": self.name,
+            "type": "form",
+            "model": self.model_id.model,
+            "arch": """<?xml version="1.0"?>"""
+            """<form><sheet><group string="Data" col="4">{}"""
+            """</group></sheet></form>""".format(
+                "".join([x._prepare_form_field() for x in self.bi_sql_view_field_ids])
+            ),
+        }
+
     def _prepare_tree_view(self):
         self.ensure_one()
         return {
@@ -507,6 +529,8 @@ def _prepare_action(self):
         self.ensure_one()
         view_mode = self.view_order
         first_view = view_mode.split(",")[0]
+        if first_view == "form":
+            view_id = self.form_view_id.id
         if first_view == "tree":
             view_id = self.tree_view_id.id
         elif first_view == "pivot":
diff --git a/bi_sql_editor/models/bi_sql_view_field.py b/bi_sql_editor/models/bi_sql_view_field.py
index 2750255f11..72deb8fb19 100644
--- a/bi_sql_editor/models/bi_sql_view_field.py
+++ b/bi_sql_editor/models/bi_sql_view_field.py
@@ -249,6 +249,10 @@ def _prepare_model_field(self):
             or False,
         }
 
+    def _prepare_form_field(self):
+        self.ensure_one()
+        return f"""<field name="{self.name}" context="{self.field_context}"/>\n"""
+
     def _prepare_tree_field(self):
         self.ensure_one()
         if self.tree_visibility == "unavailable":
diff --git a/bi_sql_editor/static/description/index.html b/bi_sql_editor/static/description/index.html
index f73a64eb5b..3e0b5ea8a9 100644
--- a/bi_sql_editor/static/description/index.html
+++ b/bi_sql_editor/static/description/index.html
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
diff --git a/bi_sql_editor/views/view_bi_sql_view.xml b/bi_sql_editor/views/view_bi_sql_view.xml
index 2eea963648..3067e8c2d2 100644
--- a/bi_sql_editor/views/view_bi_sql_view.xml
+++ b/bi_sql_editor/views/view_bi_sql_view.xml
@@ -200,6 +200,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
                                         <field name="parent_menu_id" />
                                     </group>
                                     <group string="UI Instances">
+                                        <field name="form_view_id" />
                                         <field name="tree_view_id" />
                                         <field name="graph_view_id" />
                                         <field name="pivot_view_id" />

From c5615e3b142a0f60404a57b59cfbb30d87bb16f9 Mon Sep 17 00:00:00 2001
From: Sylvain LE GAL <sylvain.legal@grap.coop>
Date: Fri, 12 Jan 2024 01:12:26 +0100
Subject: [PATCH 2/3] [IMP] bi_sql_editor : Allow to use sum / avg operator on
 tree view

---
 bi_sql_editor/migrations/16.0.2.0.0/post-migration.py | 3 +++
 bi_sql_editor/models/bi_sql_view_field.py             | 8 +++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py b/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py
index f30ae40708..2503c9c596 100644
--- a/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py
+++ b/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py
@@ -8,4 +8,7 @@
 @openupgrade.migrate()
 def migrate(env, version):
     for view in env["bi.sql.view"].search([("state", "=", "ui_valid")]):
+        # create new Form view
         view.form_view_id = env["ir.ui.view"].create(view._prepare_form_view()).id
+        # Update tree view, to add sum / avg option
+        view.tree_view_id.write(view._prepare_tree_view())
diff --git a/bi_sql_editor/models/bi_sql_view_field.py b/bi_sql_editor/models/bi_sql_view_field.py
index 72deb8fb19..72a53ca5e2 100644
--- a/bi_sql_editor/models/bi_sql_view_field.py
+++ b/bi_sql_editor/models/bi_sql_view_field.py
@@ -265,8 +265,14 @@ def _prepare_tree_field(self):
         elif self.tree_visibility == "optional_show":
             visibility_text = 'optional="show"'
 
+        operator_text = ""
+        if self.group_operator == "sum":
+            operator_text = f'sum="{_("Total")}"'
+        elif self.group_operator == "avg":
+            operator_text = f'avg="{_("Average")}"'
+
         return (
-            f"""<field name="{self.name}" {visibility_text}"""
+            f"""<field name="{self.name}" {visibility_text} {operator_text}"""
             f""" context="{self.field_context}"/>\n"""
         )
 

From 53593c9884ea9f56bf416f796c5288fbf8363d68 Mon Sep 17 00:00:00 2001
From: Sylvain LE GAL <sylvain.legal@grap.coop>
Date: Thu, 8 Feb 2024 11:11:22 +0100
Subject: [PATCH 3/3] [FIX] bi_sql_editor : update / create tree and form view
 once all the models are loaded, to avoid errors because fields are not
 available

---
 .../migrations/16.0.2.0.0/{post-migration.py => end-migration.py} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename bi_sql_editor/migrations/16.0.2.0.0/{post-migration.py => end-migration.py} (100%)

diff --git a/bi_sql_editor/migrations/16.0.2.0.0/post-migration.py b/bi_sql_editor/migrations/16.0.2.0.0/end-migration.py
similarity index 100%
rename from bi_sql_editor/migrations/16.0.2.0.0/post-migration.py
rename to bi_sql_editor/migrations/16.0.2.0.0/end-migration.py
