# HG changeset patch
# User Houzefa Abbasbhay <houzefa.abba@xcg-consulting.fr>
# Date 1675437682 -3600
#      Fri Feb 03 16:21:22 2023 +0100
# Branch 16.0
# Node ID 2b129f0d19dd16a327dd7571964e2240cd5e2067
# Parent  5ce86dbc91eac865fab89b0df6dcafb7a688ef39
Migrate to Odoo 16.0

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,3 +1,3 @@
 include:
   - project: xcg/ci-templates
-    file: /odoo/15.0/gitlab-ci.yaml
+    file: /odoo/16.0/gitlab-ci.yaml
diff --git a/.hgconf b/.hgconf
--- a/.hgconf
+++ b/.hgconf
@@ -1,5 +1,5 @@
 [converter]
 pulluri = https://orus.io/xcg/odoo-modules/converter
 layout = ../converter
-track = 15.0
+track = 16.0
 expand =
diff --git a/NEWS.rst b/NEWS.rst
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -2,6 +2,11 @@
 Changelog
 =========
 
+16.0.1.0.0
+----------
+
+* Migrate to Odoo 16.0.
+
 15.0.1.0.0
 ----------
 
diff --git a/README.rst b/README.rst
--- a/README.rst
+++ b/README.rst
@@ -3,10 +3,10 @@
 ======
 
 .. |coverage| image:: .badges/coverage.svg
-    :target: https://orus.io/xcg/odoo-modules/redner/-/pipelines?ref=branch/15.0
+    :target: https://orus.io/xcg/odoo-modules/redner/-/pipelines?ref=branch/16.0
     :alt: Coverage report
 .. |pylint| image:: .badges/pylint.svg
-    :target: https://orus.io/xcg/odoo-modules/redner/-/pipelines?ref=branch/15.0
+    :target: https://orus.io/xcg/odoo-modules/redner/-/pipelines?ref=branch/16.0
     :alt: pylint score
 .. |maturity| image:: .badges/maturity.svg
     :target: https://odoo-community.org/page/development-status
diff --git a/__manifest__.py b/__manifest__.py
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -21,7 +21,7 @@
 {
     "name": "Redner",
     "license": "AGPL-3",
-    "version": "15.0.1.0.0",
+    "version": "16.0.1.0.0",
     "category": "Reporting",
     "author": "XCG Consulting",
     "website": "https://orbeet.io/",
diff --git a/controllers/main.py b/controllers/main.py
--- a/controllers/main.py
+++ b/controllers/main.py
@@ -24,17 +24,15 @@
 from werkzeug import exceptions
 from werkzeug.urls import url_decode
 
-from odoo.http import request, route
+from odoo.http import content_disposition, request, route, serialize_exception
 from odoo.tools import html_escape
 
-from odoo.addons.web.controllers import main
-from odoo.addons.web.controllers.main import (
-    _serialize_exception,
-    content_disposition,
+from odoo.addons.web.controllers.report import (
+    ReportController as BaseReportController,
 )
 
 
-class ReportController(main.ReportController):
+class ReportController(BaseReportController):
     """Add redner report downloads within report controllers.
     Much of this code comes from OCA modules, the latest one being report_xlsx.
     """
@@ -72,7 +70,7 @@
                 description="Redner action report not found for report_name "
                 "%s" % reportname
             )
-        res, filetype = action_redner_report._render(docids, data)
+        res, filetype = action_redner_report._render(reportname, docids, data)
         filename = action_redner_report.gen_report_download_filename(
             docids, data
         )
@@ -87,7 +85,7 @@
         return request.make_response(res, headers=http_headers)
 
     @route()
-    def report_download(self, data, context=None):
+    def report_download(self, data, context=None, token=None):
         """This function is used by 'action_manager_report.js' in order to
         trigger the download of a pdf/controller report.
 
@@ -98,7 +96,7 @@
         requestcontent = json.loads(data)
         url, report_type = requestcontent[0], requestcontent[1]
         if "redner" not in report_type:
-            return super().report_download(data, context=context)
+            return super().report_download(data, context=context, token=token)
         try:
             reportname = url.split("/report/redner/")[1].split("?")[0]
             docids = None
@@ -127,6 +125,6 @@
                 )
             return response
         except Exception as e:
-            se = _serialize_exception(e)
+            se = serialize_exception(e)
             error = {"code": 200, "message": "Odoo Server Error", "data": se}
             return request.make_response(html_escape(json.dumps(error)))
diff --git a/models/ir_actions_report.py b/models/ir_actions_report.py
--- a/models/ir_actions_report.py
+++ b/models/ir_actions_report.py
@@ -174,7 +174,7 @@
             ]
         )
 
-    def _render_redner(self, res_ids, data=None):
+    def _render_redner(self, report_ref, res_ids, data=None):
         """Called by ``_render``, method name dynamically built."""
         self.ensure_one()
         if self.report_type != "redner":
diff --git a/models/redner_template.py b/models/redner_template.py
--- a/models/redner_template.py
+++ b/models/redner_template.py
@@ -112,32 +112,33 @@
 
         return _redner
 
-    @api.model
-    def create(self, vals):
+    @api.model_create_multi
+    def create(self, vals_list):
         """Overwrite create to create redner template"""
 
-        # Prepare template params according to the selected language.
-        # Use template data field if the selected language is "od";
-        # otherwise the body field is used.
-        produces, language = vals.get("language").split("|")
-        body, body_format = (
-            (vals.get("template_data", ""), "base64")
-            if language == "od+mustache"
-            else (vals.get("body"), "text")
-        )
+        for vals in vals_list:
+            # Prepare template params according to the selected language.
+            # Use template data field if the selected language is "od";
+            # otherwise the body field is used.
+            produces, language = vals.get("language").split("|")
+            body, body_format = (
+                (vals.get("template_data", ""), "base64")
+                if language == "od+mustache"
+                else (vals.get("body"), "text")
+            )
 
-        # We depend on the API for consistency here
-        # So raised error should not result with a created template
-        vals["redner_id"] = self.redner.templates.account_template_add(
-            language=language,
-            body=body,
-            name=vals.get("name"),
-            produces=produces,
-            body_format=body_format,
-            version=fields.Datetime.to_string(fields.Datetime.now()),
-        )
+            # We depend on the API for consistency here
+            # So raised error should not result with a created template
+            vals["redner_id"] = self.redner.templates.account_template_add(
+                language=language,
+                body=body,
+                name=vals.get("name"),
+                produces=produces,
+                body_format=body_format,
+                version=fields.Datetime.to_string(fields.Datetime.now()),
+            )
 
-        return super().create(vals)
+        return super().create(vals_list)
 
     def write(self, vals):
         """Overwrite write to update redner template"""
diff --git a/static/src/js/redner_report_action.esm.js b/static/src/js/redner_report_action.esm.js
--- a/static/src/js/redner_report_action.esm.js
+++ b/static/src/js/redner_report_action.esm.js
@@ -19,7 +19,7 @@
 
 /* Add a report handler to download redner reports.
  * Adapted from OCA's report_xlsx module:
- * https://github.com/OCA/reporting-engine/blob/15.0/report_xlsx/static/src/js/report/action_manager_report.esm.js
+ * https://github.com/OCA/reporting-engine/blob/16.0/report_xlsx/static/src/js/report/action_manager_report.esm.js
  */
 
 import {download} from "@web/core/network/download";
diff --git a/tests/common.py b/tests/common.py
--- a/tests/common.py
+++ b/tests/common.py
@@ -18,7 +18,7 @@
 #
 ##############################################################################
 
-import mock
+from unittest import mock
 
 from odoo.tests import TransactionCase
 
diff --git a/tests/test_ir_actions_report.py b/tests/test_ir_actions_report.py
--- a/tests/test_ir_actions_report.py
+++ b/tests/test_ir_actions_report.py
@@ -19,8 +19,7 @@
 ##############################################################################
 
 import base64
-
-import mock
+from unittest import mock
 
 from .common import TestCommon
 
@@ -72,7 +71,7 @@
             json=lambda: [{"body": base64.b64encode(b"test-rendered-report")}],
         )
         demo_user = self.env.ref("base.user_demo")
-        render_ret = self.report._render([demo_user.id])
+        render_ret = self.report._render(self.report, [demo_user.id])
         requests_post_mock.assert_called_once_with(
             "https://test-redner-url/api/v1/render",
             json={
diff --git a/tests/test_mail_template.py b/tests/test_mail_template.py
--- a/tests/test_mail_template.py
+++ b/tests/test_mail_template.py
@@ -19,8 +19,7 @@
 ##############################################################################
 
 import base64
-
-import mock
+from unittest import mock
 
 from .common import TestCommon
 
diff --git a/tests/test_redner_template.py b/tests/test_redner_template.py
--- a/tests/test_redner_template.py
+++ b/tests/test_redner_template.py
@@ -18,7 +18,7 @@
 #
 ##############################################################################
 
-import mock
+from unittest import mock
 
 from odoo import fields
 
diff --git a/views/ir_actions_report.xml b/views/ir_actions_report.xml
--- a/views/ir_actions_report.xml
+++ b/views/ir_actions_report.xml
@@ -42,7 +42,7 @@
                         colspan="2"
                     />
                     <group string="Substitutions">
-                        <field name="substitution_ids" nolabel="1">
+                        <field name="substitution_ids" nolabel="1" colspan="2">
                             <tree editable="top" default_order="keyword asc">
                                 <field name="keyword" />
                                 <field name="converter" />
diff --git a/views/mail_template.xml b/views/mail_template.xml
--- a/views/mail_template.xml
+++ b/views/mail_template.xml
@@ -48,7 +48,7 @@
                     string="Substitutions"
                     attrs="{'invisible': [('is_redner_template', '=', False)]}"
                 >
-                    <field name="redner_substitution_ids" nolabel="1">
+                    <field name="redner_substitution_ids" nolabel="1" colspan="2">
                         <tree editable="top" default_order="keyword asc">
                             <field name="keyword" />
                             <field name="converter" />