etobella
8 years ago
committed by
Enric Tobella
13 changed files with 157 additions and 139 deletions
-
21report_xml/README.rst
-
7report_xml/__init__.py
-
12report_xml/__manifest__.py
-
4report_xml/controllers/__init__.py
-
7report_xml/controllers/main.py
-
21report_xml/demo/report.xml
-
111report_xml/models.py
-
5report_xml/models/__init__.py
-
49report_xml/models/report_action.py
-
25report_xml/models/report_generator.py
-
4report_xml/tests/__init__.py
-
24report_xml/tests/test_report_xml.py
-
6report_xml/views/report_xml_templates.xml
@ -1,4 +1,5 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es> |
|||
# -*- coding: utf-8 -*- |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import controllers, models |
|||
from . import controllers |
|||
from . import models |
@ -0,0 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import main |
@ -1,8 +1,9 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from openerp.http import route |
|||
from openerp.addons.report.controllers import main as report |
|||
from odoo.addons.report.controllers import main as report |
|||
from odoo.http import route |
|||
|
|||
|
|||
class ReportController(report.ReportController): |
@ -0,0 +1,21 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
|
|||
<template id="demo_report_xml_view"> |
|||
<t t-call="report_xml.utf8_header"> |
|||
<root> |
|||
<user t-foreach="docs" t-as="doc"> |
|||
<name t-esc="doc.name"/> |
|||
<vat t-esc="doc.vat"/> |
|||
</user> |
|||
</root> |
|||
</t> |
|||
</template> |
|||
|
|||
<report id="demo_xml_report" |
|||
name="report_xml.demo_report_xml_view" |
|||
string="Demo xml report" |
|||
report_type="qweb-xml" |
|||
model="res.company"/> |
|||
|
|||
</odoo> |
@ -1,111 +0,0 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es> |
|||
|
|||
import logging |
|||
from lxml import etree |
|||
from openerp import api, fields, models |
|||
|
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class ReportAction(models.Model): |
|||
_inherit = "ir.actions.report.xml" |
|||
|
|||
report_type = fields.Selection(selection_add=[("qweb-xml", "XML")]) |
|||
|
|||
def _lookup_report(self, cr, name): |
|||
"""Enable ``qweb-xml`` report lookup.""" |
|||
try: |
|||
return super(ReportAction, self)._lookup_report(cr, name) |
|||
except Exception as ex: |
|||
# Somebody thought it was a good idea to use standard exceptions |
|||
if "qweb-xml" not in ex.message: |
|||
raise ex |
|||
else: |
|||
cr.execute( |
|||
"SELECT * FROM ir_act_report_xml WHERE report_name=%s", |
|||
(name,)) |
|||
return cr.dictfetchone()["report_name"] |
|||
|
|||
@api.model |
|||
def render_report(self, res_ids, name, data): |
|||
"""Special handling for ``qweb-xml`` reports.""" |
|||
if data.get("report_type") == u"qweb-xml": |
|||
new_report = self._lookup_report(name) |
|||
recs = self.env[self.env.context["active_model"]].browse(res_ids) |
|||
result = self.env["report"].get_html(recs, new_report, data=data) |
|||
|
|||
# XML with spaces before the <?xml tag will fail, and trailing ones |
|||
# do nothing, so let's strip them and make everyone happier |
|||
result = (result.strip(), "xml") |
|||
else: |
|||
result = super(ReportAction, self).render_report( |
|||
res_ids, name, data) |
|||
|
|||
return result |
|||
|
|||
|
|||
class ReportGenerator(models.Model): |
|||
_inherit = "report" |
|||
|
|||
@api.model |
|||
def _get_report_from_name(self, report_name): |
|||
"""Allow to view ``qweb-xml`` reports as web pages.""" |
|||
try: |
|||
return (super(ReportGenerator, self) |
|||
._get_report_from_name(report_name)) |
|||
except IndexError: |
|||
return self.env["ir.actions.report.xml"].search( |
|||
[("report_type", "=", "qweb-xml"), |
|||
("report_name", "=", report_name)])[0] |
|||
|
|||
|
|||
class XSDCheckedReport(models.AbstractModel): |
|||
"""Check XML report against a XSD schema before downloading it. |
|||
|
|||
This is an Abstract Model to be inherited by the real report models, which |
|||
must implement :meth:`.xsd` and have a ``_name`` in the form |
|||
``report.<module>.<report_name>``. |
|||
""" |
|||
_name = "report_xml.xsd_checked_report" |
|||
_description = "Base model for reports that need XSD checking" |
|||
|
|||
@api.multi |
|||
def xsd(self): |
|||
"""Return the XSD schema contents.""" |
|||
raise NotImplementedError |
|||
|
|||
@api.multi |
|||
def render_html(self, data=None): |
|||
"""Return the XML report after checking it against an XSD. |
|||
|
|||
If ``context`` contains a dict called ``docargs``, it will be used as |
|||
the Qweb context. The special key ``docs`` will be added to ``docargs`` |
|||
automatically if missing. |
|||
""" |
|||
# Qweb context |
|||
docargs = self.env.context.get("docargs", dict()) |
|||
if "docs" not in docargs: |
|||
docargs["docs"] = (self.env[self.env.context["active_model"]] |
|||
.browse(self.env.context["active_ids"])) |
|||
|
|||
# Load XSD |
|||
xsd = etree.XML(self.xsd()) |
|||
_logger.debug("XSD schema contents: %s", etree.tostring(xsd)) |
|||
xsd = etree.XMLSchema(xsd) |
|||
parser = etree.XMLParser(schema=xsd) |
|||
|
|||
# Generate XML report |
|||
result = (self.env["report"] |
|||
.render(self._name[len("report."):], docargs) |
|||
.strip()) |
|||
|
|||
# Validate XML with XSD |
|||
try: |
|||
etree.fromstring(result, parser) |
|||
except Exception as error: |
|||
_logger.error(result) |
|||
raise error |
|||
|
|||
return result |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import report_action |
|||
from . import report_generator |
@ -0,0 +1,49 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import logging |
|||
|
|||
from odoo import api, fields, models |
|||
from lxml import etree |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class ReportAction(models.Model): |
|||
_inherit = "ir.actions.report.xml" |
|||
|
|||
report_type = fields.Selection(selection_add=[("qweb-xml", "XML")]) |
|||
|
|||
def _lookup_report(self, name): |
|||
"""Enable ``qweb-xml`` report lookup.""" |
|||
try: |
|||
return super(ReportAction, self)._lookup_report(name) |
|||
except Exception as ex: |
|||
# Somebody thought it was a good idea to use standard exceptions |
|||
if "qweb-xml" not in ex.message: |
|||
raise ex |
|||
else: |
|||
self._cr.execute( |
|||
"SELECT * FROM ir_act_report_xml WHERE report_name=%s", |
|||
(name,)) |
|||
return self._cr.dictfetchone()["report_name"] |
|||
|
|||
@api.model |
|||
def render_report(self, res_ids, name, data): |
|||
"""Special handling for ``qweb-xml`` reports.""" |
|||
xml_report = self.search([('report_name', '=', name), |
|||
('report_type', '=', 'qweb-xml')], limit=1) |
|||
if xml_report: |
|||
xml_report = xml_report.ensure_one() |
|||
result = self.env["report"].get_html(res_ids, |
|||
xml_report.report_name, |
|||
data=data) |
|||
return ( |
|||
etree.tostring( |
|||
etree.fromstring(result.strip()), |
|||
encoding='UTF-8', xml_declaration=True, pretty_print=True |
|||
), "xml") |
|||
else: |
|||
return super(ReportAction, self).render_report( |
|||
res_ids, name, data) |
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import logging |
|||
|
|||
from odoo import api, models |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class ReportGenerator(models.Model): |
|||
_inherit = "report" |
|||
|
|||
@api.model |
|||
def _get_report_from_name(self, report_name): |
|||
res = super(ReportGenerator, self)._get_report_from_name(report_name) |
|||
if res: |
|||
return res |
|||
report_obj = self.env['ir.actions.report.xml'] |
|||
qwebtypes = ['qweb-xml'] |
|||
conditions = [('report_type', 'in', qwebtypes), |
|||
('report_name', '=', report_name)] |
|||
context = self.env['res.users'].context_get() |
|||
return report_obj.with_context(context).search(conditions, limit=1) |
@ -0,0 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import test_report_xml |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Creu Blanca |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from lxml import etree |
|||
from odoo.tests import common |
|||
|
|||
|
|||
class TestXmlReport(common.TransactionCase): |
|||
def test_xml(self): |
|||
report_object = self.env['ir.actions.report.xml'] |
|||
report_name = 'report_xml.demo_report_xml_view' |
|||
self.assertEqual( |
|||
report_name, report_object._lookup_report(report_name)) |
|||
docs = self.env['res.company'].search([], limit=1) |
|||
rep = report_object.render_report( |
|||
docs.ids, report_name, {} |
|||
) |
|||
root = etree.fromstring(rep[0]) |
|||
el = root.xpath('/root/user/name') |
|||
self.assertEqual( |
|||
el[0].text, |
|||
docs.ensure_one().name |
|||
) |
@ -1,11 +1,9 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<odoo> |
|||
|
|||
<template id="utf8_header"> |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<t t-raw="0"/> |
|||
</template> |
|||
|
|||
</data> |
|||
</openerp> |
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue