[MIG][13.0] report_xml: Migration to 13.0

pull/359/head
Tatiana Deribina 2019-12-23 15:49:33 +02:00
parent c553fd4f56
commit a78247dc1a
24 changed files with 435 additions and 126 deletions

View File

@ -10,4 +10,3 @@ known_odoo=odoo
known_odoo_addons=odoo.addons known_odoo_addons=odoo.addons
sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER
default_section=THIRDPARTY default_section=THIRDPARTY
known_third_party=lxml,setuptools,werkzeug

View File

@ -14,16 +14,16 @@ XML Reports
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github .. |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 :alt: OCA/reporting-engine
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png .. |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 :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png .. |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 :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 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 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 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: To develop with this module, you need to:
* Create a module. * Create a module.
* Make it depend on this one. * Make it depend on this one.
* Follow `instructions to create reports`_ having in mind that the * 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``. ``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 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. ``_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 You can make your custom report inherit ``report.report_xml.abstract``, name
it like your XML ``<template>`` id prepended by ``report.``, add a ``xsd()`` it in such way ``report.<module.report_name>``. Also you can add a XSD file for
method that returns a XSD in a string, and have XSD automatic checking for report validation into ``xsd_schema`` field of your report (check
`report definition`_) and have XSD automatic checking for
free. 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>`` You can visit ``http://<server-address>/report/xml/<module.report_name>/<ids>``
to see your XML report online as a web page. 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://www.odoo.com/forum/help-1
* https://github.com/OCA/reporting-engine * https://github.com/OCA/reporting-engine
.. _custom report: https://www.odoo.com/documentation/12.0/reference/reports.html#custom-reports .. _custom report: https://www.odoo.com/documentation/13.0/reference/reports.html#custom-reports
.. _instructions to create reports: https://www.odoo.com/documentation/12.0/reference/reports.html .. _instructions to create reports: https://www.odoo.com/documentation/13.0/reference/reports.html
.. _sample module: https://github.com/OCA/reporting-engine/tree/12.0/report_xml_sample .. _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 Bug Tracker
=========== ===========
@ -93,7 +99,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/reporting-engine/issues>`_. Bugs are tracked on `GitHub Issues <https://github.com/OCA/reporting-engine/issues>`_.
In case of trouble, please check there if your issue has already been reported. 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 If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_xml%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. `feedback <https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_xml%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues. Do not contact contributors directly about support or help with technical issues.
@ -104,14 +110,16 @@ Authors
~~~~~~~ ~~~~~~~
* Tecnativa * Tecnativa
* Avoin.Systems
Contributors Contributors
~~~~~~~~~~~~ ~~~~~~~~~~~~
* Enric Tobella <etobella@creublanca.es> * Enric Tobella <etobella@creublanca.es>
* `Tecnativa <https://www.tecnativa.com>`_: * `Tecnativa <https://www.tecnativa.com>`_:
* Jairo Llopis
Jairo Llopis * `Avoin.Systems <https://avoin.systems/>`_:
* Tatiana Deribina
Other credits 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 mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
This module is part of the `OCA/reporting-engine <https://github.com/OCA/reporting-engine/tree/12.0/report_xml>`_ project on GitHub. This module is part of the `OCA/reporting-engine <https://github.com/OCA/reporting-engine/tree/13.0/report_xml>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -2,3 +2,5 @@
from . import controllers from . import controllers
from . import models from . import models
from . import reports
from .hooks import post_init_hook

View File

@ -2,15 +2,27 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
{ {
"name": "XML Reports", "name": "XML Reports",
"version": "12.0.1.0.0", "version": "13.0.1.0.0",
"category": "Reporting", "category": "Reporting",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"author": "Tecnativa, " "Odoo Community Association (OCA)", "author": "Tecnativa, Odoo Community Association (OCA), Avoin.Systems",
"license": "AGPL-3", "license": "AGPL-3",
"installable": True, "installable": True,
"application": False, "application": False,
"summary": "Allow to generate XML reports", "summary": "Allow to generate XML reports",
"depends": ["web"], "depends": ["web"],
"data": ["views/webclient_templates.xml", "views/ir_actions_views.xml"], "data": [
"demo": ["demo/report.xml"], "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",
} }

View File

@ -39,9 +39,7 @@ class ReportController(report.ReportController):
] ]
return request.make_response(xml, headers=xmlhttpheaders) return request.make_response(xml, headers=xmlhttpheaders)
else: else:
return super(ReportController, self).report_routes( return super().report_routes(reportname, docids, converter, **data)
reportname, docids, converter, **data
)
@route() @route()
def report_download(self, data, token): def report_download(self, data, token):
@ -73,13 +71,13 @@ class ReportController(report.ReportController):
filename = "%s.xml" % (report.name) filename = "%s.xml" % (report.name)
if docids: 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) records = request.env[report.model].browse(ids)
if report.print_report_name and not len(records) > 1: if report.print_report_name and not len(records) > 1:
report_name = safe_eval( report_name = safe_eval(
report.print_report_name, {"object": records, "time": time} report.print_report_name, {"object": records, "time": time}
) )
filename = "%s.xml" % (report_name) filename = "{}.xml".format(report_name)
response.headers.add( response.headers.add(
"Content-Disposition", content_disposition(filename) "Content-Disposition", content_disposition(filename)
) )
@ -90,4 +88,4 @@ class ReportController(report.ReportController):
error = {"code": 200, "message": "Odoo Server Error", "data": se} error = {"code": 200, "message": "Odoo Server Error", "data": se}
return request.make_response(html_escape(json.dumps(error))) return request.make_response(html_escape(json.dumps(error)))
else: else:
return super(ReportController, self).report_download(data, token) return super().report_download(data, token)

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="demo_report_xml_view">
<root>
<user t-foreach="docs" t-as="doc">
<id t-esc="doc.id" />
<name t-esc="doc.name" />
<vat t-esc="doc.vat" />
</user>
</root>
</template>
</odoo>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="root_type"/>
<xs:complexType name="root_type">
<xs:sequence>
<xs:element name="user"
type="user_type"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="user_type">
<xs:sequence>
<xs:element name="id" type="xs:int"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="vat" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<template id="demo_report_xml_view"> <report
<root> id="demo_xml_report"
<user t-foreach="docs" t-as="doc"> name="report_xml.demo_report_xml_view"
<name t-esc="doc.name"/> string="Demo xml report"
<vat t-esc="doc.vat"/> report_type="qweb-xml"
</user> print_report_name="'Demo xml report'"
</root> model="res.company"
</template> />
<!--
<report id="demo_xml_report" In case of demo data next definition will not work. So it just example
name="report_xml.demo_report_xml_view" how it should look. If report is a part of demo data you will need
string="Demo xml report" add file to report instance via `post_install_hook`
report_type="qweb-xml" -->
print_report_name="'Demo xml report'" <record id="demo_xml_report" model="ir.actions.report">
file="report_xml.xml" <field name="xsd_schema" type="base64" file="report_xml/demo/demo_report.xsd" />
model="res.company"/> </record>
</odoo> </odoo>

View File

@ -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)

View File

@ -1,3 +1,3 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
from . import report_action from . import ir_actions_report

View File

@ -0,0 +1,62 @@
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
# 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 `<?xml encoding="..." version="..."?>` at the start """
"""of final report file."""
),
)
def render_qweb_xml(self, docids, data=None):
"""
Call `generate_report` method of report abstract class
`report.<report technical name>` 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

View File

@ -1,31 +0,0 @@
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
# 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",
)

View File

@ -1,4 +1,5 @@
* Enric Tobella <etobella@creublanca.es> * Enric Tobella <etobella@creublanca.es>
* `Tecnativa <https://www.tecnativa.com>`_: * `Tecnativa <https://www.tecnativa.com>`_:
* Jairo Llopis
Jairo Llopis * `Avoin.Systems <https://avoin.systems/>`_:
* Tatiana Deribina

View File

@ -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 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: To develop with this module, you need to:
* Create a module. * Create a module.
* Make it depend on this one. * Make it depend on this one.
* Follow `instructions to create reports`_ having in mind that the * 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``. ``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 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. ``_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 You can make your custom report inherit ``report.report_xml.abstract``, name
it like your XML ``<template>`` id prepended by ``report.``, add a ``xsd()`` it in such way ``report.<module.report_name>``. Also you can add a XSD file for
method that returns a XSD in a string, and have XSD automatic checking for report validation into ``xsd_schema`` field of your report (check
`report definition`_) and have XSD automatic checking for
free. 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>`` You can visit ``http://<server-address>/report/xml/<module.report_name>/<ids>``
to see your XML report online as a web page. 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://www.odoo.com/forum/help-1
* https://github.com/OCA/reporting-engine * https://github.com/OCA/reporting-engine
.. _custom report: https://www.odoo.com/documentation/12.0/reference/reports.html#custom-reports .. _custom report: https://www.odoo.com/documentation/13.0/reference/reports.html#custom-reports
.. _instructions to create reports: https://www.odoo.com/documentation/12.0/reference/reports.html .. _instructions to create reports: https://www.odoo.com/documentation/13.0/reference/reports.html
.. _sample module: https://github.com/OCA/reporting-engine/tree/12.0/report_xml_sample .. _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

View File

@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
from . import report_report_xml_abstract

View File

@ -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

View File

@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/12.0/report_xml"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-12-0/reporting-engine-12-0-report_xml"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_xml"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_xml"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module was written to extend the functionality of the reporting engine to <p>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 support XML reports and allow modules to generate them by code or by QWeb
templates.</p> templates.</p>
@ -404,22 +404,25 @@ installed its probably because there is another module that depends on it.</p
<p>This module is intended as a base engine for other modules to use it, so no direct result if you are a user.</p> <p>This module is intended as a base engine for other modules to use it, so no direct result if you are a user.</p>
<div class="section" id="if-you-are-a-developer"> <div class="section" id="if-you-are-a-developer">
<h2><a class="toc-backref" href="#id3">If you are a developer</a></h2> <h2><a class="toc-backref" href="#id3">If you are a developer</a></h2>
<p>To learn from an example, just check the <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/12.0/report_xml_sample">sample module</a>.</p> <p>To learn from an example, just check the <a class="reference external" href="https://github.com/OCA/reporting-engine/blob/13.0/report_xml/demo/demo_report.xml">demo report</a>.</p>
<p>To develop with this module, you need to:</p> <p>To develop with this module, you need to:</p>
<ul class="simple"> <ul class="simple">
<li>Create a module.</li> <li>Create a module.</li>
<li>Make it depend on this one.</li> <li>Make it depend on this one.</li>
<li>Follow <a class="reference external" href="https://www.odoo.com/documentation/12.0/reference/reports.html">instructions to create reports</a> having in mind that the <li>Follow <a class="reference external" href="https://www.odoo.com/documentation/13.0/reference/reports.html">instructions to create reports</a> having in mind that the
<tt class="docutils literal">report_type</tt> field in your <tt class="docutils literal">ir.actions.report.xml</tt> record must be <tt class="docutils literal">report_type</tt> field in your <tt class="docutils literal">ir.actions.report</tt> record must be
<tt class="docutils literal"><span class="pre">qweb-xml</span></tt>.</li> <tt class="docutils literal"><span class="pre">qweb-xml</span></tt>.</li>
</ul> </ul>
<p>In case you want to create a <a class="reference external" href="https://www.odoo.com/documentation/12.0/reference/reports.html#custom-reports">custom report</a>, the instructions remain the same <p>In case you want to create a <a class="reference external" href="https://www.odoo.com/documentation/13.0/reference/reports.html#custom-reports">custom report</a>, the instructions remain the same
as for HTML reports, and the method that you must override is also called as for HTML reports, and the method that you must override is also called
<tt class="docutils literal">_get_report_values</tt>, even when this time you are creating a XML report.</p> <tt class="docutils literal">_get_report_values</tt>, even when this time you are creating a XML report.</p>
<p>You can make your custom report inherit <tt class="docutils literal">report_xml.xsd_checked_report</tt>, name <p>You can make your custom report inherit <tt class="docutils literal">report.report_xml.abstract</tt>, name
it like your XML <tt class="docutils literal">&lt;template&gt;</tt> id prepended by <tt class="docutils literal">report.</tt>, add a <tt class="docutils literal">xsd()</tt> it in such way <tt class="docutils literal"><span class="pre">report.&lt;module.report_name&gt;</span></tt>. Also you can add a XSD file for
method that returns a XSD in a string, and have XSD automatic checking for report validation into <tt class="docutils literal">xsd_schema</tt> field of your report (check
<a class="reference external" href="https://github.com/OCA/reporting-engine/blob/13.0/report_xml/demo/report.xml">report definition</a>) and have XSD automatic checking for
free.</p> free.</p>
<p>You can customize rendering process and validation way via changing logic of
<tt class="docutils literal">generate_report</tt> and <tt class="docutils literal">validate_report</tt> methods in your report class.</p>
<p>You can visit <tt class="docutils literal"><span class="pre">http://&lt;server-address&gt;/report/xml/&lt;module.report_name&gt;/&lt;ids&gt;</span></tt> <p>You can visit <tt class="docutils literal"><span class="pre">http://&lt;server-address&gt;/report/xml/&lt;module.report_name&gt;/&lt;ids&gt;</span></tt>
to see your XML report online as a web page.</p> to see your XML report online as a web page.</p>
<p>For further information, please visit:</p> <p>For further information, please visit:</p>
@ -434,7 +437,7 @@ to see your XML report online as a web page.</p>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/reporting-engine/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/reporting-engine/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. 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 If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_xml%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> <a class="reference external" href="https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_xml%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
@ -443,15 +446,28 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<h2><a class="toc-backref" href="#id6">Authors</a></h2> <h2><a class="toc-backref" href="#id6">Authors</a></h2>
<ul class="simple"> <ul class="simple">
<li>Tecnativa</li> <li>Tecnativa</li>
<li>Avoin.Systems</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <div class="section" id="contributors">
<h2><a class="toc-backref" href="#id7">Contributors</a></h2> <h2><a class="toc-backref" href="#id7">Contributors</a></h2>
<ul> <ul class="simple">
<li><p class="first">Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</p> <li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li>
<li><dl class="first docutils">
<dt><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</dt>
<dd><ul class="first last">
<li>Jairo Llopis</li>
</ul>
</dd>
</dl>
</li> </li>
<li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p> <li><dl class="first docutils">
<p>Jairo Llopis</p> <dt><a class="reference external" href="https://avoin.systems/">Avoin.Systems</a>:</dt>
<dd><ul class="first last">
<li>Tatiana Deribina</li>
</ul>
</dd>
</dl>
</li> </li>
</ul> </ul>
</div> </div>
@ -468,7 +484,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/12.0/report_xml">OCA/reporting-engine</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_xml">OCA/reporting-engine</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> <p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div> </div>
</div> </div>

View File

@ -1,19 +1,18 @@
odoo.define('report_xml.ReportActionManager', function (require) { odoo.define("report_xml.ReportActionManager", function(require) {
'use strict'; "use strict";
var ActionManager = require('web.ActionManager'); var ActionManager = require("web.ActionManager");
ActionManager.include({ ActionManager.include({
_executeReportAction: function (action, options) { _executeReportAction: function(action, options) {
if (action.report_type === 'qweb-xml') { if (action.report_type === "qweb-xml") {
return this._triggerDownload(action, options, 'xml'); return this._triggerDownload(action, options, "xml");
} }
return this._super(action, options); return this._super(action, options);
}, },
_makeReportUrls: function (action) { _makeReportUrls: function(action) {
var reportUrls = this._super(action); var reportUrls = this._super(action);
reportUrls.xml = reportUrls.text.replace( reportUrls.xml = reportUrls.text.replace("/report/text/", "/report/xml/");
'/report/text/', '/report/xml/');
return reportUrls; return reportUrls;
}, },
}); });

View File

@ -13,7 +13,7 @@ class TestXmlReport(common.TransactionCase):
report = report_object._get_report_from_name(report_name) report = report_object._get_report_from_name(report_name)
docs = self.env["res.company"].search([], limit=1) docs = self.env["res.company"].search([], limit=1)
self.assertEqual(report.report_type, "qweb-xml") self.assertEqual(report.report_type, "qweb-xml")
rep = report.render(docs.ids, {}) result_report = report.render(docs.ids, {})
root = etree.fromstring(rep[0]) result_tree = etree.fromstring(result_report[0])
el = root.xpath("/root/user/name") el = result_tree.xpath("/root/user/name")
self.assertEqual(el[0].text, docs.ensure_one().name) self.assertEqual(el[0].text, docs.ensure_one().name)

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="ir_actions_report_view_form_report_xml" model="ir.ui.view">
<field name="name">ir.actions.report.view.form.report.xml</field>
<field name="model">ir.actions.report</field>
<field name="inherit_id" ref="base.act_report_xml_view" />
<field name="arch" type="xml">
<button name="associated_view" position="attributes">
<attribute name="attrs">{
'invisible': [
('report_type', 'not in', ('qweb-pdf', 'qweb-html', 'qweb-text', 'qweb-xml')),
],
}</attribute>
</button>
<xpath expr="//page[@name='advanced']/group" position="after">
<group
name="xml_reports"
string="XML Rreport Settings"
attrs="{
'invisible': [
('report_type', '!=', 'qweb-xml')
],
}"
>
<field name="xsd_schema" />
<field name="xml_encoding" />
<field name="xml_declaration" />
</group>
</xpath>
</field>
</record>
</odoo>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="act_report_xml_view" model="ir.ui.view">
<field name="name">ir.actions.report.report.xml</field>
<field name="model">ir.actions.report</field>
<field name="inherit_id" ref="base.act_report_xml_view"/>
<field name="arch" type="xml">
<button name="associated_view" position="attributes">
<attribute name="attrs">{'invisible':[('report_type', 'not in', ['qweb-pdf', 'qweb-html', 'qweb-text', 'qweb-xml'])]}</attribute>
</button>
</field>
</record>
</odoo>

View File

@ -2,7 +2,10 @@
<odoo> <odoo>
<template id="report_xml.assets_backend" inherit_id="web.assets_backend"> <template id="report_xml.assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside"> <xpath expr="." position="inside">
<script type="text/javascript" src="/report_xml/static/src/js/report/action_manager_report.js"/> <script
type="text/javascript"
src="/report_xml/static/src/js/report/action_manager_report.js"
/>
</xpath> </xpath>
</template> </template>
</odoo> </odoo>

View File

@ -0,0 +1 @@
../../../../report_xml

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)