diff --git a/report_py3o/__manifest__.py b/report_py3o/__manifest__.py
index 96e04f9c4..186395036 100644
--- a/report_py3o/__manifest__.py
+++ b/report_py3o/__manifest__.py
@@ -4,10 +4,10 @@
"name": "Py3o Report Engine",
"summary": "Reporting engine based on Libreoffice (ODT -> ODT, "
"ODT -> PDF, ODT -> DOC, ODT -> DOCX, ODS -> ODS, etc.)",
- "version": "15.0.1.0.0",
+ "version": "16.0.1.0.0",
"category": "Reporting",
"license": "AGPL-3",
- "author": "XCG Consulting," "ACSONE SA/NV," "Odoo Community Association (OCA)",
+ "author": "XCG Consulting, ACSONE SA/NV, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine",
"depends": ["web"],
"external_dependencies": {
@@ -21,7 +21,6 @@
},
"data": [
"security/ir.model.access.csv",
- "views/menu.xml",
"views/py3o_template.xml",
"views/ir_actions_report.xml",
"demo/report_py3o.xml",
diff --git a/report_py3o/controllers/main.py b/report_py3o/controllers/main.py
index 8f28cdd43..05be92036 100644
--- a/report_py3o/controllers/main.py
+++ b/report_py3o/controllers/main.py
@@ -6,18 +6,17 @@ import mimetypes
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
-class ReportController(main.ReportController):
+class ReportController(ReportController):
@route()
def report_routes(self, reportname, docids=None, converter=None, **data):
if converter != "py3o":
- return super(ReportController, self).report_routes(
+ return super().report_routes(
reportname=reportname, docids=docids, converter=converter, **data
)
context = dict(request.env.context)
@@ -44,7 +43,7 @@ class ReportController(main.ReportController):
description="Py3o action report not found for report_name "
"%s" % reportname
)
- res, filetype = action_py3o_report._render(docids, data)
+ res, filetype = ir_action._render(reportname, docids, data)
filename = action_py3o_report.gen_report_download_filename(docids, data)
if not filename.endswith(filetype):
filename = "{}.{}".format(filename, filetype)
@@ -57,7 +56,7 @@ class ReportController(main.ReportController):
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 'qwebactionmanager.js' in order to trigger
the download of a py3o/controller report.
@@ -68,7 +67,7 @@ class ReportController(main.ReportController):
requestcontent = json.loads(data)
url, report_type = requestcontent[0], requestcontent[1]
if "py3o" not in report_type:
- return super(ReportController, self).report_download(data, context)
+ return super().report_download(data, context=context, token=token)
try:
reportname = url.split("/report/py3o/")[1].split("?")[0]
docids = None
@@ -90,6 +89,6 @@ class ReportController(main.ReportController):
response.set_cookie("fileToken", context)
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/report_py3o/demo/report_py3o.xml b/report_py3o/demo/report_py3o.xml
index bc3d06ec6..cfc515b6a 100644
--- a/report_py3o/demo/report_py3o.xml
+++ b/report_py3o/demo/report_py3o.xml
@@ -11,6 +11,9 @@
odt
report_py3o
demo/res_user.odt
+ object.name.replace(' ', '_') + '-demo.odt'
report
diff --git a/report_py3o/models/ir_actions_report.py b/report_py3o/models/ir_actions_report.py
index 65955521e..408578877 100644
--- a/report_py3o/models/ir_actions_report.py
+++ b/report_py3o/models/ir_actions_report.py
@@ -157,16 +157,17 @@ class IrActionsReport(models.Model):
[("report_name", "=", report_name), ("report_type", "=", report_type)]
)
- def _render_py3o(self, res_ids, data):
- self.ensure_one()
- if self.report_type != "py3o":
+ @api.model
+ def _render_py3o(self, report_ref, res_ids, data=None):
+ report = self._get_report(report_ref)
+ if report.report_type != "py3o":
raise RuntimeError(
"py3o rendition is only available on py3o report.\n"
- "(current: '{}', expected 'py3o'".format(self.report_type)
+ "(current: '{}', expected 'py3o'".format(report.report_type)
)
return (
self.env["py3o.report"]
- .create({"ir_actions_report_id": self.id})
+ .create({"ir_actions_report_id": report.id})
.create_report(res_ids, data)
)
diff --git a/report_py3o/models/py3o_report.py b/report_py3o/models/py3o_report.py
index e018076ec..3aa2d3480 100644
--- a/report_py3o/models/py3o_report.py
+++ b/report_py3o/models/py3o_report.py
@@ -16,6 +16,8 @@ from zipfile import ZIP_DEFLATED, ZipFile
import pkg_resources
from odoo import _, api, fields, models, tools
+from odoo.exceptions import AccessError
+from odoo.tools.safe_eval import safe_eval, time
from ._py3o_parser_context import Py3oParserContext
@@ -187,7 +189,9 @@ class Py3oReport(models.TransientModel):
def _get_parser_context(self, model_instance, data):
report_xml = self.ir_actions_report_id
context = Py3oParserContext(self.env).localcontext
- context.update(report_xml._get_rendering_context(model_instance.ids, data))
+ context.update(
+ report_xml._get_rendering_context(report_xml, model_instance.ids, data)
+ )
context["objects"] = model_instance
self._extend_parser_context(context, report_xml)
return context
@@ -199,9 +203,30 @@ class Py3oReport(models.TransientModel):
# consumption...
# ... but odoo wants the whole data in memory anyways :)
buffer = BytesIO(f.read())
- self.ir_actions_report_id._postprocess_pdf_report(
- model_instance, buffer
+ attachment_name = safe_eval(
+ self.ir_actions_report_id.attachment,
+ {"object": model_instance, "time": time},
)
+ if attachment_name:
+ attachment_vals = {
+ "name": attachment_name,
+ "res_model": self.ir_actions_report_id.model,
+ "res_id": model_instance.id,
+ "raw": buffer.getvalue(),
+ }
+ try:
+ attach = self.env["ir.attachment"].create(attachment_vals)
+ except AccessError:
+ logger.info(
+ "Cannot save PDF report %s as attachment",
+ attachment_vals["name"],
+ )
+ else:
+ logger.info(
+ "PDF document %s saved as attachment ID %d",
+ attachment_vals["name"],
+ attach.id,
+ )
return result_path
def _create_single_report(self, model_instance, data):
diff --git a/report_py3o/tests/test_report_py3o.py b/report_py3o/tests/test_report_py3o.py
index 71efe1a3f..6ef02b541 100644
--- a/report_py3o/tests/test_report_py3o.py
+++ b/report_py3o/tests/test_report_py3o.py
@@ -74,13 +74,13 @@ class TestReportPy3o(TransactionCase):
or result
)
# test the call the the create method inside our custom parser
- self.report._render(self.env.user.ids)
+ self.report._render(self.report.id, self.env.user.ids)
self.assertEqual(call_count, patched_pdf.call_count)
# generated files no more exists
self.assertFalse(os.path.exists(result))
def test_reports(self):
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertTrue(res)
def test_reports_merge_zip(self):
@@ -93,7 +93,7 @@ class TestReportPy3o(TransactionCase):
py3o_report.__class__, "_zip_results"
) as patched_zip_results:
patched_zip_results.side_effect = _zip_results
- content, filetype = self.report._render(users.ids)
+ content, filetype = self.report._render(self.report.id, users.ids)
self.assertEqual(1, patched_zip_results.call_count)
self.assertEqual(filetype, "zip")
@@ -122,7 +122,7 @@ class TestReportPy3o(TransactionCase):
# time we ask the report we received the saved attachment not a newly
# generated document
created_attachement.datas = base64.b64encode(b"new content")
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertEqual((b"new content", self.report.py3o_filetype), res)
def test_report_post_process(self):
@@ -150,24 +150,24 @@ class TestReportPy3o(TransactionCase):
"odoo.addons.%s" % self.report.module, tmpl_name
)
self.assertTrue(os.path.exists(flbk_filename))
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertTrue(res)
# The generation fails if the template is not found
self.report.module = False
with self.assertRaises(TemplateNotFound), self.env.cr.savepoint():
- self.report._render(self.env.user.ids)
+ self.report._render(self.report.id, self.env.user.ids)
# the template can also be provided as an abspath if it's root path
# is trusted
self.report.py3o_template_fallback = flbk_filename
with self.assertRaises(TemplateNotFound):
- self.report._render(self.env.user.ids)
+ self.report._render(self.report.id, self.env.user.ids)
with temporary_copy(flbk_filename) as tmp_filename:
self.report.py3o_template_fallback = tmp_filename
tools.config.misc["report_py3o"] = {
"root_tmpl_path": os.path.realpath(os.path.dirname(tmp_filename))
}
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertTrue(res)
# the tempalte can also be provided as a binary field
@@ -184,7 +184,7 @@ class TestReportPy3o(TransactionCase):
)
self.report.py3o_template_id = py3o_template
self.report.py3o_template_fallback = flbk_filename
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertTrue(res)
@tools.misc.mute_logger("odoo.addons.report_py3o.models.py3o_report")
@@ -240,7 +240,7 @@ class TestReportPy3o(TransactionCase):
self.assertFalse(self.report.lo_bin_path)
self.assertFalse(self.report.is_py3o_report_not_available)
self.assertFalse(self.report.msg_py3o_report_not_available)
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertTrue(res)
# The report should become unavailable for an non native output format
@@ -249,7 +249,7 @@ class TestReportPy3o(TransactionCase):
self.assertTrue(self.report.is_py3o_report_not_available)
self.assertTrue(self.report.msg_py3o_report_not_available)
with self.assertRaises(RuntimeError):
- self.report._render(self.env.user.ids)
+ self.report._render(self.report.id, self.env.user.ids)
# if we reset the wrong path, everything should work
self.env["ir.config_parameter"].set_param(
@@ -260,5 +260,5 @@ class TestReportPy3o(TransactionCase):
self.assertFalse(self.report.is_py3o_native_format)
self.assertFalse(self.report.is_py3o_report_not_available)
self.assertFalse(self.report.msg_py3o_report_not_available)
- res = self.report._render(self.env.user.ids)
+ res = self.report._render(self.report.id, self.env.user.ids)
self.assertTrue(res)
diff --git a/report_py3o/views/menu.xml b/report_py3o/views/menu.xml
deleted file mode 100644
index 87385ecab..000000000
--- a/report_py3o/views/menu.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/report_py3o/views/py3o_template.xml b/report_py3o/views/py3o_template.xml
index c13f1104a..e057e77e7 100644
--- a/report_py3o/views/py3o_template.xml
+++ b/report_py3o/views/py3o_template.xml
@@ -4,7 +4,7 @@
py3o.template.configuration.search.view
py3o.template
-
+
@@ -21,7 +21,7 @@
py3o.template.configuration.form.view
py3o.template
-