Enable Dark Mode!
By: Hajaj Roshan

How to Create a PDF Report in Odoo 14?

Odoo 14

ERP software contains a lot of modules to perform various operations to run a business workflow smoothly. However every organization wants to know their progress, and they have to present the growth in front of the boards or authorities, this is where the reports come in handy. Odoo one of the best ERP solutions available today is one of the business management solutions used by 5 million people all across the world. Moreover, Odoo provides various report projections like PDF, Graphical presentation, Pivot table, etc.
This blog will provide insight on how we can create a custom PDF Report in Odoo 14.

What is Qweb?

Odoo uses Qweb as a templating engine which is used for converting XML to HTML. Moreover, Qweb properties are set as XML attributes that start with ‘t-‘ (example: t-if for checking conditions in an XML file). Furthermore, we use Qweb for defining the report templates that are written in HTML format, the same as creating a web page.

What is the Use of Wkhtmltopdf?

Wkhtmltopdf is used to render PDFs from the Qweb templates. Additionally, the templates are defined in HTML format as we discussed in the above section therefore, wkhtmltopdf will render the PDF report from the Qweb.

How do Qweb Reports work in Odoo?

The reports are working with Report Actions and Report Templates. Additionally, the report templates are used in report actions. Moreover, a report action is triggered while printing a report that you can either call this report action from the Print menu or from a python function. In addition, you can set up a custom page format as per the need in Odoo that will be specified in the report action.
Report Actions (ir.actions.report)
Odoo has several types of actions to perform different kinds of operations or processes such as the reports are generated when the report action is triggered. Furthermore, the report action will be recognized by model ‘ir.actions.report’ used in the record. Moreover, up to Odoo 13 report actions are defined using the <report> tag however in Odoo 14 we use the <record> tag instead of the <report> tag.
Create an XML file inside the reports directory and don’t forget to add this file to the manifest. The following is an example of how to define report action:
<record id="action_student_id_card" model="ir.actions.report">
   <field name="name">Student ID Card</field>
   <field name="model">education.student</field>
   <field name="report_type">qweb-pdf</field>
   <field name="report_name">education.report_student_id_card</field>
   <field name="report_file">education.report_student_id_card</field>
   <field name="print_report_name">'Student Card - %s' % (object.name)</field>
   <field name="binding_model_id" ref="model_education_student"/>
name: Name field is mandatory and is used to recognize the report.
model: Model is also a mandatory field and it stores the model name where the data are taken from.
report_type: It has 2 values qweb-pdf and qweb-html. Of which the qweb-pdf will generate a pdf report and the qweb-html will load the reports in web pages. Furthermore, the default value of report_type is qweb-pdf
report_name: It defines the external_id of the report template and is a mandatory field. Eg: module_name.template_id. 
print_report_name: You can use python expressions to generate report file names and it's not considered mandatory.
binding_model_id: If you want to print the report using the Print Action button inside a view, then you can bind the action with the corresponding model. Moreover, the value inside ref should be the following syntax: if the model is sale.order then ‘model_sale_order’. Furthermore, if you are trying to print it from other places like a wizard or any other buttons you don’t need to specify the binding_model_id
paperformat_id: If you have a specific paper format for the report place the exernal_id here. Here, is an example of the same: <field name="paperformat_id" ref="module_name.paperformat_id"/>. Moreover, if it is not specified, take the default paper format the company will use.

How to Define Report Template?
Templates are designed in an HTML format. The structure will be written inside of <template> tags. We can use other templates inside our template using t-call property.
You can create an xml file inside the report directory and down below is the simplest example of a minimal template in Odoo:
<template id="report_student_id_card">
    <t t-call="web.html_container">
        <t t-foreach="docs" t-as="o">
            <t t-call="web.external_layout">
                <div class="page">
                    <h2>Report title</h2>
                    <p>This object's name is <span t-field="o.name"/></p>
In the above example, the id “report_student_id_card” needs to be provided inside the report action.  In addition, “docs“ contains the records from the model given in the report action. Moreover, if you print the report from the form view using the Print action button, the docs will contain a single record. On the contrary, if you are selecting multiple records from the list view the docs will contain all those selected records. Therefore, here we put the docs into a loop to get each record in ‘o’. Furthermore, if you are generating reports from a wizard or any other buttons you can pass the records inside report_action() function.
Additionally, t-call="web.external_layout" is used to add the default header and footer to your report. Moreover, if you want to use a customized header and footer you can create a template for it, and set the external id for t-call. 
How to Print PDF Report from Wizard or Button?
The default report will generate reports using values from the model provided in the report action. However in certain situations, we have to take values from different models or we need to get some values from the user, in such cases, we have to generate reports using wizards or any other methods. As we mentioned before we have to trigger the report actions to render the report therefore, the print button inside the wizard or form should call the report action. Let’s look at an example.
def print_report(self):
   data = {
   'from_date': self.from_date,
   'to_date': self.to_date
   # docids = self.env['sale.order'].search([]).ids
   return self.env.ref('module_name.action_student_id_card').report_action(None, data=data)
In this example, print_report() function will call from the wizard. You can pass the values into the template using data and it is not compulsory as if you don’t have any values to pass, report_action only needs to pass None or docids. In this snippet, docids are commented. So we don’t need to pass it therefore, the report_action() first parameter is None. On the contrary, if you have docids replace the None with docids. Module_name.action_student_id_card replace with your module name and report action’s id.
Create a python file inside the report directory and don’t forget to add it to the init file.
Now we have to define an Abstract model and define a function _get_report_values(). The model name should be “report.report_name”. Here is an example of the same:
from odoo import api, models
class StudentCard(models.AbstractModel):
    _name = 'report.education.report_student_id_card

    def _get_report_values(self, docids, data=None):
        docs = self.env[model.model].browse(docids)
        return {
              'doc_ids': docids,
              'doc_model': model.model,
              'docs': docs,
              'data': data,
              'get_something': self.get_something,
    def get_something(self):
        return 5
In the above example, you can pass the values to the template in the return statement. In addition, the docs contain the records you have to print in the report. If you are trying to fetch data using a query, the result can be passed to the docs. In the template, you will get the records in docs and you can extract values from data we passed from the wizard. Furthermore, if you call the get_something in the template, it executes the function and gets the return value in the template.
Here is an example of the same: 
<span t-esc=”get_something”/> it will display 5 in the report which is returned in the function get_something.

If you need any assistance in odoo, we are online, please chat with us.


Leave a comment




Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635



Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.



Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message