OCA reporting engine fork for dev and update.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
3.7 KiB

9 years ago
9 years ago
  1. # -*- encoding: utf-8 -*-
  2. # Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
  3. import logging
  4. from lxml import etree
  5. from openerp import api, fields, models
  6. _logger = logging.getLogger(__name__)
  7. class ReportAction(models.Model):
  8. _inherit = "ir.actions.report.xml"
  9. report_type = fields.Selection(selection_add=[("qweb-xml", "XML")])
  10. def _lookup_report(self, cr, name):
  11. """Enable ``qweb-xml`` report lookup."""
  12. try:
  13. return super(ReportAction, self)._lookup_report(cr, name)
  14. except Exception as ex:
  15. # Somebody thought it was a good idea to use standard exceptions
  16. if "qweb-xml" not in ex.message:
  17. raise ex
  18. else:
  19. cr.execute(
  20. "SELECT * FROM ir_act_report_xml WHERE report_name=%s",
  21. (name,))
  22. return cr.dictfetchone()["report_name"]
  23. @api.model
  24. def render_report(self, res_ids, name, data):
  25. """Special handling for ``qweb-xml`` reports."""
  26. if data.get("report_type") == u"qweb-xml":
  27. new_report = self._lookup_report(name)
  28. recs = self.env[self.env.context["active_model"]].browse(res_ids)
  29. result = self.env["report"].get_html(recs, new_report, data=data)
  30. # XML with spaces before the <?xml tag will fail, and trailing ones
  31. # do nothing, so let's strip them and make everyone happier
  32. result = (result.strip(), "xml")
  33. else:
  34. result = super(ReportAction, self).render_report(
  35. res_ids, name, data)
  36. return result
  37. class ReportGenerator(models.Model):
  38. _inherit = "report"
  39. @api.model
  40. def _get_report_from_name(self, report_name):
  41. """Allow to view ``qweb-xml`` reports as web pages."""
  42. try:
  43. return (super(ReportGenerator, self)
  44. ._get_report_from_name(report_name))
  45. except IndexError:
  46. return self.env["ir.actions.report.xml"].search(
  47. [("report_type", "=", "qweb-xml"),
  48. ("report_name", "=", report_name)])[0]
  49. class XSDCheckedReport(models.AbstractModel):
  50. """Check XML report against a XSD schema before downloading it.
  51. This is an Abstract Model to be inherited by the real report models, which
  52. must implement :meth:`.xsd` and have a ``_name`` in the form
  53. ``report.<module>.<report_name>``.
  54. """
  55. _name = "report_xml.xsd_checked_report"
  56. _description = "Base model for reports that need XSD checking"
  57. @api.multi
  58. def xsd(self):
  59. """Return the XSD schema contents."""
  60. raise NotImplementedError
  61. @api.multi
  62. def render_html(self, data=None):
  63. """Return the XML report after checking it against an XSD.
  64. If ``context`` contains a dict called ``docargs``, it will be used as
  65. the Qweb context. The special key ``docs`` will be added to ``docargs``
  66. automatically if missing.
  67. """
  68. # Qweb context
  69. docargs = self.env.context.get("docargs", dict())
  70. if "docs" not in docargs:
  71. docargs["docs"] = (self.env[self.env.context["active_model"]]
  72. .browse(self.env.context["active_ids"]))
  73. # Load XSD
  74. xsd = etree.XML(self.xsd())
  75. _logger.debug("XSD schema contents: %s", etree.tostring(xsd))
  76. xsd = etree.XMLSchema(xsd)
  77. parser = etree.XMLParser(schema=xsd)
  78. # Generate XML report
  79. result = (self.env["report"]
  80. .render(self._name[len("report."):], docargs)
  81. .strip())
  82. # Validate XML with XSD
  83. try:
  84. etree.fromstring(result, parser)
  85. except Exception as error:
  86. _logger.error(result)
  87. raise error
  88. return result