# Odoo XML-RPC BOM Export Python Script Generator

> Source: https://netray.co/tools/odoo-xmlrpc-bom-export-python-generator
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Fill in your Odoo URL, database and filters to get a ready Python script that exports BOMs and component lines to a CSV file.

## Category

developer

## Erp

Odoo

## Industry

Discrete Manufacturing

## Audience

- ERP developer
- ERP consultant
- Data analyst

## Tool

**Kind:** template

**Output:** code

**Language:** python

**Fields:**

#### Odoo URL

**Key:** url

**Type:** text

**Default:** https://mycompany.odoo.com

#### Database name

**Key:** db

**Type:** text

**Default:** mycompany

#### Login (email)

**Key:** user

**Type:** text

**Default:** api.user@example.com

#### BOM type

**Key:** bom_type

**Type:** select

**Options:**

- normal
- phantom

**Default:** normal

#### Max BOMs to export

**Key:** limit

**Type:** number

**Default:** 500

#### Output file

**Key:** outfile

**Type:** text

**Default:** odoo_bom_export.csv

**Blocks:**

#### Python script

**Body:** import csv
import getpass
import xmlrpc.client

URL = '{{url}}'
DB = '{{db}}'
USER = '{{user}}'
API_KEY = getpass.getpass('Odoo API key: ')

common = xmlrpc.client.ServerProxy(URL + '/xmlrpc/2/common')
uid = common.authenticate(DB, USER, API_KEY, {})
if not uid:
    raise SystemExit('Authentication failed: check database, login and API key')

models = xmlrpc.client.ServerProxy(URL + '/xmlrpc/2/object')

boms = models.execute_kw(
    DB, uid, API_KEY, 'mrp.bom', 'search_read',
    [[['type', '=', '{{bom_type}}']]],
    {'fields': ['id', 'product_tmpl_id', 'product_qty', 'type', 'bom_line_ids'], 'limit': {{limit}}}
)

line_ids = [lid for b in boms for lid in b['bom_line_ids']]
lines = models.execute_kw(
    DB, uid, API_KEY, 'mrp.bom.line', 'read',
    [line_ids],
    {'fields': ['bom_id', 'product_id', 'product_qty', 'product_uom_id']}
)
lines_by_bom = {}
for ln in lines:
    lines_by_bom.setdefault(ln['bom_id'][0], []).append(ln)

with open('{{outfile}}', 'w', newline='', encoding='utf-8') as f:
    w = csv.writer(f)
    w.writerow(['bom_id', 'parent_item', 'parent_qty', 'component', 'component_qty', 'uom'])
    for b in boms:
        for ln in lines_by_bom.get(b['id'], []):
            w.writerow([b['id'], b['product_tmpl_id'][1], b['product_qty'], ln['product_id'][1], ln['product_qty'], ln['product_uom_id'][1]])

print('Exported', len(boms), 'BOMs and', len(lines), 'lines to {{outfile}}')

**Notes:** Create an API key in your Odoo user preferences under Account Security and use it in place of the password. Field names such as product_uom_id are correct for current Odoo versions; verify them with fields_get on older releases. Odoo Online and Odoo.sh allow the external API, but limits may apply to bulk calls.

## Content

**Intro:** Getting a clean BOM list out of Odoo for costing, a migration or an audit is a common job. This generator writes a Python script that logs in over the external XML-RPC API, reads mrp.bom and mrp.bom.line, and saves a flat CSV you can open in Excel.

**Sections:**

#### How to use the script

**Body:** Fill in your Odoo URL, database name and login. Pick the BOM type and a row limit, then copy the script into a file and run it with Python 3. The script asks for your API key at run time rather than storing it. The result is one CSV row per component, with the parent item, parent quantity, component, component quantity and unit of measure.

**Bullets:**

- Generate an API key in your user preferences
- Run it against a test database first
- Raise the limit or add a domain to filter by product
- Open the CSV in Excel and pivot by parent item

#### What the calls do

**Body:** The common endpoint authenticates and returns a user id. The object endpoint runs execute_kw with a model, a method and a domain. search_read returns BOM headers with the ids of their lines; a second read call fetches the lines in bulk, which avoids one request per BOM. Many2one fields come back as a pair of id and display name, which is why the script indexes by position.

#### Extending it

**Body:** Add a domain such as product_tmpl_id.categ_id to filter by category, or read mrp.routing.workcenter to export operations and times. For large databases, page through results with offset and limit instead of one big call. If you need multi-level explosion, build it in Python by recursing on components that have their own BOM, with a guard against cycles.

#### Common mistakes

**Body:** Using the account password instead of an API key, which fails when two factor authentication is on. Forgetting that BOMs can be company specific, so a user in the wrong company sees fewer records. Reading phantom BOMs as real assemblies. Assuming variants are exported; the BOM header points to the template, so variant-specific lines need the apply on variants field.

**Cta:** If you want BOM and stock questions answered directly from your ERP without scripts, Netray builds read-only natural-language access that runs on your own servers.

**Faq:**

#### Does this write anything to Odoo?

**Answer:** No. The script only calls authenticate, search_read and read, which are read operations. It writes a CSV on your own computer. Still, run it with a user that has read-only access to manufacturing data, so a later edit to the script cannot change records by accident.

#### Why use an API key rather than a password?

**Answer:** API keys can be revoked individually, do not break when two factor authentication is enabled, and keep your real password out of scripts. In Odoo they are created under your user preferences, Account Security. Use a dedicated integration user with minimal access rights.

#### Will it work with Odoo 17 and 18?

**Answer:** The XML-RPC endpoints and the mrp.bom fields used here exist across recent versions. Newer releases add a JSON-2 external API, but the XML-RPC calls continue to work in current releases at the time of writing. Check Odoo's external API documentation for deprecation notices before building anything long-lived.

#### How do I export multi-level BOMs?

**Answer:** This script exports one level per BOM. To explode levels, loop over components and look up each component's own BOM by product template, repeating until you reach purchased parts. Add a visited set to stop circular references, and apply quantities by multiplying down the tree.

## Search terms

odoo export bom python, odoo xmlrpc example, odoo external api bom, odoo search_read mrp.bom, export odoo bill of materials csv, odoo execute_kw python, odoo api authenticate python, odoo bom lines export script

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
