Fluvo#

PyPI Status Python Version License

Read the documentation at https://fluvo.readthedocs.io/ Tests Codecov

pre-commit Ruff codestyle

Fluvo is the data-migration engine for Odoo implementation partners. When you’re moving a client onto Odoo — from a legacy ERP, a spreadsheet estate, or an older Odoo — Fluvo turns a migration from a one-shot manual load into a repeatable run you can rehearse on UAT, drive from scripts, and trust in production.

It is built around one guarantee that matters on go-live weekend: every source row is accounted for. Nothing is silently dropped, every re-run is safe, and a failed step tells your automation it failed.


Why partners use it for migrations#

  • 🧾 Reconciliation, not hope — every run proves created + failed + unaccounted == total. You leave each import knowing exactly what landed, what didn’t, and why — not guessing from a scrolled-past log.

  • 🛟 Bad rows don’t sink the batch — a loadcreate fallback rescues the good records and writes the rest to a fail file with the exact Odoo error. Fix those rows and re-run with --fail to retry only them.

  • 🔁 Re-runnable by design — records upsert on their external id, so re-running an import converges to the right state instead of duplicating. Interrupted by a dropped VPN or a server restart? Run it again; checkpoints resume where it stopped.

  • 🚦 Exit codes your pipeline can trust — a fatal abort (bad credentials, wrong model, unreachable host) exits non-zero. Your set -e wrappers stop instead of marching on top of a database that received nothing.

  • 🔗 Relations and hierarchies, ordered for you — parent/child and relational data are detected and imported in a two-pass strategy, so you don’t hand-sequence files or untangle “record not found” errors.

  • 🌐 Per-environment by default — point each run at a connection.conf (xmlrpc / jsonrpc / json2). Rehearse against UAT, then swap the connection file for production. Same scripts, same data, different target.

  • 🔀 Odoo-to-Odoo in one stepfluvo migrate exports, transforms, and re-imports between two live Odoo instances in memory, for version upgrades and consolidations.

  • 🧩 Config-as-code — mappings are plain Python with a rich mapper library. They live in the client’s migration repo: reviewable, diffable, and re-runnable a year later when the next batch arrives.

Installation#

Install into your migration toolbox with uv (or pip) from PyPI:

$ uv pip install fluvo

Fluvo talks to Odoo over RPC, so it runs from your laptop or a CI runner — it does not need to be installed on the client’s Odoo server, and it can target Odoo versions independent of your own Python version.

A migration run, end to end#

A migration is a series of these two steps — one per model — chained in the order Odoo needs (companies → partners → products → …).

1. Map the client’s export to Odoo, as code. Each source file gets a transform.py that declares how its columns become Odoo fields. External ids (the id column) are what make every later re-run idempotent — give every record a stable one.

# transform.py
from fluvo.lib.transform import Processor
from fluvo.lib import mapper

partner_mapping = {
    'id': mapper.m2o('client_partner', 'CustomerCode'),  # stable external id
    'name': mapper.val('CustomerName'),
    'parent_id/id': mapper.m2o('client_partner', 'ParentCode'),  # resolved in pass 2
    'country_id/id': mapper.map_val({'NL': 'base.nl', 'BE': 'base.be'}, 'CountryISO'),
}

processor = Processor(partner_mapping, source_filename='origin/customers.csv', separator=',')
processor.process('data/partners_clean.csv', {'model': 'res.partner'})
processor.write_to_file('load_partners.sh')  # emits the exact CLI command
$ python transform.py

2. Load it — first at UAT, then production. The transform emits a ready-to-run fluvo import command. Drive it from a shell wrapper so the whole migration is one auditable script per environment:

# load_partners.sh (generated)
fluvo import \
  --connection-file conf/uat_connection.conf \
  --file data/partners_clean.csv \
  --model res.partner \
  --worker 4 --size 500

echo "exit: $?"   # non-zero here stops a `set -e` migration cold — as it should

Import detected parent_id as self-referential, so it ran two passes automatically: create every partner, then link parents. Some rows failed on a bad country code? They’re in res_partner_fail.csv with the reason. Fix them and retry just those:

$ fluvo import --connection-file conf/uat_connection.conf \
    --file data/partners_clean.csv --model res.partner --fail

When UAT reconciles clean, change one thing — conf/uat_connection.confconf/prod_connection.conf — and run the same scripts against production.

Tip for real migrations: don’t trust the exit code alone — read the imported values back out of Odoo and diff them against the source. Fluvo’s reconciliation and fail files tell you what it did; a read-back tells you what the database holds.

Documentation#

The full documentation on Read the Docs covers the reconciliation contract, two-pass relational imports, the mapper library, server-to-server migration, and per-environment configuration. See the Command-line Reference for every command and flag.

Contributing#

Contributions are very welcome. To learn more, see the Contributor Guide.

License#

Distributed under the terms of the LGPL 3.0 license, Fluvo is free and open source software. It began as, and remains a derivative of, odoo_csv_import by Thibault Francois — see NOTICE for attribution.

Issues#

If you hit a problem mid-migration, please file an issue with a detailed description — the exact command, the Odoo version, and what reconciliation reported all help.

Credits#

Development of this project is financially supported by stefcy.com.

Fluvo#

A robust Python toolkit for high-performance, intelligent Odoo data workflows.

Fluvo is a powerful and flexible library designed to simplify complex data imports and exports with Odoo. It features a smart import engine with automatic error recovery, multi-threading, and a two-pass strategy for relational data, allowing you to manage complex transformations and validations with confidence.

This library is the successor to the odoo-csv-import-export library, refactored for modern development practices and enhanced clarity.

--- config: theme: redux --- flowchart TD subgraph subGraph0["External Data"] A["CSV / XML File"] end subgraph s1["fluvo"] B{"Model Definition in Python"} C["@field Decorators"] D["Transformation & Validation Logic"] end subgraph Odoo["Odoo"] E["Odoo Database"] end A --> B B -- Defines --> C C -- Applies --> D B -- Orchestrates --> E A@{ shape: doc} E@{ shape: cyl} style A fill:#FFF9C4 style B fill:#C8E6C9 style E fill:#AA00FF style s1 fill:#BBDEFB style Odoo fill:transparent style subGraph0 fill:transparent

Getting Started#

Ready to simplify your Odoo data integrations?

Step

Description

🚀 Quickstart

Your first end-to-end example. Go from file to Odoo in minutes.

⚙️ Installation

How to install the library in your project.

🧠 Core Concepts

Understand the key ideas behind the library.