Skip to content
Integration · Odoo 17, 18 and 19

Print Odoo invoices, quotations and any record with a pdfs.build template

A free, open-source Odoo module that renders your documents through pdfs.build instead of QWeb and wkhtmltopdf. Design the layout in the pdfs.build editor, map it to an Odoo model once, and every print path in Odoo picks it up: the Print menu, email attachments, the customer portal and batch prints.

Get it on Odoo Apps Source on GitHub LGPL-3 · Community and Enterprise · Odoo.sh or self-hosted

Three steps from install to Print menu

01

Install and connect

Install pdfs.build PDF Templates from Odoo Apps or GitHub. In Settings, paste an API key and your organization ID, then click Test Connection.

02

Sync your templates

Sync Templates pulls every published template with its fields and sample data. Archive the ones that should not appear in Odoo; they stay archived on later syncs.

03

Map a model, then print

Pick the Odoo model. A design built for Odoo maps itself; any other template gets a prefilled expression to finish. The report appears in the Print menu, in emails and on the portal.

What it looks like inside Odoo

The module adds a pdfs.build app with Templates, Reports and Settings. Reports are ordinary Odoo report actions, so everything that already prints a report keeps working.

Odoo report form showing the Python data expression that maps an invoice to the template's fields, next to the Template Fields tab
The data expression is prefilled from the template's schema, one entry per field.
A rendered invoice PDF open in a dialog inside Odoo, generated by pdfs.build from a real invoice record
Preview PDF renders a real record and opens it inside Odoo before anything is printed.
Odoo dialog listing existing PDF reports, with the customer invoice report selected to be replaced by a pdfs.build template
Use for Existing Report replaces a stock Odoo PDF without touching its QWeb view.
The Print menu of an Odoo invoice with the pdfs.build report listed next to the standard options
Once mapped, the report is just another entry in the Print menu.

One Python expression per report

A report maps one Odoo model to one template with a Python expression that returns the template's data. Odoo prefills it from the template's JSON Schema, and the Template Fields and Odoo Fields tabs list both sides so the mapping is a matter of filling in the blanks.

Report on sale.order · Data expression evaluated per printed record
{
    "quoteNumber": record.name,
    "issueDate": format_date(record.date_order),
    "clientName": record.partner_id.commercial_partner_id.name,
    "clientEmail": record.partner_id.email,
    "items": [
        {"name": line.product_id.name, "description": line.name, "amount": line.price_subtotal}
        for line in record.order_line
        if not line.display_type
    ],
    "total": record.amount_total,
    "notes": html2plaintext(record.note or ""),
    "logo": image(record.company_id.logo),
}

Helpers such as format_date, format_amount, image and html2plaintext are available, and empty Odoo fields are coerced to the type the schema expects. Preview Data shows the resulting JSON for a chosen record before you print.

Built for the way Odoo prints

  • Replace stock reports in place

    Take over the customer invoice, the quotation, delivery slips or any other QWeb PDF report. The report keeps its name, its place in the Print menu and its email templates.

  • Odoo's post-processing still runs

    The module replaces only the rendering step. Attachments, Factur-X and UBL embedding, quote-builder pages and multi-record merging are still done by Odoo.

  • Preview before you print

    Preview Sample PDF renders the template's own sample data; Preview PDF renders a real record. Both open in a viewer inside Odoo.

  • Versioned templates

    Reports follow the latest published version by default, or pin a version number or a channel such as staging. A pinned report keeps the schema it was pinned to.

  • Choose what Odoo sees

    Only published templates are synced, and archived ones stay hidden. Large organizations expose a handful of templates to Odoo and keep the rest where they are.

  • Typeset, not screenshotted

    Documents are compiled by Typst: repeating table headers, correct page breaks and consistent fonts, without wkhtmltopdf. See why not a headless browser.

Designs that map themselves

These templates take Odoo's own field names, so the module writes the data expression for you. Inside Odoo, Designs for Odoo lists them with previews and adds one in a click: copied into your organization, synced, and its report created on the right model. Your company's logo and document-layout colours come through from Odoo's settings. Two designs per document, one quiet and one with more presence.

Midline — Odoo quotation template, Minimal, type-led layout, rendered from live data

Minimal, type-led · Ink & magenta · Merriweather + Open Sans

conservative A4 portrait 1 page
See the full document Use this template

Odoo purchase order

Compare the two designs

Odoo delivery slip

Compare the two designs

Requirements

Odoo 17.0, 18.0 or 19.0 on Odoo.sh or self-hosted. Odoo Online cannot install third-party modules.
pdfs.build plan Starter or higher; see pricing.
Credentials An API key (Settings → API Keys) and your organization ID, both entered once in Odoo's Settings.
Python The requests package, which ships with every Odoo installation.
License LGPL-3, source on GitHub. One branch per Odoo version, each tested against the official image.

Frequently asked questions

Do I have to write the data expression by hand?

Not for the designs built for Odoo. Their fields are named after Odoo's own (partner_id, invoice_line_ids, amount_total, tax_totals), so the module writes the whole expression itself. Designs for Odoo, in the module, adds one of them in a click with its report already created; only a field Odoo does not have is ever left for you. Any other template, including your own, is mapped with one Python expression that the module prefills from the template's schema.

Which Odoo versions does the module support?

Odoo 17.0, 18.0 and 19.0, Community and Enterprise. Each version has its own branch on the Odoo Apps listing and on GitHub, and every branch runs the same test suite against the official Odoo image.

Does it work on Odoo Online (odoo.com SaaS)?

No. Odoo Online cannot install third-party modules. You need Odoo.sh or a self-hosted Odoo, which is where custom modules are installed anyway.

What does it cost?

The module is free and open source (LGPL-3). Rendering goes through the pdfs.build API, which needs a Starter plan or higher; each printed document counts as one API render against your monthly quota.

Which data leaves my Odoo server?

Only the JSON your data expression builds for the printed record, sent to api.pdfs.build with your API key. Nothing else is read from your database, and the generated PDF is stored by Odoo exactly as a QWeb report would be.

Can I replace Odoo's own invoice or quotation PDF?

Yes. Open a synced template and choose Use for Existing Report, then pick the stock report, for example the customer invoice or the sales quotation. From then on the Print menu, email attachments, the customer portal and every other place Odoo prints that report use your pdfs.build template. Odoo's post-processing, such as Factur-X or UBL embedding, still runs on the result.

What happens when I change the template on pdfs.build?

A report follows the template's latest published version by default. If a change adds a field, Odoo refreshes the field list on the next sync so the data expression can be updated. You can also pin a report to a fixed version number, or to a channel such as staging, with the report's Version field.

How do I print several records at once?

Select them in a list and print as usual. Each record is rendered on its own and the PDFs are merged into one file, the same way Odoo merges QWeb reports.

The step-by-step walkthrough, including replacing the stock invoice, is in the blog post Print Odoo invoices and quotations with a pdfs.build template.

Your Odoo documents, designed properly

Start from an invoice or quotation in the template gallery, publish it, and map it to Odoo in an afternoon.