Overview
In this guide, you’ll learn how to design payroll and HR reports for Odoo using Py3o with LibreOffice Writer. By following this approach, functional users can easily create report layouts in LibreOffice, while developers can integrate them into Odoo via XML—no UI upload required. This streamlines the creation of payslips, EOSB, and bonus reports while preserving full formatting control.
Goals of This Tutorial
By the end of this tutorial, you will learn how to:
- Design payslip, EOSB, and bonus reports in LibreOffice Writer.
- Insert dynamic fields and control structures (for loops, if conditions) inside the template.
- Bind the template to Odoo via an ir.actions.report record using Py3o.
Prerequisites
- OCA report_py3o module available in the addons path and installed in your database.
- LibreOffice Writer installed for template creation and editing.
Creating a LibreOffice Template
Follow these steps to design the layout, insert dynamic fields, and add loops and conditionals for Py3o reporting in Odoo.
1. Create a LibreOffice Template
- Open LibreOffice Writer and create a new text document.
- Save it as payslip_py3o.odt inside your custom Odoo module folder.
This template will serve as the base layout for your payroll or HR reports.
2. Insert Fields (Variables/Expressions)
Use User Fields to insert dynamic content.
- Press Ctrl+F2, select “Variables” > “User Field.”
- Set the Name to match the dataset field (the Value can be left empty; it is resolved at render time).
Example fields:
- Name: object.employee_id.name
- Name: object.number
- Name: object.date_from / object.date_to
Place these fields wherever the data should appear in the document.
3. Add Loops for Payslip Lines, Worked Days, and Inputs
Py3o allows loops to be added using Hyperlinks or Input Fields. A common pattern in payslips includes:
Loop Header (first cell of table row)
- Select the first cell of the table row.
- Go to Insert > Hyperlink, choose Type: Web.
- Set Target/URL to:
py3o:// for line in object.line_ids
Inside row cells
Insert User Fields such as:
- Line.salary_rule_id.name
- line.total
Loop Footer (next row after repeated block)
Insert a Hyperlink with Target/URL:
py3o:// endfor
Repeat the same pattern for other collections, such as:
object.worked_days_line_ids or object.input_line_ids.
4. Conditional Sections (if/endif)
Wrap optional sections with if / endif controls using Hyperlinks:
Start condition:
py3o:// if object.contract_id
End condition:
py3o:// endif
This allows certain sections of the report to appear only when specific conditions are met.
5. Formatting and Totals
- Use Writer styles for headers, tables, page breaks, footers, and logos. Py3o preserves all formatting applied in LibreOffice.
- Totals can be standard fields (e.g., object.amount, object.credit_note) or computed in the template using simple expressions (e.g., show a grand total row below the loop).
Binding Template via XML in Odoo
Define an ir.actions.report record for each report. Below is a ready-to-adapt snippet for payslips:
This binds the template to Odoo, generating PDFs with dynamic data from your payslip records.
Wrapping Up
You’ve now created a fully functional payroll or HR report using LibreOffice and Py3o in Odoo. This method gives functional users control over the layout while keeping developers in charge of data integration.