317 lines
11 KiB
ReStructuredText
317 lines
11 KiB
ReStructuredText
:banner: banners/reports.jpg
|
|
|
|
.. highlight:: xml
|
|
|
|
============
|
|
QWeb Reports
|
|
============
|
|
|
|
Reports are written in HTML/QWeb, like all regular views in Odoo. You can use
|
|
the usual :ref:`QWeb control flow tools <reference/qweb>`. The PDF rendering
|
|
itself is performed by wkhtmltopdf_.
|
|
|
|
If you want to create a report on a certain model, you will need to define
|
|
this :ref:`reference/reports/report` and the
|
|
:ref:`reference/reports/templates` it will use. If you wish, you can also
|
|
specify a specific :ref:`reference/reports/paper_formats` for this
|
|
report. Finally, if you need access to more than your model, you can define a
|
|
:ref:`reference/reports/custom_reports` class that gives you access to more
|
|
models and records in the template.
|
|
|
|
.. _reference/reports/report:
|
|
|
|
Report
|
|
======
|
|
|
|
Every report must be declared by a :ref:`report action
|
|
<reference/actions/report>`.
|
|
|
|
For simplicity, a shortcut ``<report>`` element is available to define a
|
|
report, rather than have to set up :ref:`the action
|
|
<reference/actions/report>` and its surroundings manually. That ``<report>``
|
|
can take the following attributes:
|
|
|
|
``id``
|
|
the generated record's :term:`external id`
|
|
``name`` (mandatory)
|
|
only useful as a mnemonic/description of the report when looking for one
|
|
in a list of some sort
|
|
``model`` (mandatory)
|
|
the model your report will be about
|
|
``report_type`` (mandatory)
|
|
either ``qweb-pdf`` for PDF reports or ``qweb-html`` for HTML
|
|
``report_name``
|
|
the name of your report (which will be the name of the PDF output)
|
|
``groups``
|
|
:class:`~odoo.fields.Many2many` field to the groups allowed to view/use
|
|
the current report
|
|
``attachment_use``
|
|
if set to True, the report will be stored as an attachment of the record
|
|
using the name generated by the ``attachment`` expression; you can use
|
|
this if you need your report to be generated only once (for legal reasons,
|
|
for example)
|
|
``attachment``
|
|
python expression that defines the name of the report; the record is
|
|
acessible as the variable ``object``
|
|
``paperformat``
|
|
external id of the paperformat you wish to use (defaults to the company's
|
|
paperformat if not specified)
|
|
|
|
Example::
|
|
|
|
<report
|
|
id="account_invoices"
|
|
model="account.invoice"
|
|
string="Invoices"
|
|
report_type="qweb-pdf"
|
|
name="account.report_invoice"
|
|
file="account.report_invoice"
|
|
attachment_use="True"
|
|
attachment="(object.state in ('open','paid')) and
|
|
('INV'+(object.number or '').replace('/','')+'.pdf')"
|
|
/>
|
|
|
|
.. _reference/reports/templates:
|
|
|
|
Report template
|
|
===============
|
|
|
|
|
|
Minimal viable template
|
|
-----------------------
|
|
|
|
A minimal template would look like::
|
|
|
|
<template id="report_invoice">
|
|
<t t-call="report.html_container">
|
|
<t t-foreach="docs" t-as="o">
|
|
<t t-call="report.external_layout">
|
|
<div class="page">
|
|
<h2>Report title</h2>
|
|
<p>This object's name is <span t-field="o.name"/></p>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
Calling ``external_layout`` will add the default header and footer on your
|
|
report. The PDF body will be the content inside the ``<div
|
|
class="page">``. The template's ``id`` must be the name specified in the
|
|
report declaration; for example ``account.report_invoice`` for the above
|
|
report. Since this is a QWeb template, you can access all the fields of the
|
|
``docs`` objects received by the template.
|
|
|
|
There are some specific variables accessible in reports, mainly:
|
|
|
|
``docs``
|
|
records for the current report
|
|
``doc_ids``
|
|
list of ids for the ``docs`` records
|
|
``doc_model``
|
|
model for the ``docs`` records
|
|
``time``
|
|
a reference to :mod:`python:time` from the Python standard library
|
|
``user``
|
|
``res.user`` record for the user printing the report
|
|
``res_company``
|
|
record for the current ``user``'s company
|
|
|
|
If you wish to access other records/models in the template, you will need
|
|
:ref:`a custom report <reference/reports/custom_reports>`.
|
|
|
|
Translatable Templates
|
|
----------------------
|
|
|
|
If you wish to translate reports (to the language of a partner, for example),
|
|
you need to define two templates:
|
|
|
|
* The main report template
|
|
* The translatable document
|
|
|
|
You can then call the translatable document from your main template with the attribute
|
|
``t-lang`` set to a language code (for example ``fr`` or ``en_US``) or to a record field.
|
|
You will also need to re-browse the related records with the proper context if you use
|
|
fields that are translatable (like country names, sales conditions, etc.)
|
|
|
|
.. warning::
|
|
|
|
If your report template does not use translatable record fields, re-browsing the record
|
|
in another language is *not* necessary and will impact performances.
|
|
|
|
For example, let's look at the Sale Order report from the Sale module::
|
|
|
|
<!-- Main template -->
|
|
<template id="report_saleorder">
|
|
<t t-call="report.html_container">
|
|
<t t-foreach="docs" t-as="doc">
|
|
<t t-call="sale.report_saleorder_document" t-lang="doc.partner_id.lang"/>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- Translatable template -->
|
|
<template id="report_saleorder_document">
|
|
<!-- Re-browse of the record with the partner lang -->
|
|
<t t-set="doc" t-value="doc.with_context({'lang':doc.partner_id.lang})" />
|
|
<t t-call="report.external_layout">
|
|
<div class="page">
|
|
<div class="oe_structure"/>
|
|
<div class="row">
|
|
<div class="col-xs-6">
|
|
<strong t-if="doc.partner_shipping_id == doc.partner_invoice_id">Invoice and shipping address:</strong>
|
|
<strong t-if="doc.partner_shipping_id != doc.partner_invoice_id">Invoice address:</strong>
|
|
<div t-field="doc.partner_invoice_id" t-options="{"no_marker": True}"/>
|
|
<...>
|
|
<div class="oe_structure"/>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
|
|
The main template calls the translatable template with ``doc.partner_id.lang`` as a
|
|
``t-lang`` parameter, so it will be rendered in the language of the partner. This way,
|
|
each Sale Order will be printed in the language of the corresponding customer. If you wish
|
|
to translate only the body of the document, but keep the header and footer in a default
|
|
language, you could call the report's external layout this way::
|
|
|
|
<t t-call="report.external_layout" t-lang="en_US">
|
|
|
|
.. tip::
|
|
|
|
Please take note that this works only when calling external templates, you will not be
|
|
able to translate part of a document by setting a ``t-lang`` attribute on an xml node other
|
|
than ``t-call``. If you wish to translate part of a template, you can create an external
|
|
template with this partial template and call it from the main one with the ``t-lang``
|
|
attribute.
|
|
|
|
|
|
Barcodes
|
|
--------
|
|
|
|
Barcodes are images returned by a controller and can easily be embedded in
|
|
reports thanks to the QWeb syntax:
|
|
|
|
.. code-block:: html
|
|
|
|
<img t-att-src="'/report/barcode/QR/%s' % 'My text in qr code'"/>
|
|
|
|
More parameters can be passed as a query string
|
|
|
|
.. code-block:: html
|
|
|
|
<img t-att-src="'/report/barcode/?
|
|
type=%s&value=%s&width=%s&height=%s'%('QR', 'text', 200, 200)"/>
|
|
|
|
|
|
Useful Remarks
|
|
--------------
|
|
* Twitter Bootstrap and FontAwesome classes can be used in your report
|
|
template
|
|
* Local CSS can be put directly in the template
|
|
* Global CSS can be inserted in the main report layout by inheriting its
|
|
template and inserting your CSS::
|
|
|
|
<template id="report_saleorder_style" inherit_id="report.style">
|
|
<xpath expr=".">
|
|
<t>
|
|
.example-css-class {
|
|
background-color: red;
|
|
}
|
|
</t>
|
|
</xpath>
|
|
</template>
|
|
* If it appears that your PDF report is missing the styles, please check
|
|
:ref:`these instructions <reference/backend/reporting/printed-reports/pdf-without-styles>`.
|
|
|
|
.. _reference/reports/paper_formats:
|
|
|
|
Paper Format
|
|
============
|
|
|
|
Paper formats are records of ``report.paperformat`` and can contain the
|
|
following attributes:
|
|
|
|
``name`` (mandatory)
|
|
only useful as a mnemonic/description of the report when looking for one
|
|
in a list of some sort
|
|
``description``
|
|
a small description of your format
|
|
``format``
|
|
either a predefined format (A0 to A9, B0 to B10, Legal, Letter,
|
|
Tabloid,...) or ``custom``; A4 by default. You cannot use a non-custom
|
|
format if you define the page dimensions.
|
|
``dpi``
|
|
output DPI; 90 by default
|
|
``margin_top``, ``margin_bottom``, ``margin_left``, ``margin_right``
|
|
margin sizes in mm
|
|
``page_height``, ``page_width``
|
|
page dimensions in mm
|
|
``orientation``
|
|
Landscape or Portrait
|
|
``header_line``
|
|
boolean to display a header line
|
|
``header_spacing``
|
|
header spacing in mm
|
|
|
|
Example::
|
|
|
|
<record id="paperformat_frenchcheck" model="report.paperformat">
|
|
<field name="name">French Bank Check</field>
|
|
<field name="default" eval="True"/>
|
|
<field name="format">custom</field>
|
|
<field name="page_height">80</field>
|
|
<field name="page_width">175</field>
|
|
<field name="orientation">Portrait</field>
|
|
<field name="margin_top">3</field>
|
|
<field name="margin_bottom">3</field>
|
|
<field name="margin_left">3</field>
|
|
<field name="margin_right">3</field>
|
|
<field name="header_line" eval="False"/>
|
|
<field name="header_spacing">3</field>
|
|
<field name="dpi">80</field>
|
|
</record>
|
|
|
|
.. _reference/reports/custom_reports:
|
|
|
|
Custom Reports
|
|
==============
|
|
|
|
The report model has a default ``get_html`` function that looks for a model
|
|
named :samp:`report.{module.report_name}`. If it exists, it will use it to
|
|
call the QWeb engine; otherwise a generic function will be used. If you wish
|
|
to customize your reports by including more things in the template (like
|
|
records of others models, for example), you can define this model, overwrite
|
|
the function ``render_html`` and pass objects in the ``docargs`` dictionary:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo import api, models
|
|
|
|
class ParticularReport(models.AbstractModel):
|
|
_name = 'report.module.report_name'
|
|
@api.model
|
|
def render_html(self, docids, data=None):
|
|
report_obj = self.env['report']
|
|
report = report_obj._get_report_from_name('module.report_name')
|
|
docargs = {
|
|
'doc_ids': docids,
|
|
'doc_model': report.model,
|
|
'docs': self,
|
|
}
|
|
return report_obj.render('module.report_name', docargs)
|
|
|
|
Reports are web pages
|
|
=====================
|
|
|
|
Reports are dynamically generated by the report module and can be accessed
|
|
directly via URL:
|
|
|
|
For example, you can access a Sale Order report in html mode by going to
|
|
\http://<server-address>/report/html/sale.report_saleorder/38
|
|
|
|
Or you can access the pdf version at
|
|
\http://<server-address>/report/pdf/sale.report_saleorder/38
|
|
|
|
.. _wkhtmltopdf: http://wkhtmltopdf.org
|