Enable Dark Mode!
overview-of-inheriting-reports-in-odoo-19.jpg
By: Sruthi M

Overview of Inheriting Reports in Odoo 19

Technical Odoo 19 Odoo Enterprises Odoo Community

Odoo's reporting engine is powered by QWeb, the same XML-based template system that drives its web views. And just like views, reports can be inherited: you can extend or modify them from a custom module without ever editing core code. This is essential for keeping your customizations upgrade-safe.

In this post, we'll walk through exactly how report inheritance works in Odoo 19, from the basics to practical real-world patterns.

Every printable report in Odoo is made up of two parts:

  • An ir.actions.report record â€“ defines the report name, model, paper format, and which template to render.
  • A QWeb template (an ir.ui.view of type qweb) – the actual HTML/XML layout rendered into PDF.

To inherit a report, you target the QWeb template, not the action record. You do this exactly the way you'd inherit a form or list view using inherit_id.

The Basic Inheritance Pattern

Step 1 – Find the template to inherit

First, identify the external ID of the report template you want to extend. For example, Odoo's standard invoice report template is: account.report_invoice_document

You can find this by enabling developer mode and inspecting the report under Settings > Technical > Reports, or by searching the source XML in the relevant Odoo module.

Step 2 – Create the inherited view in XML

<odoo>
  <template id="custom_invoice_report"
            inherit_id="account.report_invoice_document">
    <!-- XPath to target a specific node -->
    <xpath expr="//div[@class='page']" position="inside">
      <div class="row">
        <div class="col-12">
          <p>Custom note: <t t-esc="o.custom_field_id.name"/></p>
        </div>
      </div>
    </xpath>
  </template>
</odoo>

Use your module's name as a prefix for your template id to avoid conflicts â€“ e.g., my_module.custom_invoice_report.

XPath Position Attributes

The position attribute on your <xpath> node controls how your content is inserted relative to the matched node:

  • inside – appends your content as the last child inside the matched element.
  • before – inserts your content immediately before the matched element.
  • after – inserts your content immediately after the matched element.
  • replace – completely replaces the matched element with your content.
  • attributes – modifies attribute values on the matched element (useful for adding CSS classes).

Example – adding a class attribute

<xpath expr="//table[@class='table table-sm']"
        position="attributes">
  <attribute name="class">table table-sm table-bordered</attribute>
</xpath>

Adding a Custom Field to the Sale Order Report

Say you've added a field delivery_notes to sale.order and want it to appear on the printed order. Here's the full inheritance:

<odoo>
  <template id="sale_order_custom_notes"
            inherit_id="sale.report_saleorder_document">
    <!-- Insert after the order information table -->
    <xpath expr="//p[@name='payment_term']" position="after">
      <t t-if="doc.delivery_notes">
        <div class="row mt-3">
          <div class="col-12">
            <strong>Delivery Notes:</strong>
            <p><t t-esc="doc.delivery_notes"/></p>
          </div>
        </div>
      </t>
    </xpath>
  </template>
</odoo>

Notice the t-if guard – it's always good practice to hide sections when the field is empty, keeping your printed output clean.

Inheriting Sub-Templates (t-call)

Many Odoo reports are composed of multiple sub-templates called with <t t-call="..."/>. For example, the invoice report calls a shared address block, a lines table, and a tax summary all separate named templates.

You can inherit any of those sub-templates directly by using their external ID as your inherit_id. This is far more surgical than inheriting the top-level document template.

<!-- Inheriting the invoice tax totals sub-template -->
<template id="custom_invoice_tax_totals"
          inherit_id="account.document_tax_totals">
  <xpath expr="//t[@t-foreach]" position="after">
    <tr>
      <td colspan="2">
        <em>All prices include applicable duties.</em>
      </td>
    </tr>
  </xpath>
</template>

Odoo 19 continues to support the report.layout mechanism for global styling – inherit from web.report_layout only if you're making layout-wide changes like header/footer branding across all reports.

Don't forget to declare your XML file in __manifest__.py:

'data': [
    'views/report_templates.xml',
],

Reports go under data, not assets. If you need custom CSS for a report, that goes under assets separately but the template XML itself is always in data.

Report inheritance in Odoo 19 follows the same clean pattern as view inheritance find the template ID, write an XPath, and declare your position. The payoff is significant: your customizations stay isolated in your own module, making upgrades and maintenance far easier than copy-pasting core templates.

Whether you're adding a custom field, tweaking the layout, or inserting conditional blocks, XPath-based inheritance gives you precise control without the risks of direct modification.

To read more about Overview of Different Types of Inheritance in Odoo 19, refer to our blog Overview of Different Types of Inheritance in Odoo 19.


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



0
Comments



Leave a comment



Recent Posts

whatsapp_icon
location

Calicut

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

location

Kochi

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

location

Bangalore

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

Send Us A Message