How to Export Excel Files from Odoo Backend

Generate Custom Excel Reports in Odoo

Odoo’s built-in export tool is fine for simple CSV files, but what about professionally formatted Excel reports with company branding, colours, formulas, and charts?

If you’ve ever needed to generate detailed, polished reports from Odoo, this guide is for you. This guide will show you how to export Odoo data to Excel (XLSX) files programmatically via the backend using Python, with full control over the layout and content.

We’ll cover:

  • Exporting data from any Odoo model
  • Writing XLSX files using xlsxwriter
  • Adding styling, formulas, and charts
  • Making files downloadable via a wizard pop-up

Prerequisites

  • Odoo backend development experience
  • Python 3.x installed
  • xlsxwriter Python library
Install via:

pip install xlsxwriter

Module Structure

Module Name - custom_export_excel/
├── models/
│ └── export_wizard.py
├── views/
│ └── export_wizard_view.xml
├── __manifest__.py

Python Code

Import Required Libraries
import xlsxwriter
import base64
from io import BytesIO
from odoo import models, fields, api

Define the Wizard Model

We use a transient model (wizard) here because the export is a temporary action. It doesn’t need to persist in the database, and it gives the user a quick download interface.

class SaleOrderExportWizard(models.TransientModel):
    _name = 'sale.order.export.wizard'
    _description = 'Export Sales Order to Excel'
    file_data = fields.Binary('Excel File', readonly=True)
    file_name = fields.Char('Filename', readonly=True)

XML View for Wizard

<odoo>
    <record id="view_sale_order_excel_wizard_form" model="ir.ui.view">
        <field name="name">sale.order.export.wizard.form</field>
        <field name="model">sale.order.export.wizard</field>
        <field name="arch" type="xml">
            <form string="Download Excel File">
                <group>
                    <field name="file_name" readonly="1"/>
                    <field name="file_data" filename="file_name"/>
                </group>
                <footer>
                    <button string="Close" class="btn-secondary" special="cancel"/>
                </footer>
            </form>
        </field>
    </record>
    <record id="view_order_form_inherit_export_excel" model="ir.ui.view">
        <field name="name">sale.order.export.wizard</field>
        <field name="model">sale.order</field>
        <field name="inherit_id" ref="sale.view_order_form"/>
        <field name="arch" type="xml">
            <xpath expr="//header" position="inside">
                <button name="action_export_sales_orders"
                        type="object"
                        string="Export Sales Orders"
                        class="btn-primary"
                        icon="fa-download"/>
            </xpath>
        </field>
    </record>
</odoo>

Excel File Generation Method

This method handles the actual Excel file generation. It fetches sales orders, applies formatting, adds totals, and even inserts a visual chart.

class SaleOrder(models.Model):
    _inherit = 'sale.order'
    def action_export_sales_orders(self):
        # Create Excel in memory
        output = BytesIO()
        workbook = xlsxwriter.Workbook(output, {'in_memory': True})
        worksheet = workbook.add_worksheet('Sales Orders')
        title_format = workbook.add_format({
            'bold': True, 'font_color': 'white',
            'bg_color': '#4472C4', 'font_size': 14,
            'align': 'center', 'valign': 'vcenter'
        })
        header_format = workbook.add_format({
            'bold': True, 'bg_color': '#D9E1F2',
            'border': 1, 'align': 'center'
        })
        normal_format = workbook.add_format({'border': 1})
        # Title
        worksheet.merge_range('A1:E1', 'Sales Orders Report', title_format)
        # Column headers
        headers = ['Order', 'Customer', 'Order Date', 'Total', 'Status']
        for col, header in enumerate(headers):
            worksheet.write(1, col, header, header_format)
        # Fetch sale orders
        sale_orders = self.env['sale.order'].search([])
        # Data rows
        row = 2
        amount = 0
        for order in sale_orders:
            worksheet.write(row, 0, order.name, normal_format)
            worksheet.write(row, 1, order.partner_id.name, normal_format)
            worksheet.write(row, 2, str(order.date_order), normal_format)
            worksheet.write(row, 3, order.amount_total, normal_format)
            worksheet.write(row, 4, order.state, normal_format)
            amount += order.amount_total
            row += 1
        # Add total sum formula in footer
        worksheet.write(row, 2, 'Total', header_format)
        worksheet.write(row, 3, str(amount), header_format)
        # Adjust column widths
        worksheet.set_column('A:A', 15)
        worksheet.set_column('B:B', 25)
        worksheet.set_column('C:C', 20)
        worksheet.set_column('D:D', 12)
        worksheet.set_column('E:E', 15)
        chart = workbook.add_chart({'type': 'column'})
        chart.add_series({
            'name': 'Sales Total',
            'categories': f'=Sales Orders!$A$3:$A${row}',
            'values':     f'=Sales Orders!$D$3:$D${row}',
        })
        chart.set_title({'name': 'Sales Total by Order'})
        worksheet.insert_chart('G3', chart)
        workbook.close()
        output.seek(0)
        file_data = base64.b64encode(output.read())
        wizad_id = self.env['sale.order.export.wizard'].create({
            'file_data': file_data,
            'file_name': 'SalesOrders.xlsx'
        })
        return {
            'type': 'ir.actions.act_window',
            'name': 'Download Excel',
            'res_model': 'sale.order.export.wizard',
            'view_mode': 'form',
            'res_id': wizad_id.id,
            'target': 'new'
        }

Wrapping Up

With this setup, you can now generate professional Excel reports from your Odoo backend with just one click. The reports are dynamic and styled, include totals and charts, and can be easily downloaded via a wizard pop-up.

This solution is ideal for generating business reports, financial statements, or stock analysis sheets from Odoo.

Found this article useful?

Explore more development guides and solutions from our team.

Check out more posts
Vijay Elangovan 2 June, 2025
Archive
Sign in to leave a comment
How to Sync Odoo with External Databases Using Python