Skip to content

Commit

Permalink
Merge 4263985 into 05f5fe2
Browse files Browse the repository at this point in the history
  • Loading branch information
Tatider committed Dec 24, 2019
2 parents 05f5fe2 + 4263985 commit 2410ed0
Show file tree
Hide file tree
Showing 98 changed files with 9,912 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .isort.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ line_length=88
known_odoo=odoo
known_odoo_addons=odoo.addons
sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER
known_third_party=
known_third_party=lxml,werkzeug
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/psf/black
rev: 19.3b0
rev: 19.10b0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
142 changes: 142 additions & 0 deletions report_xml/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
===========
XML Reports
===========

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
: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
: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-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/13.0
:alt: Try me on Runbot

|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
templates.

**Table of contents**

.. contents::
:local:

Installation
============

To install this module, you need to:

* Install lxml_ in Odoo's ``$PYTHONPATH``.
* Install the repository `reporting-engine`_.

But this module does nothing for the end user by itself, so if you have it
installed it's probably because there is another module that depends on it.

.. _reporting-engine: https://github.com/OCA/reporting-engine
.. _lxml: http://lxml.de/

Usage
=====

This module is intended as a base engine for other modules to use it, so no direct result if you are a user.

If you are a developer
~~~~~~~~~~~~~~~~~~~~~~

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`` 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.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:

* https://www.odoo.com/forum/help-1
* https://github.com/OCA/reporting-engine

.. _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/tree/13.0/report_xml/report_xml/demo
.. _report definition: https://github.com/OCA/reporting-engine/blob/13.0/report_xml/report_xml/demo/reports.xml

Bug Tracker
===========

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.
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**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Tecnativa

Contributors
~~~~~~~~~~~~

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

Other credits
~~~~~~~~~~~~~

* Icon taken from http://commons.wikimedia.org/wiki/File:Text-xml.svg

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

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 <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.
6 changes: 6 additions & 0 deletions report_xml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).

from . import controllers
from . import models
from . import reports
from .hooks import post_init_hook
23 changes: 23 additions & 0 deletions report_xml/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
{
"name": "XML Reports",
"version": "13.0.1.0.0",
"category": "Reporting",
"website": "https://github.com/OCA/reporting-engine",
"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", # 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
],
"post_init_hook": "post_init_hook",
}
3 changes: 3 additions & 0 deletions report_xml/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).

from . import main
93 changes: 93 additions & 0 deletions report_xml/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).

import json
import time

from werkzeug.urls import url_decode

from odoo.http import content_disposition, request, route, serialize_exception
from odoo.tools import html_escape, safe_eval

from odoo.addons.web.controllers import main as report


class ReportController(report.ReportController):
@route()
def report_routes(self, reportname, docids=None, converter=None, **data):
if converter == "xml":
report = request.env["ir.actions.report"]._get_report_from_name(reportname)
context = dict(request.env.context)

if docids:
docids = [int(i) for i in docids.split(",")]
if data.get("options"):
data.update(json.loads(data.pop("options")))
if data.get("context"):
# Ignore 'lang' here, because the context in data is the one
# from the webclient *but* if the user explicitely wants to
# change the lang, this mechanism overwrites it.
data["context"] = json.loads(data["context"])
if data["context"].get("lang"):
del data["context"]["lang"]
context.update(data["context"])

xml = report.with_context(context).render_qweb_xml(docids, data=data)[0]
xmlhttpheaders = [
("Content-Type", "text/xml"),
("Content-Length", len(xml)),
]
return request.make_response(xml, headers=xmlhttpheaders)
else:
return super(ReportController, self).report_routes(
reportname, docids, converter, **data
)

@route()
def report_download(self, data, token):
requestcontent = json.loads(data)
url, report_type = requestcontent[0], requestcontent[1]
if report_type == "qweb-xml":
try:
reportname = url.split("/report/xml/")[1].split("?")[0]

docids = None
if "/" in reportname:
reportname, docids = reportname.split("/")

if docids:
# Generic report:
response = self.report_routes(
reportname, docids=docids, converter="xml"
)
else:
# Particular report:
# decoding the args represented in JSON
data = url_decode(url.split("?")[1]).items()
response = self.report_routes(
reportname, converter="xml", **dict(data)
)

report_obj = request.env["ir.actions.report"]
report = report_obj._get_report_from_name(reportname)
filename = "%s.xml" % (report.name)

if docids:
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 = "{}.xml".format(report_name)
response.headers.add(
"Content-Disposition", content_disposition(filename)
)
response.set_cookie("fileToken", token)
return response
except Exception as e:
se = serialize_exception(e)
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)
14 changes: 14 additions & 0 deletions report_xml/demo/demo_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>

<template id="demo_report_xml_view">
<root>
<user t-foreach="docs" t-as="doc">
<id><t t-esc="doc.id"/></id>
<name t-esc="doc.name"/>
<vat t-esc="doc.vat"/>
</user>
</root>
</template>

</odoo>
23 changes: 23 additions & 0 deletions report_xml/demo/demo_report.xsd
Original file line number Diff line number Diff line change
@@ -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>
21 changes: 21 additions & 0 deletions report_xml/demo/report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>

<report id="demo_xml_report"
name="report_xml.demo_report_xml_view"
string="Demo xml report"
report_type="qweb-xml"
print_report_name="'Demo xml report'"
model="res.company"
/>

<!--
In case of demo data next definition will not work. So it just example
how it should look. If report is a part of demo data you will need
add file to report instance via `post_install_hook`
-->
<record id="demo_xml_report" model="ir.actions.report">
<field name="xsd_schema" type="base64" file="report_xml/demo/demo_report.xsd"/>
</record>

</odoo>
47 changes: 47 additions & 0 deletions report_xml/hooks.py
Original file line number Diff line number Diff line change
@@ -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)
Loading

0 comments on commit 2410ed0

Please sign in to comment.