The last part of the presentation layer is printing out reports. In case you haven't till now, install wkhtmltopdf
as described in Chapter 1, Installing the Odoo Development Environment otherwise you won't get shiny PDFs as result of your efforts.
The conversion mechanism to PDFs is implemented in the addon report, so you should add it as dependency of your addon. Also double check that the configuration parameter web.base.url
(or alternatively, report.url
) is a URL accessible from your Odoo instance, otherwise report generation takes ages and the result looks funny.
<template id="qweb_res_partner_birthdays"> <t t-call="report.html_container"> <t t-call="report.internal_layout"> <div class="page"> <h2>Partner's birthdays</h2> <div t-foreach="docs" t-as="o" class="row mt4 mb4"> <div class="col-md-6"><t t-esc="o.name" /></div> <div class="col-md-6"> <t t-if="o.birthdate" t-esc="o.birthdate" /> <t t-if="not o.birthdate">-</t> </div> </div> </div> </t> </t> </template>
<report id="report_res_partner_birthdays" name="ch08.qweb_res_partner_birthdays" model="res.partner" string="Birthdays" report_type="qweb-pdf" />
Now when opening a partner form or selecting partners in the list view, you should be offered to print the birthday list.
Instead of using the record
syntax as we did earlier, we use the template
element here. This is entirely for convenience; QWeb views are just views as all the others. The reason to use this element is that the arch
field of QWeb views has to follow quite strict rules and the template
element takes care to generate an arch
content which fulfills these rules.
Don't worry about the syntax within the template
element now. This topic will be addressed extensively in the recipe QWeb in Chapter 14, CMS Website Development.
The report
element is another shortcut for an action of type ir.actions.report.xml
and a glue record of type ir.value
. The crucial part here is that you set the name
field to the complete XML ID of the view you defined, otherwise the report generation will fail. The model
attribute determines on which type of record the report operates, and the string
attribute is the name shown to the user in the print menu.
By setting report_type
to qweb-pdf
, we request that the HTML generated by our view is run through wkhtmltopdf
in order to deliver a PDF to the user. There are a couple of other (mostly deprecated) choices, but in some cases, qweb-html
can be convenient to just render the HTML within the browser.
There are some marker classes in a report's HTML that are crucial for the layout. Be sure to wrap all your content in an element with the class page
set. If you forget that, you'll see nothing at all. To add a header or footer to your record, use the class header
or footer
.
Also remember that this is HTML, so make use of CSS attributes such as page-break-before
, page-break-after
, and page-break-inside
.
You'll have noticed that all of our template body is wrapped in two elements with the t-call
attribute set. We'll examine the mechanics of this attribute later, but it is crucial that you do the same in your reports. These elements take care that the HTML generated links to all the necessary CSS files and contains some other data needed for the report generation. While html_container
doesn't really have an alternative, the second t-call
could also be report.external_layout
. The difference is that the external layout already comes with a header and footer displaying the company logo, the company's name, and some other information you expect from a company's external communication, while the internal layout just gives you a header with pagination, the print date, and the company's name. For the sake of consistency, always use one of the two.
Note that report.internal_layout
, report.external_layout
, report.external_layout_header
, and report.external_layout_footer
(the last two are called by the external layout) are just views by themselves, and you already know how to change them by inheritance. To inherit with the template element, use the attribute inherit_id
.