| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Lines of code | 608 |
| Technical Name |
nz_dynamic_report |
| License | LGPL-3 |
| Website | https://www.nezam.co |
| Versions | 17.0 18.0 19.0 |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Lines of code | 608 |
| Technical Name |
nz_dynamic_report |
| License | LGPL-3 |
| Website | https://www.nezam.co |
| Versions | 17.0 18.0 19.0 |
NZ Solutions Apps for Odoo
Dynamic Report Templates & PDF Layouts - Odoo 19
Design and print professional PDF reports directly from Odoo — without touching any XML or Python file. Pick any model, build field placeholders visually, write your HTML template, choose a layout and paper format, and generate pixel-perfect PDFs with one click.
What does this module provide?
This module lets you create fully custom PDF reports for any Odoo model — all from within the Odoo interface, with no developer files required. Define a report name, pick your target model, choose a report layout (Basic, External, or HTML Container) and a paper format, then write free-form HTML using {{field_name}} placeholders. The visual Field Placeholder Builder lets you navigate relational fields up to 5 levels deep and automatically generates the correct placeholder expression. Repeating sections (order lines, attendees, etc.) are handled with {{#each field}}...{{/each}} loops. A Variables panel keeps all your registered placeholders in one list with one-click append. Saving a report automatically creates a Server Action bound to the target model, so the report appears instantly in the model's Print menu. A live rendered preview shows the template populated with real record data before printing.
KEY HIGHLIGHTS
Visual Field Placeholder Builder
Browse the fields of your target model — including relational fields up to 5 levels deep — and generate the correct {{placeholder}} expression automatically. No coding required.
{{#each}} Loop Support
Repeat template blocks over One2many / Many2many fields (e.g. order lines, attendees) using {{#each lines}}...{{/each}}. The builder generates loop-start and loop-end tags with one click.
3 Built-in Report Layouts
Choose from web.html_container (minimal wrapper), web.basic_layout (header & footer), or web.external_layout (company-branded letterhead) per report.
Custom Paper Format per Report
Assign any Odoo paper format (A4, Letter, custom size) to each report independently. The PDF engine picks it up automatically at print time.
Auto-created Server Action
Saving a report template automatically creates (or updates) a bound Server Action, so the report appears immediately in the Print menu of the target model — no manual action wiring needed.
Live Rendered Preview
The Rendered Content field shows the template populated with real record data in real time, so you can verify the output before printing any PDF.
1) Reports List View
The main list of all defined Custom Server HTML Reports. Each row shows the report Name, the Target Model it is bound to, the generated Server Action, and whether the report is Active. From here you can create a new report or open an existing one.

2) Report Form — General Settings
The report form showing the main configuration fields: Name, Target Model (model the report is linked to), Report Layout (web.html_container / web.basic_layout / web.external_layout), Paper Format, and the auto-generated Server Action reference. The Create/Update Server Action button in the header re-syncs the action whenever needed.

3) Report Layout Selection Dropdown
The Report Layout dropdown showing the three available layout options: web.html_container (minimal HTML wrapper — full control over the page), web.basic_layout (adds a standard Odoo header and footer), and web.external_layout (uses the company-branded external letterhead with logo and address).

4) Paper Format Selection
The Paper Format field dropdown listing all available paper formats defined in Odoo (A4, US Letter, custom sizes, etc.). Each report can use a different paper format. If left empty, the system default format is used. The selection is passed directly to the wkhtmltopdf PDF engine at print time.

5) Field Placeholder Builder — Picking the First Field
The Field Placeholder Builder panel. The Field 1 selector is open showing all stored fields of the target model. Selecting a field populates Field 1 and the Placeholder field below automatically shows the correct {{field_name}} expression. If the selected field is relational (Many2one / One2many / Many2many), Field 2 appears for deeper traversal.

6) Deep Relational Field Traversal (Multi-level Chain)
After picking a Many2one field in Field 1, the Field 2 selector appears and is filtered to show only the fields of the related model. The chain can extend up to 5 levels (Field 1 → Field 2 → … → Field 5). The Placeholder field updates in real time, e.g. {{partner_id.country_id.name}}, ready to copy into the HTML template.

7) Loop Mode — Generating {{#each}} Placeholders
Activating Loop Mode and selecting a One2many / Many2many field (e.g. order_line) switches the placeholder to an {{#each order_line}} expression. The Append Loop Start and Append Loop End buttons appear, inserting the opening and closing loop tags directly into the HTML template. Sub-fields inside the loop use {{.field_name}} syntax.

8) Variables Panel — Registered Placeholders
The Variables List shows all placeholders that have been added via Add To Variables. Each row displays the Field Label (human-readable), the Path (dotted field chain), and the Placeholder expression. Clicking the Append button on any row inserts that placeholder at the cursor position in the HTML template — no need to retype it.

9) HTML Template Editor
The Template tab contains a full rich-text HTML editor (widget=html). The editor shows a sample report template with {{name}}, {{partner_id.name}}, and a loop block rendering order lines. You can type raw HTML, paste content from an external editor, or append placeholders directly from the Variables panel above.

10) Live Rendered Content Preview
The Rendered Content computed field shows the template populated with real data from the currently viewed record. Placeholders like {{name}} are replaced with the actual field values, and loop blocks are expanded into their full rows — giving you an accurate preview of what the PDF will look like before printing.


11) Auto-Generated Server Action
When a report is saved, the system automatically creates an ir.actions.server record bound to the target model with Binding Type = Report. The Server Action field on the form becomes a clickable link to the generated action. No manual wiring is needed — the report is immediately available in the model's Print menu.

12) Report in the Model's Print Menu
Opening a record of the target model (e.g. a Sale Order) and clicking the Print dropdown now shows the custom report by name. Clicking it triggers the PDF generation flow, passing the selected record IDs and the report configuration to the rendering engine.

13) PDF Output — web.basic_layout
The generated PDF using web.basic_layout: the standard Odoo header (company name, date, page number) and footer are added automatically around the custom HTML content. Field values like the order number, customer name, and order lines are fully rendered with the correct data from the record.

14) PDF Output — web.external_layout (Letterhead)
The same report rendered with web.external_layout: the company letterhead is applied with the company logo, address, and contact details. The custom HTML body sits inside the branded frame — ideal for customer-facing documents like offers, delivery notes, or certificates.

15) Multi-record PDF — Page Break Between Records
When multiple records are selected from the list view and the Print action is triggered, each record is rendered as a separate page. A page-break-after: always CSS rule is injected automatically between pages, so every record starts on its own clean page in the merged PDF.

16) Image Rendering in PDF — URL Resolution
Images embedded in the HTML template (relative URLs like /web/image/...) are automatically converted to absolute URLs before being passed to wkhtmltopdf, ensuring they render correctly in the PDF. The module also handles loading="lazy" images by switching them to eager loading and fixes padding-to-margin translation for precise image positioning.

17) Report with {{#each}} Loop — Order Lines Table
A report template that uses the {{#each order_line}} loop to generate a full order-lines table. Each row renders sub-fields like {{.product_id}}, {{.product_uom_qty}}, and {{.price_unit}} using the dot-prefixed syntax. The loop is closed with {{/each}}. In the PDF, every line of the order appears as a separate table row.

18) Custom Report Applied to Any Model
Because the Target Model is fully configurable, the same module works for any Odoo model — Sale Orders, Purchase Orders, Invoices, Employees, Projects, custom models, and more. Each report is independently configured with its own layout, paper format, and HTML template, giving complete flexibility across all business documents.

{{placeholder}} expressions without writing any code.{{partner_id.country_id.name}}, automatically validated by the picker.{{.sub_field}} dot notation inside the loop.--encoding utf-8 to prevent character rendering issues in Arabic, French, or other non-ASCII content.Do I need to write Python or XML to create a report?
No. Everything is configured inside Odoo — you pick the model, build placeholders with the visual field picker, write the HTML template in the editor, and save. The module automatically creates all the required Odoo records (report action, server action) behind the scenes.
Which models can I target?
Any model available in Odoo — both standard models (Sale Order, Purchase Order, Invoice, Employee, Project, etc.) and your own custom models. The Target Model field is a standard Many2one on ir.model, so every installed model is selectable.
How do I print a report from a record?
Open any record of the target model, click the Print (⊞) dropdown button in the action bar, and select your report by name. To print multiple records at once, select them in the list view and use the same Print menu — each record becomes a separate page in the PDF.
How do I render a list of related records (e.g. order lines)?
Enable Loop Mode in the Field Placeholder Builder and select the One2many or Many2many field (e.g. order_line). Click Append Loop Start to insert {{#each order_line}}, then add sub-field placeholders using {{.product_id}}, {{.price_unit}}, etc., and finally click Append Loop End to close the block with {{/each}}.
Can I navigate to a field that is 3 or 4 levels deep?
Yes. The Field Placeholder Builder supports up to 5 levels of relational traversal. Each time you pick a Many2one field, the next field selector appears, filtered to the related model. The Placeholder field shows the full chain (e.g. {{sale_id.partner_id.country_id.name}}) as you build it.
What happens if a placeholder references an empty field?
The rendering engine resolves the expression step by step. If any segment in the chain is falsy or empty, it returns an empty string and continues rendering the rest of the template. No error is raised — the placeholder is simply replaced with nothing.
Can I use custom CSS and images in the template?
Yes. The template editor accepts any valid HTML including inline <style> blocks, external CSS classes, and images. Relative image URLs (like /web/image/product.product/1/image_1920) are automatically resolved to absolute URLs before PDF generation so images render correctly.
What happens when I rename or delete a report?
Renaming a report automatically updates the bound server action name. Deleting a report cascades the deletion to its server action, cleanly removing the entry from the model's Print menu with no orphaned records left behind.
Which Odoo editions and deployment modes are supported?
The module is compatible with Odoo 19 Community and Enterprise on On-Premise, Odoo Online, and Odoo.sh deployments. It depends only on base and web, so it has minimal dependencies.
Version 19.0.1.0.0
Initial Release- Custom HTML report templates for any Odoo model
- Visual Field Placeholder Builder with up to 5-level relational traversal
- {{#each}} / {{/each}} loop support for One2many and Many2many fields
- Variables panel with one-click Append to template
- 3 report layouts: web.html_container, web.basic_layout, web.external_layout
- Custom paper format selection per report
- Auto-creation and auto-update of bound ir.actions.server (Print menu integration)
- Live rendered content preview field with real record data
- Multi-record PDF generation with automatic page breaks
- Absolute URL resolution for images and lazy-load fix for wkhtmltopdf
- UTF-8 encoding flag automatically added to wkhtmltopdf arguments
- Cascade deletion of server action when report is deleted
- Unique report name constraint to prevent duplicate server actions
Please log in to comment on this module