Skip to main content

Odoo Abstract Model Generator from XSD Schemas

codecov PyPI pyversions PyPI version

Generate Odoo abstract models (mixins) from XSD schemas using xsdata. Heavily inspired by xsdata-plantuml.

Video Tutorial: YouTube - xsdata-odoo Overview


Table of Contents


Install

$ pip install xsdata[cli]
$ pip install git+https://github.com/akretion/xsdata-odoo

Quick Start

Microsoft Purchase Order Demo

$ xsdata generate tests/fixtures/po/po.xsd --output=odoo
Parsing schema po.xsd
Compiling schema po.xsd
Builder: 6 main and 1 inner classes
Analyzer input: 6 main and 1 inner classes
Analyzer output: 5 main and 1 inner classes
Generating package: generated.po

Brazilian NF-e (Electronic Invoice)

$ export XSDATA_SCHEMA=nfe
$ export XSDATA_VERSION=40
$ export XSDATA_SKIP="^ICMS.ICMS\d+|^ICMS.ICMSSN\d+"
$ export XSDATA_LANG="portuguese"

$ xsdata generate nfelib/nfe/schemas/v4_0 \
    --package nfelib.nfe.odoo.v4_0 \
    --output=odoo

Real-World Usage

xsdata-odoo is used in production by the OCA Brazilian Localization (l10n-brazil) to generate models for complex fiscal documents:

Brazilian Electronic Fiscal Documents

Document Fields Model Version OCA Module
NF-e (Nota Fiscal Eletrônica) 800+ 55/65 4.0 l10n_br_nfe_spec
CT-e (Transport Document) 1000+ 57 4.0 l10n_br_cte_spec
MDF-e (Manifest) 500+ 58 3.0 l10n_br_mdfe_spec
SPED (Fiscal Reports) Variable - - l10n_br_sped_*
  • NF-e: 800+ fields across multiple hierarchical structures (identification, items, taxes, transport, payment)
  • CT-e: Multiple transport modes (road, air, waterway, rail, pipeline, multimodal) with specific fields each
  • MDF-e: Aggregation of multiple NF-e/CT-e documents with municipal grouping
  • SPED: Complex register hierarchies with parent-child relationships

Integration with nfelib: xsdata-odoo generates Odoo models, while nfelib handles XML serialization. Both use the same XSD schemas for consistency.

Architecture Pattern

Two-Layer Architecture

The OCA l10n-brazil uses a proven two-layer architecture:

1. Spec Modules (l10n_br_*_spec)

  • 100% generated from XSD schemas
  • Abstract models (mixins) with field definitions
  • No business logic
  • Versioned per schema version (nfe40, cte40, mdfe30)

2. Implementation Modules (l10n_br_nfe, etc.)

  • Inherits from spec modules
  • Maps to Odoo fiscal documents (l10n_br_fiscal.document)
  • Business rules and validations
  • Web service communication (SEFAZ)
  • User interface

Benefits

  • Schema Updates: Regenerate spec modules without touching business logic
  • Version Migration: Different schema versions coexist (nfe40 vs nfe50)
  • Testing: Business logic tested separately from generated code
  • Maintainability: Clear separation of concerns

Configuration

Environment Variables

Variable Description Default
XSDATA_SCHEMA Schema name spec
XSDATA_VERSION Schema version 10
XSDATA_SKIP Regex patterns to skip (pipe-separated) []
XSDATA_LANG Language for text processing ""
XSDATA_MONETARY_TYPE XSD type to force fields.Monetary ""
XSDATA_NUM_TYPE XSD type for numeric detection TDec_[5:7.7:9]
XSDATA_CURRENCY_FIELD Currency field name currency_id
XSDATA_GENDS GenerateDS compatibility mode false

Python API

from xsdata_odoo import get_config

config = get_config()
print(config.schema)              # "spec"
print(config.version)             # "10"
print(config.field_safe_prefix)   # "spec10_"
print(config.inherit_model)       # "spec.mixin.spec"

Advanced Examples

Brazilian NF-e with ICMS Handling

The NF-e schema defines ICMS taxes with multiple groups (ICMS00, ICMS10, ICMS40, etc.) that share field names. Skip them to avoid conflicts:

export XSDATA_SCHEMA=nfe
export XSDATA_VERSION=40
export XSDATA_SKIP="^ICMS.ICMS\d+|^ICMS.ICMSSN\d+"
export XSDATA_LANG="portuguese"
export XSDATA_CURRENCY_FIELD="brl_currency_id"

xsdata generate nfelib/nfe/schemas/v4_0 \
  --package nfelib.nfe.odoo.v4_0 \
  --output=odoo

# Move generated files to your module
mv nfelib/odoo/nfe/v4_0/* your_addon/models/v4_0/

CT-e (Transport Document)

export XSDATA_SCHEMA=cte
export XSDATA_VERSION=40
export XSDATA_SKIP="^ICMS\d+|^ICMSSN+|ICMSOutraUF|ICMSUFFim|INFESPECIE_TPESPECIE"
export XSDATA_LANG="portuguese"

xsdata generate nfelib/cte/schemas/v4_0 \
  --package nfelib.cte.odoo.v4_0 \
  --output=odoo

MDF-e (Manifest Document)

export XSDATA_SCHEMA=mdfe
export XSDATA_VERSION=30
export XSDATA_LANG="portuguese"

xsdata generate nfelib/mdfe/schemas/v3_0 \
  --package nfelib.mdfe.odoo.v3_0 \
  --output=odoo

SPED Fiscal Reports (Advanced)

For complex non-XML fiscal reports with register hierarchies:

from xsdata_odoo.generator import OdooGenerator
from xsdata_odoo.filters import OdooFilters

class SpedFilters(OdooFilters):
    def registry_name(self, name="", parents=[], type_names=[]):
        # Custom naming: schema.version.register_code
        name = self.class_name(name)
        return f"{self.schema}.{self.version}.{name[-4:].lower()}"

    def class_properties(self, obj, parents):
        # Add custom metadata
        register = lookup_register(obj.name)
        return f"_sped_level = {register['level']}"

Field Prefixing Strategy

Problem

With 800+ fields in NF-e alone, plus thousands of OCA modules, field name collisions are a real risk. Additionally, schemas evolve (3.0 → 4.0 → 5.0).

Solution

Each field gets a prefix combining schema name + version digits:

  • NF-e v4.0: nfe40_ prefix → nfe40_vBC, nfe40_vICMS
  • CT-e v4.0: cte40_ prefix → cte40_vTPrest
  • MDF-e v3.0: mdfe30_ prefix → mdfe30_qNFe

Versioning Strategy

Scenario Example Database Impact
Minor update (4.00 → 4.01) Same nfe40_ prefix Fields updated in place, --update sufficient
Major update (3.0 → 4.0) nfe30_ → nfe40_ prefix New fields/tables, data migration needed

Automatic Prefix Generation

from xsdata_odoo import get_config

config = get_config()
config.schema = "nfe"
config.version = "40"

print(config.field_safe_prefix)  # "nfe40_"

Custom Filters

Extend OdooFilters for specialized use cases:

from xsdata_odoo.filters import OdooFilters
from collections import OrderedDict

class MyCustomFilters(OdooFilters):
    def registry_name(self, name="", parents=[], type_names=[]):
        # Custom model naming logic
        return f"my_module.{self.version}.{name.lower()}"

    def _extract_field_attributes(self, parents, attr):
        # Add custom field attributes
        kwargs = super()._extract_field_attributes(parents, attr)

        # Add custom metadata
        kwargs["my_custom_attr"] = True

        return kwargs

# Use custom filters
generator = OdooGenerator(config)
generator.filters = MyCustomFilters(
    config,
    all_simple_types=[],
    all_complex_types=[],
    registry_names={},
    implicit_many2ones={},
)
generator.filters.register(generator.env)

Field Name Conflicts

Problem: XSD defines multiple groups with same field names (e.g., ICMS00.vBC, ICMS10.vBC).

Solution: Use XSDATA_SKIP to skip conflicting classes:

export XSDATA_SKIP="^ICMS.ICMS\d+|^ICMS.ICMSSN\d+"

Then implement business logic in your implementation module to handle the different ICMS groups.

Currency Fields

Problem: Monetary fields reference non-existent currency field.

Solution: Set XSDATA_CURRENCY_FIELD to match your Odoo module's currency field:

export XSDATA_CURRENCY_FIELD="company_currency_id"  # or "currency_id", "brl_currency_id"

Language-Specific Text Processing

Problem: Field labels not extracted properly from XSD documentation.

Solution: Set XSDATA_LANG for stopword processing:

export XSDATA_LANG="portuguese"  # or "english", "spanish", etc.

Links

License

MIT License - See LICENSE file for details

Copyright

2025 Akretion - Raphaël Valyi raphael.valyi@akretion.com

Metadata

Release files for xsdata-odoo 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xsdata-odoo 1.1.0
File Size Uploaded
xsdata_odoo-1.1.0.tar.gz 27.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xsdata-odoo 1.1.0
File Interpreter ABI Platform
xsdata_odoo-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 52.1 kB

Release files / xsdata_odoo-1.1.0.tar.gz

Download URL xsdata_odoo-1.1.0.tar.gz
Size 27.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0f15420fc29956ff3fbba96f76836d3d420c69fdffeeec2720d96e0501b36588
BLAKE2b-256 checksum
How to use checksums
598d3ca082631a33b45ca94fb17b5a5c570785c6bd2134c28979c05c1be087df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 27, 2026.

Transparency log

Release files / xsdata_odoo-1.1.0-py3-none-any.whl

Download URL xsdata_odoo-1.1.0-py3-none-any.whl
Size 25.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
829d61af9883aac910f859268a5c7e0ec6f1093f96f0d5956e08af22d103bc29
BLAKE2b-256 checksum
How to use checksums
2714abb43505fd434826943c048371b03a01a1fe72b4f25c9816b7187beb351e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page