diff --git a/report_xml/README.rst b/report_xml/README.rst
index f73c82046..a290fd663 100644
--- a/report_xml/README.rst
+++ b/report_xml/README.rst
@@ -14,16 +14,16 @@ XML Reports
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github
- :target: https://github.com/OCA/reporting-engine/tree/12.0/report_xml
+ :target: https://github.com/OCA/reporting-engine/tree/13.0/report_xml
:alt: OCA/reporting-engine
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/reporting-engine-12-0/reporting-engine-12-0-report_xml
+ :target: https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_xml
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
- :target: https://runbot.odoo-community.org/runbot/143/12.0
+ :target: https://runbot.odoo-community.org/runbot/143/13.0
:alt: Try me on Runbot
-|badge1| |badge2| |badge3| |badge4| |badge5|
+|badge1| |badge2| |badge3| |badge4| |badge5|
This module was written to extend the functionality of the reporting engine to
support XML reports and allow modules to generate them by code or by QWeb
@@ -56,25 +56,30 @@ This module is intended as a base engine for other modules to use it, so no dire
If you are a developer
~~~~~~~~~~~~~~~~~~~~~~
-To learn from an example, just check the `sample module`_.
+To learn from an example, just check the `demo report`_ on GitHub for
+the model ``res.company`` or check it in interface from companies views.
To develop with this module, you need to:
* Create a module.
* Make it depend on this one.
* Follow `instructions to create reports`_ having in mind that the
- ``report_type`` field in your ``ir.actions.report.xml`` record must be
+ ``report_type`` field in your ``ir.actions.report`` record must be
``qweb-xml``.
In case you want to create a `custom report`_, the instructions remain the same
as for HTML reports, and the method that you must override is also called
``_get_report_values``, even when this time you are creating a XML report.
-You can make your custom report inherit ``report_xml.xsd_checked_report``, name
-it like your XML ```` id prepended by ``report.``, add a ``xsd()``
-method that returns a XSD in a string, and have XSD automatic checking for
+You can make your custom report inherit ``report.report_xml.abstract``, name
+it in such way ``report.``. Also you can add a XSD file for
+report validation into ``xsd_schema`` field of your report (check
+`report definition`_) and have XSD automatic checking for
free.
+You can customize rendering process and validation way via changing logic of
+``generate_report`` and ``validate_report`` methods in your report class.
+
You can visit ``http:///report/xml//``
to see your XML report online as a web page.
@@ -83,9 +88,10 @@ For further information, please visit:
* https://www.odoo.com/forum/help-1
* https://github.com/OCA/reporting-engine
-.. _custom report: https://www.odoo.com/documentation/12.0/reference/reports.html#custom-reports
-.. _instructions to create reports: https://www.odoo.com/documentation/12.0/reference/reports.html
-.. _sample module: https://github.com/OCA/reporting-engine/tree/12.0/report_xml_sample
+.. _custom report: https://www.odoo.com/documentation/13.0/reference/reports.html#custom-reports
+.. _instructions to create reports: https://www.odoo.com/documentation/13.0/reference/reports.html
+.. _demo report: https://github.com/OCA/reporting-engine/blob/13.0/report_xml/demo/demo_report.xml
+.. _report definition: https://github.com/OCA/reporting-engine/blob/13.0/report_xml/demo/report.xml
Bug Tracker
===========
@@ -93,7 +99,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -104,14 +110,16 @@ Authors
~~~~~~~
* Tecnativa
+* Avoin.Systems
Contributors
~~~~~~~~~~~~
* Enric Tobella
* `Tecnativa `_:
-
- Jairo Llopis
+ * Jairo Llopis
+* `Avoin.Systems `_:
+ * Tatiana Deribina
Other credits
~~~~~~~~~~~~~
@@ -131,6 +139,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
-This module is part of the `OCA/reporting-engine `_ project on GitHub.
+This module is part of the `OCA/reporting-engine `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/report_xml/__init__.py b/report_xml/__init__.py
index 9c6a80011..64ad93366 100644
--- a/report_xml/__init__.py
+++ b/report_xml/__init__.py
@@ -2,3 +2,5 @@
from . import controllers
from . import models
+from . import reports
+from .hooks import post_init_hook
diff --git a/report_xml/__manifest__.py b/report_xml/__manifest__.py
index 5e89d51be..ba8344aa4 100644
--- a/report_xml/__manifest__.py
+++ b/report_xml/__manifest__.py
@@ -2,15 +2,27 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
{
"name": "XML Reports",
- "version": "12.0.1.0.0",
+ "version": "13.0.1.0.0",
"category": "Reporting",
"website": "https://github.com/OCA/reporting-engine",
- "author": "Tecnativa, " "Odoo Community Association (OCA)",
+ "author": "Tecnativa, Odoo Community Association (OCA), Avoin.Systems",
"license": "AGPL-3",
"installable": True,
"application": False,
"summary": "Allow to generate XML reports",
"depends": ["web"],
- "data": ["views/webclient_templates.xml", "views/ir_actions_views.xml"],
- "demo": ["demo/report.xml"],
+ "data": [
+ "views/webclient_templates.xml", # add js handlers for action manager
+ "views/ir_actions_report_view.xml",
+ ],
+ "demo": [
+ "demo/report.xml", # register report in the system
+ "demo/demo_report.xml", # report body definition
+ ],
+ "external_dependencies": {
+ "python": [ # Python third party libraries required for module
+ "lxml" # XML and HTML with Python
+ ]
+ },
+ "post_init_hook": "post_init_hook",
}
diff --git a/report_xml/controllers/main.py b/report_xml/controllers/main.py
index 953c55b6e..f7c646662 100644
--- a/report_xml/controllers/main.py
+++ b/report_xml/controllers/main.py
@@ -39,9 +39,7 @@ class ReportController(report.ReportController):
]
return request.make_response(xml, headers=xmlhttpheaders)
else:
- return super(ReportController, self).report_routes(
- reportname, docids, converter, **data
- )
+ return super().report_routes(reportname, docids, converter, **data)
@route()
def report_download(self, data, token):
@@ -73,13 +71,13 @@ class ReportController(report.ReportController):
filename = "%s.xml" % (report.name)
if docids:
- ids = [int(x) for x in docids.split(",")]
+ ids = [int(doc_id) for doc_id in docids.split(",")]
records = request.env[report.model].browse(ids)
if report.print_report_name and not len(records) > 1:
report_name = safe_eval(
report.print_report_name, {"object": records, "time": time}
)
- filename = "%s.xml" % (report_name)
+ filename = "{}.xml".format(report_name)
response.headers.add(
"Content-Disposition", content_disposition(filename)
)
@@ -90,4 +88,4 @@ class ReportController(report.ReportController):
error = {"code": 200, "message": "Odoo Server Error", "data": se}
return request.make_response(html_escape(json.dumps(error)))
else:
- return super(ReportController, self).report_download(data, token)
+ return super().report_download(data, token)
diff --git a/report_xml/demo/demo_report.xml b/report_xml/demo/demo_report.xml
new file mode 100644
index 000000000..521ff610c
--- /dev/null
+++ b/report_xml/demo/demo_report.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/report_xml/demo/demo_report.xsd b/report_xml/demo/demo_report.xsd
new file mode 100644
index 000000000..e19b01d39
--- /dev/null
+++ b/report_xml/demo/demo_report.xsd
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/report_xml/demo/report.xml b/report_xml/demo/report.xml
index 4504ec82b..67acbf1c3 100644
--- a/report_xml/demo/report.xml
+++ b/report_xml/demo/report.xml
@@ -1,19 +1,19 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/report_xml/hooks.py b/report_xml/hooks.py
new file mode 100644
index 000000000..67a17a64c
--- /dev/null
+++ b/report_xml/hooks.py
@@ -0,0 +1,47 @@
+# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
+
+import os
+
+from odoo import SUPERUSER_ID, api
+
+
+def post_init_hook(cr, registry):
+ """
+ Loaded after installing this module, and before the next module starts
+ installing.
+
+ Add XSD Validation Schema for a demo report if it's in the system.
+ Demo data records are always created with `noupdate == True` and render of
+ tag `report` doesn't support new `ir.actions.report` field `xsd_schema`.
+ Thus it is impossible to define `xsd_schema` in the demo definition or add
+ schema after that via xml update record. Therefore it possible to add value
+ to `xsd_schema` field for demo record only via hook.
+
+ Args:
+ * cr(odoo.sql_db.Cursor) - database cursor.
+ * registry(odoo.modules.registry.RegistryManager) - a mapping between
+ model names and model classes.
+ """
+ with api.Environment.manage():
+ env = api.Environment(cr, SUPERUSER_ID, {})
+ report_domain = [
+ ("report_name", "=", "report_xml.demo_report_xml_view") # report tech name
+ ]
+ demo_report = env["ir.actions.report"].search(report_domain, limit=1)
+ if demo_report:
+ dir_path = os.path.dirname(__file__)
+ xsd_file_relative_path = "demo/demo_report.xsd"
+ xsd_file_full_path = os.path.join(dir_path, xsd_file_relative_path)
+
+ with open(xsd_file_full_path, "r") as xsd:
+ # `xsd_schema` is binary fields with an attribute
+ # `attachment=True` so XSD Schema will be added as attachment
+ attach_vals = {
+ "name": "Demo Report.xsd",
+ "datas": xsd.read(),
+ "res_model": "ir.actions.report",
+ "res_id": demo_report.id,
+ "res_field": "xsd_schema",
+ "type": "binary",
+ }
+ env["ir.attachment"].create(attach_vals)
diff --git a/report_xml/models/__init__.py b/report_xml/models/__init__.py
index ce7d113e2..f7c21950b 100644
--- a/report_xml/models/__init__.py
+++ b/report_xml/models/__init__.py
@@ -1,3 +1,3 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
-from . import report_action
+from . import ir_actions_report
diff --git a/report_xml/models/ir_actions_report.py b/report_xml/models/ir_actions_report.py
new file mode 100644
index 000000000..56e125d61
--- /dev/null
+++ b/report_xml/models/ir_actions_report.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2014-2015 Grupo ESOC
+# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
+
+from odoo import fields, models
+
+
+class IrActionsReport(models.Model):
+ _inherit = "ir.actions.report"
+
+ report_type = fields.Selection(selection_add=[("qweb-xml", "XML")])
+ xsd_schema = fields.Binary(
+ string="XSD Validation Schema",
+ attachment=True,
+ help=(
+ "File with XSD Schema for checking content of result report. "
+ "Can be empty if validation is not required."
+ ),
+ )
+ xml_encoding = fields.Selection(
+ selection=[
+ ("UTF-8", "UTF-8") # will be used as default even if nothing is selected
+ ],
+ string="XML Encoding",
+ help=(
+ "Encoding for XML reports. If nothing is selected, "
+ "then UTF-8 will be applied."
+ ),
+ )
+ xml_declaration = fields.Boolean(
+ string="XML Declaration",
+ help=(
+ """Add `` at the start """
+ """of final report file."""
+ ),
+ )
+
+ def render_qweb_xml(self, docids, data=None):
+ """
+ Call `generate_report` method of report abstract class
+ `report.` or of standard class for XML report
+ rendering - `report.report_xml.abstract`
+
+ Args:
+ * docids(list) - IDs of instances for those report will be generated
+ * data(dict, None) - variables for report rendering
+
+ Returns:
+ * str - result content of report
+ * str - type of result content
+ """
+ report_model_name = "report.{}".format(self.report_name)
+
+ report_model = self.env.get(report_model_name)
+ if report_model is None:
+ report_model = self.env["report.report_xml.abstract"]
+
+ content, ttype = report_model.generate_report(
+ ir_report=self, # will be used to get settings of report
+ docids=docids,
+ data=data,
+ )
+ return content, ttype
diff --git a/report_xml/models/report_action.py b/report_xml/models/report_action.py
deleted file mode 100644
index 62547c597..000000000
--- a/report_xml/models/report_action.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2014-2015 Grupo ESOC
-# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
-
-from lxml import etree
-
-from odoo import api, fields, models
-
-
-class ReportAction(models.Model):
- _inherit = "ir.actions.report"
-
- report_type = fields.Selection(selection_add=[("qweb-xml", "XML")])
-
- @api.model
- def render_qweb_xml(self, docids, data=None):
- if not data:
- data = {}
- data.setdefault("report_type", "text")
- data = self._get_rendering_context(docids, data)
- result = self.render_template(self.report_name, data)
- return (
- etree.tostring(
- etree.fromstring(
- str(result, "UTF-8").lstrip("\n").lstrip().encode("UTF-8")
- ),
- encoding="UTF-8",
- xml_declaration=True,
- pretty_print=True,
- ),
- "xml",
- )
diff --git a/report_xml/readme/CONTRIBUTORS.rst b/report_xml/readme/CONTRIBUTORS.rst
index 98e13baea..12497944c 100644
--- a/report_xml/readme/CONTRIBUTORS.rst
+++ b/report_xml/readme/CONTRIBUTORS.rst
@@ -1,4 +1,5 @@
* Enric Tobella
* `Tecnativa `_:
-
- Jairo Llopis
+ * Jairo Llopis
+* `Avoin.Systems `_:
+ * Tatiana Deribina
diff --git a/report_xml/readme/USAGE.rst b/report_xml/readme/USAGE.rst
index 8a8160c22..3574a6bb3 100644
--- a/report_xml/readme/USAGE.rst
+++ b/report_xml/readme/USAGE.rst
@@ -3,25 +3,30 @@ This module is intended as a base engine for other modules to use it, so no dire
If you are a developer
~~~~~~~~~~~~~~~~~~~~~~
-To learn from an example, just check the `sample module`_.
+To learn from an example, just check the `demo report`_ on GitHub for
+the model ``res.company`` or check it in interface from companies views.
To develop with this module, you need to:
* Create a module.
* Make it depend on this one.
* Follow `instructions to create reports`_ having in mind that the
- ``report_type`` field in your ``ir.actions.report.xml`` record must be
+ ``report_type`` field in your ``ir.actions.report`` record must be
``qweb-xml``.
In case you want to create a `custom report`_, the instructions remain the same
as for HTML reports, and the method that you must override is also called
``_get_report_values``, even when this time you are creating a XML report.
-You can make your custom report inherit ``report_xml.xsd_checked_report``, name
-it like your XML ```` id prepended by ``report.``, add a ``xsd()``
-method that returns a XSD in a string, and have XSD automatic checking for
+You can make your custom report inherit ``report.report_xml.abstract``, name
+it in such way ``report.``. Also you can add a XSD file for
+report validation into ``xsd_schema`` field of your report (check
+`report definition`_) and have XSD automatic checking for
free.
+You can customize rendering process and validation way via changing logic of
+``generate_report`` and ``validate_report`` methods in your report class.
+
You can visit ``http:///report/xml//``
to see your XML report online as a web page.
@@ -30,6 +35,7 @@ For further information, please visit:
* https://www.odoo.com/forum/help-1
* https://github.com/OCA/reporting-engine
-.. _custom report: https://www.odoo.com/documentation/12.0/reference/reports.html#custom-reports
-.. _instructions to create reports: https://www.odoo.com/documentation/12.0/reference/reports.html
-.. _sample module: https://github.com/OCA/reporting-engine/tree/12.0/report_xml_sample
+.. _custom report: https://www.odoo.com/documentation/13.0/reference/reports.html#custom-reports
+.. _instructions to create reports: https://www.odoo.com/documentation/13.0/reference/reports.html
+.. _demo report: https://github.com/OCA/reporting-engine/blob/13.0/report_xml/demo/demo_report.xml
+.. _report definition: https://github.com/OCA/reporting-engine/blob/13.0/report_xml/demo/report.xml
diff --git a/report_xml/reports/__init__.py b/report_xml/reports/__init__.py
new file mode 100644
index 000000000..fff0f44db
--- /dev/null
+++ b/report_xml/reports/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
+
+from . import report_report_xml_abstract
diff --git a/report_xml/reports/report_report_xml_abstract.py b/report_xml/reports/report_report_xml_abstract.py
new file mode 100644
index 000000000..b3fd291d2
--- /dev/null
+++ b/report_xml/reports/report_report_xml_abstract.py
@@ -0,0 +1,123 @@
+# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
+
+from base64 import b64decode
+from xml.dom import minidom
+
+from lxml import etree
+
+from odoo import api, models
+from odoo.exceptions import ValidationError
+
+
+class ReportXmlAbstract(models.AbstractModel):
+ """
+ Model `report.report_xml.abstract`.
+
+ This class provide basic methods for rendering XML report and it's
+ validation by XSD schema.
+ """
+
+ _name = "report.report_xml.abstract"
+ _description = "Abstract XML Report"
+
+ @api.model
+ def generate_report(self, ir_report, docids, data=None):
+ """
+ Generate and validate XML report. Use incoming `ir_report` settings
+ to setup encoding and XMl declaration for result `xml`.
+
+ Methods:
+ * `_get_rendering_context` `ir.actions.report` - get report variables.
+ It will call `_get_report_values` of report's class if it's exist.
+ * `render_template` of `ir.actions.report` - get report content
+ * `validate_report` - check result content
+
+ Args:
+ * ir_report(`ir.actions.report`) - report definition instance in Odoo
+ * docids(list) - IDs of instances for those report will be generated
+ * data(dict, None) - variables for report rendering
+
+ Returns:
+ * str - result content of report
+ * str - `"xml"`
+
+ Extra Info:
+ * Default encoding is `UTF-8`
+ """
+ # collect variable for rendering environment
+ if not data:
+ data = {}
+ data.setdefault("report_type", "text")
+ data = ir_report._get_rendering_context(docids, data)
+
+ # render template
+ result_bin = ir_report.render_template(ir_report.report_name, data)
+
+ # prettify result content
+ # normalize indents
+ parsed_result_bin = minidom.parseString(result_bin)
+ result = parsed_result_bin.toprettyxml(indent=" " * 4)
+
+ # remove empty lines
+ utf8 = "UTF-8"
+ result = "\n".join(
+ line for line in result.splitlines() if line and not line.isspace()
+ ).encode(utf8)
+
+ content = etree.tostring(
+ etree.fromstring(result),
+ encoding=ir_report.xml_encoding or utf8,
+ xml_declaration=ir_report.xml_declaration,
+ pretty_print=True,
+ )
+
+ # validate content
+ xsd_schema_doc = ir_report.xsd_schema
+ self.validate_report(xsd_schema_doc, content)
+ return content, "xml"
+
+ @api.model
+ def validate_report(self, xsd_schema_doc, content):
+ """
+ Validate final report content against value of `xsd_schema` field
+ ("XSD Validation Schema") of `ir.actions.report` via `etree` lib.
+
+ Args:
+ * xsd_schema_doc(byte-string) - report validation schema
+ * content(str) - report content for validation
+
+ Raises:
+ * odoo.exceptions.ValidationError - Syntax of final report is wrong
+
+ Returns:
+ * bool - True
+ """
+ if xsd_schema_doc:
+ # create validation parser
+ decoded_xsd_schema_doc = b64decode(xsd_schema_doc)
+ parsed_xsd_schema = etree.XML(decoded_xsd_schema_doc)
+ xsd_schema = etree.XMLSchema(parsed_xsd_schema)
+ parser = etree.XMLParser(schema=xsd_schema)
+
+ try:
+ # check content
+ etree.fromstring(content, parser)
+ except etree.XMLSyntaxError as error:
+ raise ValidationError(error.msg)
+ return True
+
+ @api.model
+ def _get_report_values(self, docids, data=None):
+ """
+ Allow to generate extra variables for report environment.
+
+ Args:
+ * docids(list) - IDs of instances for those report will be generated
+ * data(dict, None) - variables for report rendering
+
+ Returns:
+ * dict - extra variables for report render
+ """
+ if not data:
+ data = {}
+ return data
diff --git a/report_xml/static/description/index.html b/report_xml/static/description/index.html
index a7e4d0f60..80d34de08 100644
--- a/report_xml/static/description/index.html
+++ b/report_xml/static/description/index.html
@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-
+
This module was written to extend the functionality of the reporting engine to
support XML reports and allow modules to generate them by code or by QWeb
templates.
@@ -404,22 +404,25 @@ installed it’s probably because there is another module that depends on it.
This module is intended as a base engine for other modules to use it, so no direct result if you are a user.
To learn from an example, just check the sample module.
+
To learn from an example, just check the demo report.
To develop with this module, you need to:
Create a module.
Make it depend on this one.
-
Follow instructions to create reports having in mind that the
-report_type field in your ir.actions.report.xml record must be
+
Follow instructions to create reports having in mind that the
+report_type field in your ir.actions.report record must be
qweb-xml.
-
In case you want to create a custom report, the instructions remain the same
+
In case you want to create a custom report, the instructions remain the same
as for HTML reports, and the method that you must override is also called
_get_report_values, even when this time you are creating a XML report.
-
You can make your custom report inherit report_xml.xsd_checked_report, name
-it like your XML <template> id prepended by report., add a xsd()
-method that returns a XSD in a string, and have XSD automatic checking for
+
You can make your custom report inherit report.report_xml.abstract, name
+it in such way report.<module.report_name>. Also you can add a XSD file for
+report validation into xsd_schema field of your report (check
+report definition) and have XSD automatic checking for
free.
+
You can customize rendering process and validation way via changing logic of
+generate_report and validate_report methods in your report class.
You can visit http://<server-address>/report/xml/<module.report_name>/<ids>
to see your XML report online as a web page.
For further information, please visit:
@@ -434,7 +437,7 @@ to see your XML report online as a web page.
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
-feedback.
@@ -468,7 +484,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.